Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit f7afaaa

Browse files
committed
[CodeGen] Suppress emission of lifetime markers if a label has been seen
in the current lexical scope. clang currently emits the lifetime.start marker of a variable when the variable comes into scope even though a variable's lifetime starts at the entry of the block with which it is associated, according to the C standard. This normally doesn't cause any problems, but in the rare case where a goto jumps backwards past the variable declaration to an earlier point in the block (see the test case added to lifetime2.c), it can cause mis-compilation. To prevent such mis-compiles, this commit conservatively disables emitting lifetime variables when a label has been seen in the current block. This problem was discussed on cfe-dev here: http://lists.llvm.org/pipermail/cfe-dev/2016-July/050066.html rdar://problem/30153946 Differential Revision: https://reviews.llvm.org/D27680 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@293106 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 771d6cd commit f7afaaa

File tree

3 files changed

+51
-11
lines changed

3 files changed

+51
-11
lines changed

lib/CodeGen/CGDecl.cpp

+15-5
Original file line numberDiff line numberDiff line change
@@ -1022,11 +1022,21 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
10221022
// Emit a lifetime intrinsic if meaningful. There's no point in doing this
10231023
// if we don't have a valid insertion point (?).
10241024
if (HaveInsertPoint() && !IsMSCatchParam) {
1025-
// goto or switch-case statements can break lifetime into several
1026-
// regions which need more efforts to handle them correctly. PR28267
1027-
// This is rare case, but it's better just omit intrinsics than have
1028-
// them incorrectly placed.
1029-
if (!Bypasses.IsBypassed(&D)) {
1025+
// If there's a jump into the lifetime of this variable, its lifetime
1026+
// gets broken up into several regions in IR, which requires more work
1027+
// to handle correctly. For now, just omit the intrinsics; this is a
1028+
// rare case, and it's better to just be conservatively correct.
1029+
// PR28267.
1030+
//
1031+
// We have to do this in all language modes if there's a jump past the
1032+
// declaration. We also have to do it in C if there's a jump to an
1033+
// earlier point in the current block because non-VLA lifetimes begin as
1034+
// soon as the containing block is entered, not when its variables
1035+
// actually come into scope; suppressing the lifetime annotations
1036+
// completely in this case is unnecessarily pessimistic, but again, this
1037+
// is rare.
1038+
if (!Bypasses.IsBypassed(&D) &&
1039+
!(!getLangOpts().CPlusPlus && hasLabelBeenSeenInCurrentScope())) {
10301040
uint64_t size = CGM.getDataLayout().getTypeAllocSize(allocaTy);
10311041
emission.SizeForLifetimeMarkers =
10321042
EmitLifetimeStart(size, address.getPointer());

lib/CodeGen/CodeGenFunction.h

+11
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,13 @@ class CodeGenFunction : public CodeGenTypeCache {
212212
/// value. This is invalid iff the function has no return value.
213213
Address ReturnValue;
214214

215+
/// Return true if a label was seen in the current scope.
216+
bool hasLabelBeenSeenInCurrentScope() const {
217+
if (CurLexicalScope)
218+
return CurLexicalScope->hasLabels();
219+
return !LabelMap.empty();
220+
}
221+
215222
/// AllocaInsertPoint - This is an instruction in the entry block before which
216223
/// we prefer to insert allocas.
217224
llvm::AssertingVH<llvm::Instruction> AllocaInsertPt;
@@ -620,6 +627,10 @@ class CodeGenFunction : public CodeGenTypeCache {
620627
rescopeLabels();
621628
}
622629

630+
bool hasLabels() const {
631+
return !Labels.empty();
632+
}
633+
623634
void rescopeLabels();
624635
};
625636

test/CodeGen/lifetime2.c

+25-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
// RUN: %clang -S -emit-llvm -o - -O2 %s | FileCheck %s -check-prefixes=CHECK,O2
2-
// RUN: %clang -S -emit-llvm -o - -O2 -Xclang -disable-lifetime-markers %s \
1+
// RUN: %clang_cc1 -S -emit-llvm -o - -O2 -disable-llvm-passes %s | FileCheck %s -check-prefixes=CHECK,O2
2+
// RUN: %clang_cc1 -S -emit-llvm -o - -O2 -disable-lifetime-markers %s \
33
// RUN: | FileCheck %s -check-prefixes=CHECK,O0
4-
// RUN: %clang -S -emit-llvm -o - -O0 %s | FileCheck %s -check-prefixes=CHECK,O0
4+
// RUN: %clang_cc1 -S -emit-llvm -o - -O0 %s | FileCheck %s -check-prefixes=CHECK,O0
55

66
extern int bar(char *A, int n);
77

@@ -25,13 +25,11 @@ void no_goto_bypass() {
2525
char x;
2626
l1:
2727
bar(&x, 1);
28-
// O2: @llvm.lifetime.start(i64 5
29-
// O2: @llvm.lifetime.end(i64 5
3028
char y[5];
3129
bar(y, 5);
3230
goto l1;
3331
// Infinite loop
34-
// O2-NOT: @llvm.lifetime.end(i64 1
32+
// O2-NOT: @llvm.lifetime.end(
3533
}
3634

3735
// CHECK-LABEL: @goto_bypass
@@ -91,3 +89,24 @@ void indirect_jump(int n) {
9189
L:
9290
bar(&x, 1);
9391
}
92+
93+
// O2-LABEL: define i32 @jump_backward_over_declaration(
94+
// O2-NOT: call void @llvm.lifetime.{{.*}}(i64 4,
95+
96+
extern void foo2(int p);
97+
98+
int jump_backward_over_declaration(int a) {
99+
int *p = 0;
100+
label1:
101+
if (p) {
102+
foo2(*p);
103+
return 0;
104+
}
105+
106+
int i = 999;
107+
if (a != 2) {
108+
p = &i;
109+
goto label1;
110+
}
111+
return -1;
112+
}

0 commit comments

Comments
 (0)