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

Reply via email to