[clang] [analyzer] Fix assertion failure in `CXXInstanceCall::getCXXThisVal` (PR #70837)
Balazs Benics via cfe-commits
cfe-commits at lists.llvm.org
Sat Nov 4 02:37:15 PDT 2023
https://github.com/steakhal updated https://github.com/llvm/llvm-project/pull/70837
>From 2de19fc8e14319674ce87c18771ba1b8ba22f79b Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Mon, 23 Oct 2023 18:10:29 +0200
Subject: [PATCH 1/3] [analyzer] Fix assertion failure in
CXXInstanceCall::getCXXThisVal
Workaround the case when the `this` pointer is actually a `NonLoc`, by
returning `Unknown` instead.
The solution isn't ideal, as `this` should be really a `Loc`, but due to
how casts work, I feel this is our easiest and best option.
I've considered using `SVB.evalCast(ThisVal, Base->getType(), QualType())`,
but it doesn't work as `EvalCastVisitor::VisitNonLocSymbolVal()` only
evaluates casts that happen from NonLoc to NonLocs.
When I tried to actually implement that case, I figured:
1) Create a SymbolicRegion from that nonloc::SymbolVal; but SymbolRegion
ctor expects a pointer type for the symbol.
2) Okay, just have a SymbolCast, getting us the pointer type; but
SymbolRegion expects SymbolData symbols, not generic SymExprs, as stated:
> // Because pointer arithmetic is represented by ElementRegion layers,
> // the base symbol here should not contain any arithmetic.
3) We can't use ElementRegions to perform this cast because to have an
ElementRegion, you already have to have a SubRegion that you want to
cast, but the point is that we don't have that.
At this point, I gave up, and just returned `Unknown` xD
IMO this is still better than having a crash.
Fixes #69922
---
clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 5 ++---
clang/test/Analysis/builtin_bitcast.cpp | 21 +++++++++++++++++++++
2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index ad5bb66c4fff3c8..20bc64dc2631cec 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -715,10 +715,9 @@ void CXXInstanceCall::getExtraInvalidatedValues(
SVal CXXInstanceCall::getCXXThisVal() const {
const Expr *Base = getCXXThisExpr();
// FIXME: This doesn't handle an overloaded ->* operator.
- if (!Base)
+ SVal ThisVal = Base ? getSVal(Base) : UnknownVal();
+ if (isa<NonLoc>(ThisVal))
return UnknownVal();
-
- SVal ThisVal = getSVal(Base);
assert(ThisVal.isUnknownOrUndef() || isa<Loc>(ThisVal));
return ThisVal;
}
diff --git a/clang/test/Analysis/builtin_bitcast.cpp b/clang/test/Analysis/builtin_bitcast.cpp
index 396e7caa45f6acd..13475694d287a22 100644
--- a/clang/test/Analysis/builtin_bitcast.cpp
+++ b/clang/test/Analysis/builtin_bitcast.cpp
@@ -30,3 +30,24 @@ void test(int i) {
clang_analyzer_dump(g4);
// expected-warning at -1 {{&i [as 64 bit integer]}}
}
+
+struct A {
+ int n;
+ void set(int x) {
+ n = x;
+ }
+};
+using ptr_size = decltype(sizeof(void *));
+void gh_69922(ptr_size p) {
+ // expected-warning-re at +1 {{(reg_${{[0-9]+}}<ptr_size p>) & 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 at -1 {{(reg_${{[0-9]+}}<ptr_size p>) & 1U}}
+}
>From bcb048c09dcc7bb2728d46afc0ff9a09cf71f663 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Tue, 31 Oct 2023 19:20:16 +0100
Subject: [PATCH 2/3] Add fixme and add the ineffective evalCast
---
clang/lib/StaticAnalyzer/Core/CallEvent.cpp | 9 +++++++--
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp | 5 +++++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 20bc64dc2631cec..76fb7481f65194b 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -716,8 +716,13 @@ SVal CXXInstanceCall::getCXXThisVal() const {
const Expr *Base = getCXXThisExpr();
// FIXME: This doesn't handle an overloaded ->* operator.
SVal ThisVal = Base ? getSVal(Base) : UnknownVal();
- if (isa<NonLoc>(ThisVal))
- return UnknownVal();
+
+ if (isa<NonLoc>(ThisVal)) {
+ SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
+ QualType OriginalTy = ThisVal.getType(SVB.getContext());
+ return SVB.evalCast(ThisVal, Base->getType(), OriginalTy);
+ }
+
assert(ThisVal.isUnknownOrUndef() || isa<Loc>(ThisVal));
return ThisVal;
}
diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index d89d82626f72694..9375f39b2d71dd4 100644
--- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -980,6 +980,11 @@ class EvalCastVisitor : public SValVisitor<EvalCastVisitor, SVal> {
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();
}
>From 1d2050fb73a8166d9a9913e07f75f3f1a270bb67 Mon Sep 17 00:00:00 2001
From: Balazs Benics <benicsbalazs at gmail.com>
Date: Sat, 4 Nov 2023 10:35:51 +0100
Subject: [PATCH 3/3] Prefer using size_t over custom typedef
---
clang/test/Analysis/builtin_bitcast.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/test/Analysis/builtin_bitcast.cpp b/clang/test/Analysis/builtin_bitcast.cpp
index 13475694d287a22..5a0d9e7189b8edd 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 <typename T> 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
@@ -37,9 +38,8 @@ struct A {
n = x;
}
};
-using ptr_size = decltype(sizeof(void *));
-void gh_69922(ptr_size p) {
- // expected-warning-re at +1 {{(reg_${{[0-9]+}}<ptr_size p>) & 1U}}
+void gh_69922(size_t p) {
+ // expected-warning-re at +1 {{(reg_${{[0-9]+}}<size_t p>) & 1U}}
clang_analyzer_dump(__builtin_bit_cast(A*, p & 1));
__builtin_bit_cast(A*, p & 1)->set(2); // no-crash
@@ -49,5 +49,5 @@ void gh_69922(ptr_size 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 at -1 {{(reg_${{[0-9]+}}<ptr_size p>) & 1U}}
+ // expected-warning-re at -1 {{(reg_${{[0-9]+}}<size_t p>) & 1U}}
}
More information about the cfe-commits
mailing list