Skip to content

Commit 0e2970b

Browse files
committed
[xray] Do not emit tail exit hooks for conditional tail calls
xray instruments tail call function exits by inserting a nop sled before the tail call. When tracing is enabled, the nop sled is replaced with a call to `__xray_FunctionTailExit()`. This currently does not work for conditional tail calls, as the instrumentation assumes that the tail call will be unconditional. This causes two issues: - `__xray_FunctionTailExit()` is inappropately called even when the tail call is not taken. - `__xray_FunctionTailExit()`'s prologue/epilogue adjusts the stack pointer with add/sub instructions. This clobbers condition flags, which can flip the condition used for the tail call, leading to incorrect program behavior. Avoid this misbehavior by disabling instrumentation of conditional tail calls. A more comprehensive fix could be to either rewrite conditional tail calls to non-conditional ones, or to create specialized function tail exit instrumentation functions for each of the possible types of conditional tail calls.
1 parent e2a72fa commit 0e2970b

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

llvm/lib/CodeGen/XRayInstrumentation.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ void XRayInstrumentation::replaceRetWithPatchableRet(
100100
// PATCHABLE_RET <Opcode>, <Operand>...
101101
Opc = TargetOpcode::PATCHABLE_RET;
102102
}
103-
if (TII->isTailCall(T) && op.HandleTailcall) {
103+
if (TII->isTailCall(T) && T.isBarrier() && op.HandleTailcall) {
104104
// Treat the tail call as a return instruction, which has a
105105
// different-looking sled than the normal return case.
106106
Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
@@ -131,7 +131,7 @@ void XRayInstrumentation::prependRetWithPatchableExit(
131131
(op.HandleAllReturns || T.getOpcode() == TII->getReturnOpcode())) {
132132
Opc = TargetOpcode::PATCHABLE_FUNCTION_EXIT;
133133
}
134-
if (TII->isTailCall(T) && op.HandleTailcall) {
134+
if (TII->isTailCall(T) && T.isBarrier() && op.HandleTailcall) {
135135
Opc = TargetOpcode::PATCHABLE_TAIL_CALL;
136136
}
137137
if (Opc != 0) {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
; RUN: llc -mtriple=x86_64 < %s | FileCheck %s
2+
3+
declare void @tail_call_target()
4+
5+
define void @conditional_tail_call(i32 %cond) "function-instrument"="xray-always" nounwind {
6+
; CHECK-LABEL: conditional_tail_call:
7+
; CHECK-NEXT: .Lfunc_begin0:
8+
; CHECK-NEXT: # %bb.0:
9+
; CHECK-NEXT: .p2align 1, 0x90
10+
; CHECK-NEXT: .Lxray_sled_0:
11+
; CHECK-NEXT: .ascii "\353\t"
12+
; CHECK-NEXT: nopw 512(%rax,%rax)
13+
; CHECK-NEXT: testl %edi, %edi
14+
; CHECK-NEXT: jne tail_call_target@PLT # TAILCALL
15+
; CHECK-NEXT: # %bb.1:
16+
; CHECK-NEXT: .p2align 1, 0x90
17+
; CHECK-NEXT: .Lxray_sled_1:
18+
; CHECK-NEXT: retq
19+
; CHECK-NEXT: nopw %cs:512(%rax,%rax)
20+
; CHECK-NEXT: .Lfunc_end0:
21+
%cmp = icmp ne i32 %cond, 0
22+
br i1 %cmp, label %docall, label %ret
23+
docall:
24+
tail call void @tail_call_target()
25+
ret void
26+
ret:
27+
ret void
28+
}

0 commit comments

Comments
 (0)