Skip to content

Commit 025541d

Browse files
authored
[analyzer] Relax assertion in BugReporterVisitors.cpp isInitializationOfVar (llvm#125044)
If we see a variable declaration (aka. DeclStmt), and the VarRegion it declared doesn't have Stack memspace, we assumed that it must be a local static variable. However, the declared variable may be an extern declaration of a global. In this patch, let's admit that local extern declarations are a thing. For the sake of completeness, I also added one more test for thread_locals - which are implicitly considered statics btw. (the `isStaticLocal()` correctly also considers thread locals as local statics). Fixes llvm#124975
1 parent b68b4f6 commit 025541d

File tree

2 files changed

+39
-1
lines changed

2 files changed

+39
-1
lines changed

clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -1198,7 +1198,10 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
11981198
// If we ever directly evaluate global DeclStmts, this assertion will be
11991199
// invalid, but this still seems preferable to silently accepting an
12001200
// initialization that may be for a path-sensitive variable.
1201-
assert(VR->getDecl()->isStaticLocal() && "non-static stackless VarRegion");
1201+
[[maybe_unused]] bool IsLocalStaticOrLocalExtern =
1202+
VR->getDecl()->isStaticLocal() || VR->getDecl()->isLocalExternDecl();
1203+
assert(IsLocalStaticOrLocalExtern &&
1204+
"Declared a variable on the stack without Stack memspace?");
12021205
return true;
12031206
}
12041207

clang/test/Analysis/null-deref-path-notes.cpp

+35
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,38 @@ void c::f(B &g, int &i) {
2323
f(h, b); // expected-note{{Calling 'c::f'}}
2424
}
2525
}
26+
27+
namespace GH124975 {
28+
void no_crash_in_br_visitors(int *p) {
29+
if (p) {}
30+
// expected-note@-1 {{Assuming 'p' is null}}
31+
// expected-note@-2 {{Taking false branch}}
32+
33+
extern bool ExternLocalCoin;
34+
// expected-note@+2 {{Assuming 'ExternLocalCoin' is false}}
35+
// expected-note@+1 {{Taking false branch}}
36+
if (ExternLocalCoin)
37+
return;
38+
39+
*p = 4;
40+
// expected-warning@-1 {{Dereference of null pointer (loaded from variable 'p')}}
41+
// expected-note@-2 {{Dereference of null pointer (loaded from variable 'p')}}
42+
}
43+
44+
// Thread local variables are implicitly static, so let's test them too.
45+
void thread_local_alternative(int *p) {
46+
if (p) {}
47+
// expected-note@-1 {{Assuming 'p' is null}}
48+
// expected-note@-2 {{Taking false branch}}
49+
50+
thread_local bool ThreadLocalCoin;
51+
// expected-note@+2 {{'ThreadLocalCoin' is false}}
52+
// expected-note@+1 {{Taking false branch}}
53+
if (ThreadLocalCoin)
54+
return;
55+
56+
*p = 4;
57+
// expected-warning@-1 {{Dereference of null pointer (loaded from variable 'p')}}
58+
// expected-note@-2 {{Dereference of null pointer (loaded from variable 'p')}}
59+
}
60+
} // namespace GH124975

0 commit comments

Comments
 (0)