https://github.com/ziqingluo-90 created https://github.com/llvm/llvm-project/pull/139188
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. >From 95ac7cf69dbd683f70b123446115fe3893844526 Mon Sep 17 00:00:00 2001 From: Ziqing Luo <ziq...@udel.edu> Date: Thu, 8 May 2025 17:48:41 -0700 Subject: [PATCH] [StaticAnalyzer] Handle __builtin_bit_cast Previously, CSA did not handle __builtin_bit_cast correctly. It evaluated the LvalueToRvalue conversion for the casting expression, but did not actually convert the value of the expression to be of the destination type. This commit fixes the problem. rdar://149987320 --- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 26 ++++++++++++++++++- clang/test/Analysis/builtin_bitcast.cpp | 14 ++++++++-- clang/test/Analysis/exercise-ps.c | 2 +- 3 files changed, 38 insertions(+), 4 deletions(-) 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@+1 {{(reg_${{[0-9]+}}<size_t p>) & 1U}} + // expected-warning@+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@-1 {{(reg_${{[0-9]+}}<size_t p>) & 1U}} + // expected-warning@-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@-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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits