Skip to content

Commit

Permalink
[Clang][CFG] check children statements of asm goto
Browse files Browse the repository at this point in the history
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: #51024
Fixes: ClangBuiltLinux/linux#1439

Reviewed By: void, jyknight, jyu2, efriedma

Differential Revision: https://reviews.llvm.org/D116059
  • Loading branch information
nickdesaulniers committed Jan 7, 2022
1 parent f388735 commit 3a604fd
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 25 deletions.
2 changes: 1 addition & 1 deletion clang/lib/Analysis/CFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Analysis/UninitializedValues.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down
29 changes: 23 additions & 6 deletions clang/test/Analysis/asm-goto.cpp
Original file line number Diff line number Diff line change
@@ -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)
{
Expand All @@ -17,11 +17,12 @@ int foo(int cond)
// 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);
Expand All @@ -32,7 +33,9 @@ int bar(int cond)
}

// 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

Expand All @@ -48,6 +51,20 @@ int zoo(int n)
}

// 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
47 changes: 34 additions & 13 deletions clang/test/Analysis/uninit-asm-goto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -24,9 +24,9 @@ int test2(int x) {
}

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;
Expand All @@ -38,20 +38,20 @@ int test3(int x) {
}

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:
Expand All @@ -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}}
}
12 changes: 12 additions & 0 deletions clang/test/Sema/array-bounds-ptr-arith.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:;
}

0 comments on commit 3a604fd

Please sign in to comment.