ASDenysPetrov updated this revision to Diff 328109.
ASDenysPetrov added a comment.
Rebased on main.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D97874/new/
https://reviews.llvm.org/D97874
Files:
clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
clang/test/Analysis/cast_symbolic_ints_to_bool.cpp
Index: clang/test/Analysis/cast_symbolic_ints_to_bool.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/cast_symbolic_ints_to_bool.cpp
@@ -0,0 +1,67 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
+
+template <typename T>
+void clang_analyzer_dump(T);
+
+void test_int_to_bool(bool b, int x) {
+ clang_analyzer_dump(b); // expected-warning{{reg_$0<_Bool b>}}
+ b = x;
+ clang_analyzer_dump(b); // expected-warning{{reg_$1<int x>}}
+ if (x < 0) {
+ b = x;
+ clang_analyzer_dump(b); // expected-warning{{1 U1b}}
+ } else if (x > 0) {
+ b = x;
+ clang_analyzer_dump(b); // expected-warning{{1 U1b}}
+ } else {
+ b = x;
+ clang_analyzer_dump(b); // expected-warning{{0 U1b}}
+ }
+}
+
+void test_char_to_bool(char x) {
+ bool b = x;
+ clang_analyzer_dump(b); // expected-warning{{reg_$0<char x>}}
+ if (x < 0) {
+ bool b = x;
+ clang_analyzer_dump(b); // expected-warning{{1 U1b}}
+ } else if (x > 0) {
+ bool b = x;
+ clang_analyzer_dump(b); // expected-warning{{1 U1b}}
+ } else {
+ bool b = x;
+ clang_analyzer_dump(b); // expected-warning{{0 U1b}}
+ }
+}
+
+void test_unsigned_to_bool(bool b, unsigned x) {
+ clang_analyzer_dump(b); // expected-warning{{reg_$0<_Bool b>}}
+ b = x;
+ clang_analyzer_dump(b); // expected-warning{{reg_$1<unsigned int x>}}
+ if (x) {
+ b = x;
+ clang_analyzer_dump(b); // expected-warning{{1 U1b}}
+ } else {
+ b = x;
+ clang_analyzer_dump(b); // expected-warning{{0 U1b}}
+ }
+}
+
+void test_unsigned_to_bool(unsigned char x) {
+ bool b = x;
+ clang_analyzer_dump(b); // expected-warning{{reg_$0<unsigned char x>}}
+ if (x < 42) {
+ b = x;
+ clang_analyzer_dump(b); // expected-warning{{reg_$0<unsigned char x>}}
+ if (x) {
+ b = x;
+ clang_analyzer_dump(b); // expected-warning{{1 U1b}}
+ } else {
+ b = x;
+ clang_analyzer_dump(b); // expected-warning{{0 U1b}}
+ }
+ } else {
+ b = x;
+ clang_analyzer_dump(b); // expected-warning{{1 U1b}}
+ }
+}
Index: clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -872,11 +872,18 @@
// Symbol to bool.
if (!OriginalTy.isNull() && CastTy->isBooleanType()) {
// Non-float to bool.
- if (Loc::isLocType(OriginalTy) ||
- OriginalTy->isIntegralOrEnumerationType() ||
- OriginalTy->isMemberPointerType()) {
+ if (OriginalTy->isIntegralOrEnumerationType()) {
BasicValueFactory &BVF = getBasicValueFactory();
- return makeNonLoc(SE, BO_NE, BVF.getValue(0, SE->getType()), CastTy);
+ const llvm::APSInt &Zero = BVF.getValue(0, OriginalTy);
+ bool IsZero, IsNotZero;
+ std::tie(IsZero, IsNotZero) =
+ getStateManager().getConstraintManager().isSymValWithinOrOutsideRange(
+ State, SE, Zero, Zero);
+ // Symbolic pointer, integer to bool.
+ if (IsZero || IsNotZero)
+ return makeTruthVal(IsNotZero, CastTy);
+ // Symbolic integer to bool.
+ return V;
}
} else {
// Symbol to integer.
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -1278,6 +1278,9 @@
const llvm::APSInt *getSymVal(ProgramStateRef State,
SymbolRef Sym) const override;
+ std::pair<bool, bool>
+ isSymValWithinOrOutsideRange(ProgramStateRef State, SymbolRef Sym,
+ llvm::APSInt lower, llvm::APSInt upper) override;
ProgramStateRef removeDeadBindings(ProgramStateRef State,
SymbolReaper &SymReaper) override;
@@ -1875,6 +1878,15 @@
return T ? T->getConcreteValue() : nullptr;
}
+std::pair<bool, bool> RangeConstraintManager::isSymValWithinOrOutsideRange(
+ ProgramStateRef St, SymbolRef Sym, llvm::APSInt lower, llvm::APSInt upper) {
+ if (const RangeSet *T = getConstraint(St, Sym)) {
+ RangeSet RS = T->Intersect(getBasicVals(), F, lower, upper);
+ return {RS == *T, RS.isEmpty()};
+ }
+ return {false, false};
+}
+
//===----------------------------------------------------------------------===//
// Remove dead symbols from existing constraints
//===----------------------------------------------------------------------===//
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h
@@ -153,6 +153,19 @@
return nullptr;
}
+ /// Return pair of booleans for Within and Outside statuses.
+ /// First bool is `true` when SymbolRef range is within the range.
+ /// Second bool is `true` when SymbolRef range is outside the range.
+ /// Return 'false, false' otherwise.
+ ///
+ /// This function acts as `assumeDual` function
+ /// but it does not create any new states.
+ virtual std::pair<bool, bool>
+ isSymValWithinOrOutsideRange(ProgramStateRef state, SymbolRef sym,
+ llvm::APSInt lower, llvm::APSInt upper) {
+ return {false, false};
+ }
+
/// Scan all symbols referenced by the constraints. If the symbol is not
/// alive, remove it.
virtual ProgramStateRef removeDeadBindings(ProgramStateRef state,
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits