diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -288,8 +288,36 @@ ExplodedNodeSet dstPreStmt; getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this); - if (CastE->getCastKind() == CK_LValueToRValue || - CastE->getCastKind() == CK_LValueToRValueBitCast) { + if (CastE->getCastKind() == CK_LValueToRValueBitCast) { + // Do the same as for 'CK_LValueToRValue' but cast the resulting value to + // the appropriate type before binding. + for (ExplodedNode *subExprNode : dstPreStmt) { + ProgramStateRef state = subExprNode->getState(); + const LocationContext *LCtx = subExprNode->getLocationContext(); + Optional Location = state->getSVal(Ex, LCtx).getAs(); + if (!Location) + return; + + ExplodedNodeSet Tmp; + evalLocation(Tmp, CastE, CastE, subExprNode, state, *Location, true); + if (Tmp.empty()) + return; + + // Proceed with the load. + StmtNodeBuilder Bldr(Tmp, Dst, *currBldrCtx); + for (ExplodedNode *I : Tmp) { + state = I->getState(); + + SVal V = state->getSVal(*Location, CastE->getType()); + SVal CastV = getSValBuilder().evalCast(V, CastE->getType(), QualType{}); + Bldr.generateNode(CastE, I, state->BindExpr(CastE, LCtx, CastV), + nullptr, ProgramPoint::PostLoadKind); + } + } + return; + } + + if (CastE->getCastKind() == CK_LValueToRValue) { for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); I!=E; ++I) { ExplodedNode *subExprNode = *I; diff --git a/clang/test/Analysis/ptr-arith.cpp b/clang/test/Analysis/ptr-arith.cpp --- a/clang/test/Analysis/ptr-arith.cpp +++ b/clang/test/Analysis/ptr-arith.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_analyze_cc1 -Wno-unused-value -std=c++14 -analyzer-checker=core,debug.ExprInspection,alpha.core.PointerArithm -verify %s +// RUN: %clang_analyze_cc1 -Wno-unused-value -std=c++14 -verify %s -triple x86_64-pc-linux-gnu \ +// RUN: -analyzer-checker=core,debug.ExprInspection,alpha.core.PointerArithm template void clang_analyzer_dump(T); @@ -141,3 +142,22 @@ return bits->b; // no-warning } } // namespace Bug_55934 + +void LValueToRValueBitCast_dumps(void *p, char (*array)[8]) { + clang_analyzer_dump(p); + clang_analyzer_dump(array); + // expected-warning@-2 {{&SymRegion{reg_$0}}} + // expected-warning@-2 {{&SymRegion{reg_$1}}} + clang_analyzer_dump((unsigned long)p); + clang_analyzer_dump(__builtin_bit_cast(unsigned long, p)); + // expected-warning@-2 {{&SymRegion{reg_$0} [as 64 bit integer]}} + // expected-warning@-2 {{&SymRegion{reg_$0} [as 64 bit integer]}} + clang_analyzer_dump((unsigned long)array); + clang_analyzer_dump(__builtin_bit_cast(unsigned long, array)); + // expected-warning@-2 {{&SymRegion{reg_$1} [as 64 bit integer]}} + // expected-warning@-2 {{&SymRegion{reg_$1} [as 64 bit integer]}} +} + +unsigned long ptr_arithmetic(void *p) { + return __builtin_bit_cast(unsigned long, p) + 1; // no-crash +}