[clang] [StaticAnalyzer] Handle `__builtin_bit_cast` (PR #139188)
via cfe-commits
cfe-commits at lists.llvm.org
Thu May 8 18:08:18 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-static-analyzer-1
Author: Ziqing Luo (ziqingluo-90)
<details>
<summary>Changes</summary>
I am investigating a CSA crash: https://godbolt.org/z/fEExYqoWM. If one changes the `__builtin_bit_cast` to a C-style cast, the test will be fine. So the problem is specific to `__builtin_bit_cast`.
Looking at the piece of code below, it seems that CSA handles `__builtin_bit_cast` just as an `LValueToRValue` cast. The actual operation of cast-to-target-type is missing.
```
void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
ExplodedNodeSet dstPreStmt;
getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this);
if (CastE->getCastKind() == CK_LValueToRValue ||
CastE->getCastKind() == CK_LValueToRValueBitCast) {
for (ExplodedNode *subExprNode : dstPreStmt) {
ProgramStateRef state = subExprNode->getState();
const LocationContext *LCtx = subExprNode->getLocationContext();
evalLoad(Dst, CastE, CastE, subExprNode, state, state->getSVal(Ex, LCtx));
}
return;
}
```
The `BuiltinBitCastExpr` node always have the kind `LValueToRValueBitCast`. I suppose it is just associated to the second argument of a `__builtin_bit_cast` call.
```
-BuiltinBitCastExpr <col:17, col:45> 'void *' <LValueToRValueBitCast>
```
I'm trying to add the missing part.
---
Full diff: https://github.com/llvm/llvm-project/pull/139188.diff
3 Files Affected:
- (modified) clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp (+25-1)
- (modified) clang/test/Analysis/builtin_bitcast.cpp (+12-2)
- (modified) clang/test/Analysis/exercise-ps.c (+1-1)
``````````diff
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 3d0a69a515ab8..f2f640f459776 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -287,10 +287,34 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
if (CastE->getCastKind() == CK_LValueToRValue ||
CastE->getCastKind() == CK_LValueToRValueBitCast) {
+ ExplodedNodeSet dstEvalLoad;
+
for (ExplodedNode *subExprNode : dstPreStmt) {
ProgramStateRef state = subExprNode->getState();
const LocationContext *LCtx = subExprNode->getLocationContext();
- evalLoad(Dst, CastE, CastE, subExprNode, state, state->getSVal(Ex, LCtx));
+ evalLoad(dstEvalLoad, CastE, CastE, subExprNode, state,
+ state->getSVal(Ex, LCtx));
+ }
+ if (CastE->getCastKind() == CK_LValueToRValue) {
+ Dst.insert(dstEvalLoad);
+ return;
+ }
+ assert(CastE->getCastKind() == CK_LValueToRValueBitCast &&
+ "unexpected cast kind");
+ // Need to simulate the actual cast operation:
+ StmtNodeBuilder Bldr(dstEvalLoad, Dst, *currBldrCtx);
+
+ for (ExplodedNode *Node : dstEvalLoad) {
+ ProgramStateRef state = Node->getState();
+ const LocationContext *LCtx = Node->getLocationContext();
+ // getAsRegion should always be successful since Ex is an lvalue:
+ SVal OrigV = state->getSVal(state->getSVal(Ex, LCtx).getAsRegion());
+ SVal CastedV =
+ svalBuilder.evalCast(svalBuilder.simplifySVal(state, OrigV),
+ CastE->getType(), Ex->getType());
+
+ state = state->BindExpr(CastE, LCtx, CastedV);
+ Bldr.generateNode(CastE, Node, state);
}
return;
}
diff --git a/clang/test/Analysis/builtin_bitcast.cpp b/clang/test/Analysis/builtin_bitcast.cpp
index 5a0d9e7189b8e..9309ca7785a92 100644
--- a/clang/test/Analysis/builtin_bitcast.cpp
+++ b/clang/test/Analysis/builtin_bitcast.cpp
@@ -39,7 +39,7 @@ struct A {
}
};
void gh_69922(size_t p) {
- // expected-warning-re at +1 {{(reg_${{[0-9]+}}<size_t p>) & 1U}}
+ // expected-warning at +1 {{Unknown}}
clang_analyzer_dump(__builtin_bit_cast(A*, p & 1));
__builtin_bit_cast(A*, p & 1)->set(2); // no-crash
@@ -49,5 +49,15 @@ void gh_69922(size_t p) {
// store to the member variable `n`.
clang_analyzer_dump(__builtin_bit_cast(A*, p & 1)->n); // Ideally, this should print "2".
- // expected-warning-re at -1 {{(reg_${{[0-9]+}}<size_t p>) & 1U}}
+ // expected-warning at -1 {{Unknown}}
+}
+
+namespace {
+ typedef unsigned long uintptr_t;
+
+ bool previously_crash(const void *& ptr) {
+ clang_analyzer_dump(__builtin_bit_cast(void*, static_cast<uintptr_t>(-1)));
+ // expected-warning-re at -1 {{{{[0-9]+}} (Loc)}}
+ return ptr == __builtin_bit_cast(void*, static_cast<uintptr_t>(-1));
+ }
}
diff --git a/clang/test/Analysis/exercise-ps.c b/clang/test/Analysis/exercise-ps.c
index 50643d5b04687..21d97a364e190 100644
--- a/clang/test/Analysis/exercise-ps.c
+++ b/clang/test/Analysis/exercise-ps.c
@@ -41,7 +41,7 @@ void f4(char *array) {
_Static_assert(sizeof(int) == 4, "Wrong triple for the test");
- clang_analyzer_dump_int(__builtin_bit_cast(int, b)); // expected-warning {{lazyCompoundVal}}
+ clang_analyzer_dump_int(__builtin_bit_cast(int, b)); // expected-warning {{Unknown}}
clang_analyzer_dump_int(array[__builtin_bit_cast(int, b)]); // expected-warning {{Unknown}}
array[__builtin_bit_cast(int, b)] = 0x10; // no crash
``````````
</details>
https://github.com/llvm/llvm-project/pull/139188
More information about the cfe-commits
mailing list