diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 3d0a69a515ab8..886c51908b010 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -282,15 +282,47 @@ ProgramStateRef ExprEngine::handleLValueBitCast( 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)); + ExplodedNodeSet DstPreStmt; + getCheckerManager().runCheckersForPreStmt(DstPreStmt, Pred, CastE, *this); + + if (CastE->getCastKind() == CK_LValueToRValue) { + for (ExplodedNode *Node : DstPreStmt) { + ProgramStateRef State = Node->getState(); + const LocationContext *LCtx = Node->getLocationContext(); + evalLoad(Dst, CastE, CastE, Node, State, State->getSVal(Ex, LCtx)); + } + return; + } + if (CastE->getCastKind() == CK_LValueToRValueBitCast) { + // Handle `__builtin_bit_cast`: + ExplodedNodeSet DstEvalLoc; + + // Simulate the lvalue-to-rvalue conversion on `Ex`: + for (ExplodedNode *Node : DstPreStmt) { + ProgramStateRef State = Node->getState(); + const LocationContext *LCtx = Node->getLocationContext(); + evalLocation(DstEvalLoc, CastE, Ex, Node, State, State->getSVal(Ex, LCtx), + true); + } + // Simulate the operation that actually casts the original value to a new + // value of the destination type : + StmtNodeBuilder Bldr(DstEvalLoc, Dst, *currBldrCtx); + + for (ExplodedNode *Node : DstEvalLoc) { + ProgramStateRef State = Node->getState(); + const LocationContext *LCtx = Node->getLocationContext(); + // Although `Ex` is an lvalue, it could have `Loc::ConcreteInt` kind + // (e.g., `(int *)123456`). In such cases, there is no MemRegion + // available and we can't get the value to be casted. + SVal CastedV = UnknownVal(); + + if (const MemRegion *MR = State->getSVal(Ex, LCtx).getAsRegion()) { + SVal OrigV = State->getSVal(MR); + CastedV = svalBuilder.evalCast(svalBuilder.simplifySVal(State, OrigV), + CastE->getType(), Ex->getType()); + } + State = State->BindExpr(CastE, LCtx, CastedV); + Bldr.generateNode(CastE, Node, State); } return; } @@ -302,8 +334,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, if (const ExplicitCastExpr *ExCast=dyn_cast_or_null(CastE)) T = ExCast->getTypeAsWritten(); - StmtNodeBuilder Bldr(dstPreStmt, Dst, *currBldrCtx); - for (ExplodedNode *Pred : dstPreStmt) { + StmtNodeBuilder Bldr(DstPreStmt, Dst, *currBldrCtx); + for (ExplodedNode *Pred : DstPreStmt) { ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); diff --git a/clang/test/Analysis/builtin_bitcast.cpp b/clang/test/Analysis/builtin_bitcast.cpp index 5a0d9e7189b8e..2ba32ec6d23d2 100644 --- a/clang/test/Analysis/builtin_bitcast.cpp +++ b/clang/test/Analysis/builtin_bitcast.cpp @@ -1,5 +1,5 @@ // RUN: %clang_analyze_cc1 -triple x86_64-unknown-unknown -verify %s \ -// RUN: -analyzer-checker=core,debug.ExprInspection +// RUN: -analyzer-checker=core,debug.ExprInspection -analyzer-disable-checker=core.FixedAddressDereference template void clang_analyzer_dump(T); using size_t = decltype(sizeof(int)); @@ -39,7 +39,7 @@ struct A { } }; void gh_69922(size_t p) { - // expected-warning-re@+1 {{(reg_${{[0-9]+}}) & 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,20 @@ 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]+}}) & 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(-1))); + // expected-warning-re@-1 {{{{[0-9]+}} (Loc)}} + return ptr == __builtin_bit_cast(void*, static_cast(-1)); + } + + void check_loc_concreteInt() { + clang_analyzer_dump(__builtin_bit_cast(unsigned, *(reinterpret_cast(0xdeadbeef)))); + // expected-warning@-1 {{Unknown}} + } } 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