diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index ad5bb66c4fff3..76fb7481f6519 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -715,10 +715,14 @@ void CXXInstanceCall::getExtraInvalidatedValues( SVal CXXInstanceCall::getCXXThisVal() const { const Expr *Base = getCXXThisExpr(); // FIXME: This doesn't handle an overloaded ->* operator. - if (!Base) - return UnknownVal(); + SVal ThisVal = Base ? getSVal(Base) : UnknownVal(); + + if (isa(ThisVal)) { + SValBuilder &SVB = getState()->getStateManager().getSValBuilder(); + QualType OriginalTy = ThisVal.getType(SVB.getContext()); + return SVB.evalCast(ThisVal, Base->getType(), OriginalTy); + } - SVal ThisVal = getSVal(Base); assert(ThisVal.isUnknownOrUndef() || isa(ThisVal)); return ThisVal; } diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index d89d82626f726..9375f39b2d71d 100644 --- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -980,6 +980,11 @@ class EvalCastVisitor : public SValVisitor { return VB.makeNonLoc(SE, T, CastTy); } + // FIXME: We should be able to cast NonLoc -> Loc + // (when Loc::isLocType(CastTy) is true) + // But it's hard to do as SymbolicRegions can't refer to SymbolCasts holding + // generic SymExprs. Check the commit message for the details. + // Symbol to pointer and whatever else. return UnknownVal(); } diff --git a/clang/test/Analysis/builtin_bitcast.cpp b/clang/test/Analysis/builtin_bitcast.cpp index 396e7caa45f6a..5a0d9e7189b8e 100644 --- a/clang/test/Analysis/builtin_bitcast.cpp +++ b/clang/test/Analysis/builtin_bitcast.cpp @@ -2,6 +2,7 @@ // RUN: -analyzer-checker=core,debug.ExprInspection template void clang_analyzer_dump(T); +using size_t = decltype(sizeof(int)); __attribute__((always_inline)) static inline constexpr unsigned int _castf32_u32(float __A) { return __builtin_bit_cast(unsigned int, __A); // no-warning @@ -30,3 +31,23 @@ void test(int i) { clang_analyzer_dump(g4); // expected-warning@-1 {{&i [as 64 bit integer]}} } + +struct A { + int n; + void set(int x) { + n = x; + } +}; +void gh_69922(size_t p) { + // expected-warning-re@+1 {{(reg_${{[0-9]+}}) & 1U}} + clang_analyzer_dump(__builtin_bit_cast(A*, p & 1)); + + __builtin_bit_cast(A*, p & 1)->set(2); // no-crash + // However, since the `this` pointer is expected to be a Loc, but we have + // NonLoc there, we simply give up and resolve it as `Unknown`. + // Then, inside the `set()` member function call we can't evaluate the + // 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}} +}