Skip to content

Commit 4122958

Browse files
authored
[analyzer] Fix crashing __builtin_bit_cast (#139188)
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
1 parent 831592d commit 4122958

File tree

3 files changed

+62
-15
lines changed

3 files changed

+62
-15
lines changed

clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -286,15 +286,47 @@ ProgramStateRef ExprEngine::handleLValueBitCast(
286286
void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
287287
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
288288

289-
ExplodedNodeSet dstPreStmt;
290-
getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this);
291-
292-
if (CastE->getCastKind() == CK_LValueToRValue ||
293-
CastE->getCastKind() == CK_LValueToRValueBitCast) {
294-
for (ExplodedNode *subExprNode : dstPreStmt) {
295-
ProgramStateRef state = subExprNode->getState();
296-
const LocationContext *LCtx = subExprNode->getLocationContext();
297-
evalLoad(Dst, CastE, CastE, subExprNode, state, state->getSVal(Ex, LCtx));
289+
ExplodedNodeSet DstPreStmt;
290+
getCheckerManager().runCheckersForPreStmt(DstPreStmt, Pred, CastE, *this);
291+
292+
if (CastE->getCastKind() == CK_LValueToRValue) {
293+
for (ExplodedNode *Node : DstPreStmt) {
294+
ProgramStateRef State = Node->getState();
295+
const LocationContext *LCtx = Node->getLocationContext();
296+
evalLoad(Dst, CastE, CastE, Node, State, State->getSVal(Ex, LCtx));
297+
}
298+
return;
299+
}
300+
if (CastE->getCastKind() == CK_LValueToRValueBitCast) {
301+
// Handle `__builtin_bit_cast`:
302+
ExplodedNodeSet DstEvalLoc;
303+
304+
// Simulate the lvalue-to-rvalue conversion on `Ex`:
305+
for (ExplodedNode *Node : DstPreStmt) {
306+
ProgramStateRef State = Node->getState();
307+
const LocationContext *LCtx = Node->getLocationContext();
308+
evalLocation(DstEvalLoc, CastE, Ex, Node, State, State->getSVal(Ex, LCtx),
309+
true);
310+
}
311+
// Simulate the operation that actually casts the original value to a new
312+
// value of the destination type :
313+
StmtNodeBuilder Bldr(DstEvalLoc, Dst, *currBldrCtx);
314+
315+
for (ExplodedNode *Node : DstEvalLoc) {
316+
ProgramStateRef State = Node->getState();
317+
const LocationContext *LCtx = Node->getLocationContext();
318+
// Although `Ex` is an lvalue, it could have `Loc::ConcreteInt` kind
319+
// (e.g., `(int *)123456`). In such cases, there is no MemRegion
320+
// available and we can't get the value to be casted.
321+
SVal CastedV = UnknownVal();
322+
323+
if (const MemRegion *MR = State->getSVal(Ex, LCtx).getAsRegion()) {
324+
SVal OrigV = State->getSVal(MR);
325+
CastedV = svalBuilder.evalCast(svalBuilder.simplifySVal(State, OrigV),
326+
CastE->getType(), Ex->getType());
327+
}
328+
State = State->BindExpr(CastE, LCtx, CastedV);
329+
Bldr.generateNode(CastE, Node, State);
298330
}
299331
return;
300332
}
@@ -306,8 +338,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
306338
if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
307339
T = ExCast->getTypeAsWritten();
308340

309-
StmtNodeBuilder Bldr(dstPreStmt, Dst, *currBldrCtx);
310-
for (ExplodedNode *Pred : dstPreStmt) {
341+
StmtNodeBuilder Bldr(DstPreStmt, Dst, *currBldrCtx);
342+
for (ExplodedNode *Pred : DstPreStmt) {
311343
ProgramStateRef state = Pred->getState();
312344
const LocationContext *LCtx = Pred->getLocationContext();
313345

clang/test/Analysis/builtin_bitcast.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %clang_analyze_cc1 -triple x86_64-unknown-unknown -verify %s \
2-
// RUN: -analyzer-checker=core,debug.ExprInspection
2+
// RUN: -analyzer-checker=core,debug.ExprInspection -analyzer-disable-checker=core.FixedAddressDereference
33

44
template <typename T> void clang_analyzer_dump(T);
55
using size_t = decltype(sizeof(int));
@@ -39,7 +39,7 @@ struct A {
3939
}
4040
};
4141
void gh_69922(size_t p) {
42-
// expected-warning-re@+1 {{(reg_${{[0-9]+}}<size_t p>) & 1U}}
42+
// expected-warning@+1 {{Unknown}}
4343
clang_analyzer_dump(__builtin_bit_cast(A*, p & 1));
4444

4545
__builtin_bit_cast(A*, p & 1)->set(2); // no-crash
@@ -49,5 +49,20 @@ void gh_69922(size_t p) {
4949
// store to the member variable `n`.
5050

5151
clang_analyzer_dump(__builtin_bit_cast(A*, p & 1)->n); // Ideally, this should print "2".
52-
// expected-warning-re@-1 {{(reg_${{[0-9]+}}<size_t p>) & 1U}}
52+
// expected-warning@-1 {{Unknown}}
53+
}
54+
55+
namespace {
56+
typedef unsigned long uintptr_t;
57+
58+
bool previously_crash(const void *& ptr) {
59+
clang_analyzer_dump(__builtin_bit_cast(void*, static_cast<uintptr_t>(-1)));
60+
// expected-warning-re@-1 {{{{[0-9]+}} (Loc)}}
61+
return ptr == __builtin_bit_cast(void*, static_cast<uintptr_t>(-1));
62+
}
63+
64+
void check_loc_concreteInt() {
65+
clang_analyzer_dump(__builtin_bit_cast(unsigned, *(reinterpret_cast<int*>(0xdeadbeef))));
66+
// expected-warning@-1 {{Unknown}}
67+
}
5368
}

clang/test/Analysis/exercise-ps.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void f4(char *array) {
4141

4242
_Static_assert(sizeof(int) == 4, "Wrong triple for the test");
4343

44-
clang_analyzer_dump_int(__builtin_bit_cast(int, b)); // expected-warning {{lazyCompoundVal}}
44+
clang_analyzer_dump_int(__builtin_bit_cast(int, b)); // expected-warning {{Unknown}}
4545
clang_analyzer_dump_int(array[__builtin_bit_cast(int, b)]); // expected-warning {{Unknown}}
4646

4747
array[__builtin_bit_cast(int, b)] = 0x10; // no crash

0 commit comments

Comments
 (0)