[Clang][CFG] check children statements of asm goto
When performing CFG based analyses, don't forget to check the child statements of an asm goto, such as the expressions used for inputs+outputs. Fixes: https://github.com/llvm/llvm-project/issues/51024 Fixes: https://github.com/ClangBuiltLinux/linux/issues/1439 Reviewed By: void, jyknight, jyu2, efriedma Differential Revision: https://reviews.llvm.org/D116059
This commit is contained in:
parent
f38873537b
commit
3a604fdbcd
|
@ -3352,7 +3352,7 @@ CFGBlock *CFGBuilder::VisitGCCAsmStmt(GCCAsmStmt *G, AddStmtChoice asc) {
|
|||
// Save "Succ" in BackpatchBlocks. In the backpatch processing, "Succ" is
|
||||
// used to avoid adding "Succ" again.
|
||||
BackpatchBlocks.push_back(JumpSource(Succ, ScopePos));
|
||||
return Block;
|
||||
return VisitChildren(G);
|
||||
}
|
||||
|
||||
CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
|
||||
|
|
|
@ -819,12 +819,11 @@ void TransferFunctions::VisitGCCAsmStmt(GCCAsmStmt *as) {
|
|||
while (const auto *UO = dyn_cast<UnaryOperator>(Ex))
|
||||
Ex = stripCasts(C, UO->getSubExpr());
|
||||
|
||||
// Mark the variable as potentially uninitialized for those cases where
|
||||
// it's used on an indirect path, where it's not guaranteed to be
|
||||
// defined.
|
||||
if (const VarDecl *VD = findVar(Ex).getDecl())
|
||||
if (vals[VD] != Initialized)
|
||||
// If the variable isn't initialized by the time we get here, then we
|
||||
// mark it as potentially uninitialized for those cases where it's used
|
||||
// on an indirect path, where it's not guaranteed to be defined.
|
||||
vals[VD] = MayUninitialized;
|
||||
vals[VD] = MayUninitialized;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_analyze_cc1 -triple i386-pc-linux-gnu -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
|
||||
// RUN: %clang_analyze_cc1 -triple x86_64-pc-linux-gnu -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
|
||||
// RUN: %clang_analyze_cc1 -triple i386-pc-linux-gnu -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
|
||||
// RUN: %clang_analyze_cc1 -triple x86_64-pc-linux-gnu -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s
|
||||
|
||||
int foo(int cond)
|
||||
{
|
||||
|
@ -17,11 +17,12 @@ loop:
|
|||
// CHECK-NEXT: Succs (1): B0
|
||||
|
||||
// CHECK-LABEL: label_true
|
||||
// CHECK-NEXT: asm goto
|
||||
// CHECK-NEXT: cond
|
||||
// CHECK-NEXT: [B3.1]
|
||||
// CHECK-NEXT: T: asm goto
|
||||
// CHECK-NEXT: Preds (2): B3 B4
|
||||
// CHECK-NEXT: Succs (3): B2 B3 B1
|
||||
|
||||
|
||||
int bar(int cond)
|
||||
{
|
||||
asm goto("testl %0, %0; jne %l1;" :: "r"(cond)::L1, L2);
|
||||
|
@ -32,7 +33,9 @@ L2:
|
|||
}
|
||||
|
||||
// CHECK: [B4]
|
||||
// CHECK-NEXT: asm goto
|
||||
// CHECK-NEXT: cond
|
||||
// CHECK-NEXT: [B4.1]
|
||||
// CHECK-NEXT: T: asm goto
|
||||
// CHECK-NEXT: Preds (1): B5
|
||||
// CHECK-NEXT: Succs (3): B3 B2 B1
|
||||
|
||||
|
@ -48,6 +51,20 @@ A4:
|
|||
}
|
||||
|
||||
// CHECK-LABEL: A1
|
||||
// CHECK-NEXT: asm goto
|
||||
// CHECK-NEXT: n
|
||||
// CHECK-NEXT: [B4.1]
|
||||
// CHECK-NEXT: T: asm goto
|
||||
// CHECK-NEXT: Preds (2): B5 B4
|
||||
// CHECK-NEXT: Succs (5): B3 B4 B2 B1 B5
|
||||
|
||||
void baz(void)
|
||||
{
|
||||
asm goto("" :: "r"(1 ? 2 : 0 << -1) :: error);
|
||||
error:;
|
||||
}
|
||||
|
||||
// CHECK: [B2]
|
||||
// CHECK-NEXT: 1: [B5.2] ? [B3.1] : [B4.4]
|
||||
// CHECK-NEXT: T: asm goto ("" : : "r" ([B2.1]) : : error);
|
||||
// CHECK-NEXT: Preds (2): B3 B4
|
||||
// CHECK-NEXT: Succs (1): B1
|
||||
|
|
|
@ -3,19 +3,19 @@
|
|||
// test1: Expect no diagnostics
|
||||
int test1(int x) {
|
||||
int y;
|
||||
asm goto("nop" : "=r"(y) : "r"(x) : : err);
|
||||
asm goto("" : "=r"(y) : "r"(x) : : err);
|
||||
return y;
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int test2(int x) {
|
||||
int y; // expected-warning {{variable 'y' is used uninitialized whenever its declaration is reached}} \
|
||||
// expected-note {{initialize the variable}}
|
||||
int y; // expected-warning {{variable 'y' is used uninitialized whenever its declaration is reached}}
|
||||
// expected-note@-1 {{initialize the variable}}
|
||||
if (x < 42)
|
||||
asm volatile goto("testl %0, %0; testl %1, %2; jne %l3" : "+S"(x), "+D"(y) : "r"(x) :: indirect_1, indirect_2);
|
||||
asm goto("" : "+S"(x), "+D"(y) : "r"(x) :: indirect_1, indirect_2);
|
||||
else
|
||||
asm volatile goto("testl %0, %1; testl %2, %3; jne %l5" : "+S"(x), "+D"(y) : "r"(x), "r"(y) :: indirect_1, indirect_2);
|
||||
asm goto("" : "+S"(x), "+D"(y) : "r"(x), "r"(y) :: indirect_1, indirect_2);
|
||||
return x + y;
|
||||
indirect_1:
|
||||
return -42;
|
||||
|
@ -24,9 +24,9 @@ indirect_2:
|
|||
}
|
||||
|
||||
int test3(int x) {
|
||||
int y; // expected-warning {{variable 'y' is used uninitialized whenever its declaration is reached}} \
|
||||
// expected-note {{initialize the variable}}
|
||||
asm goto("xorl %1, %0; jmp %l2" : "=&r"(y) : "r"(x) : : fail);
|
||||
int y; // expected-warning {{variable 'y' is used uninitialized whenever its declaration is reached}}
|
||||
// expected-note@-1 {{initialize the variable}}
|
||||
asm goto("" : "=&r"(y) : "r"(x) : : fail);
|
||||
normal:
|
||||
y += x;
|
||||
return y;
|
||||
|
@ -38,20 +38,20 @@ fail:
|
|||
}
|
||||
|
||||
int test4(int x) {
|
||||
int y; // expected-warning {{variable 'y' is used uninitialized whenever its declaration is reached}} \
|
||||
// expected-note {{initialize the variable}}
|
||||
int y; // expected-warning {{variable 'y' is used uninitialized whenever its declaration is reached}}
|
||||
// expected-note@-1 {{initialize the variable}}
|
||||
goto forward;
|
||||
backward:
|
||||
return y; // expected-note {{uninitialized use occurs here}}
|
||||
forward:
|
||||
asm goto("# %0 %1 %2" : "=r"(y) : "r"(x) : : backward);
|
||||
asm goto("" : "=r"(y) : "r"(x) : : backward);
|
||||
return y;
|
||||
}
|
||||
|
||||
// test5: Expect no diagnostics
|
||||
int test5(int x) {
|
||||
int y;
|
||||
asm volatile goto("testl %0, %0; testl %1, %2; jne %l3" : "+S"(x), "+D"(y) : "r"(x) :: indirect, fallthrough);
|
||||
asm goto("" : "+S"(x), "+D"(y) : "r"(x) :: indirect, fallthrough);
|
||||
fallthrough:
|
||||
return y;
|
||||
indirect:
|
||||
|
@ -63,9 +63,30 @@ int test6(unsigned int *x) {
|
|||
unsigned int val;
|
||||
|
||||
// See through casts and unary operators.
|
||||
asm goto("nop" : "=r" (*(unsigned int *)(&val)) ::: indirect);
|
||||
asm goto("" : "=r" (*(unsigned int *)(&val)) ::: indirect);
|
||||
*x = val;
|
||||
return 0;
|
||||
indirect:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int test7(int z) {
|
||||
int x; // expected-warning {{variable 'x' is used uninitialized whenever its declaration is reached}}
|
||||
// expected-note@-1 {{initialize the variable 'x' to silence this warning}}
|
||||
if (z)
|
||||
asm goto ("":"=r"(x):::A1,A2);
|
||||
return 0;
|
||||
A1:
|
||||
A2:
|
||||
return x; // expected-note {{uninitialized use occurs here}}
|
||||
}
|
||||
|
||||
int test8() {
|
||||
int x = 0; // expected-warning {{variable 'x' is used uninitialized whenever its declaration is reached}}
|
||||
// expected-note@-1 {{variable 'x' is declared here}}
|
||||
asm goto ("":"=r"(x):::A1,A2);
|
||||
return 0;
|
||||
A1:
|
||||
A2:
|
||||
return x; // expected-note {{uninitialized use occurs here}}
|
||||
}
|
||||
|
|
|
@ -37,3 +37,15 @@ void radar11387038() {
|
|||
RDar11387038_B *pRDar11387038_B;
|
||||
struct RDar11387038* y = &(*pRDar11387038_B->x)->z[4];
|
||||
}
|
||||
|
||||
void pr51682 (void) {
|
||||
int arr [1];
|
||||
switch (0) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
asm goto (""::"r"(arr[42] >> 1)::failed); // no-warning
|
||||
break;
|
||||
}
|
||||
failed:;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue