Skip to content

Commit

Permalink
[analyzer] Relax assertion in BugReporterVisitors.cpp isInitializatio…
Browse files Browse the repository at this point in the history
…nOfVar (#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 #124975
  • Loading branch information
steakhal authored Jan 30, 2025
1 parent b68b4f6 commit 025541d
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 1 deletion.
5 changes: 4 additions & 1 deletion clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1198,7 +1198,10 @@ static bool isInitializationOfVar(const ExplodedNode *N, const VarRegion *VR) {
// If we ever directly evaluate global DeclStmts, this assertion will be
// invalid, but this still seems preferable to silently accepting an
// initialization that may be for a path-sensitive variable.
assert(VR->getDecl()->isStaticLocal() && "non-static stackless VarRegion");
[[maybe_unused]] bool IsLocalStaticOrLocalExtern =
VR->getDecl()->isStaticLocal() || VR->getDecl()->isLocalExternDecl();
assert(IsLocalStaticOrLocalExtern &&
"Declared a variable on the stack without Stack memspace?");
return true;
}

Expand Down
35 changes: 35 additions & 0 deletions clang/test/Analysis/null-deref-path-notes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,38 @@ void c::f(B &g, int &i) {
f(h, b); // expected-note{{Calling 'c::f'}}
}
}

namespace GH124975 {
void no_crash_in_br_visitors(int *p) {
if (p) {}
// expected-note@-1 {{Assuming 'p' is null}}
// expected-note@-2 {{Taking false branch}}

extern bool ExternLocalCoin;
// expected-note@+2 {{Assuming 'ExternLocalCoin' is false}}
// expected-note@+1 {{Taking false branch}}
if (ExternLocalCoin)
return;

*p = 4;
// expected-warning@-1 {{Dereference of null pointer (loaded from variable 'p')}}
// expected-note@-2 {{Dereference of null pointer (loaded from variable 'p')}}
}

// Thread local variables are implicitly static, so let's test them too.
void thread_local_alternative(int *p) {
if (p) {}
// expected-note@-1 {{Assuming 'p' is null}}
// expected-note@-2 {{Taking false branch}}

thread_local bool ThreadLocalCoin;
// expected-note@+2 {{'ThreadLocalCoin' is false}}
// expected-note@+1 {{Taking false branch}}
if (ThreadLocalCoin)
return;

*p = 4;
// expected-warning@-1 {{Dereference of null pointer (loaded from variable 'p')}}
// expected-note@-2 {{Dereference of null pointer (loaded from variable 'p')}}
}
} // namespace GH124975

0 comments on commit 025541d

Please sign in to comment.