[clang] [analyzer] SValBuilder::evalBinOpLN: try simplifying the RHS first (PR #161537)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 1 08:27:38 PDT 2025
https://github.com/guillem-bartrina-sonarsource created https://github.com/llvm/llvm-project/pull/161537
The first thing `SValBuilder::evalBinOpNN` does is simplify both operators ([here](https://github.com/llvm/llvm-project/blob/main/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp#L430-L437)), why wouldn't we simplify the RHS in `SValBuilder::evalBinOpLN`?
When the LHS is an `Element`, the right side is simplified incidentally when calling `evalBinOpNN` ([here](https://github.com/llvm/llvm-project/blob/main/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp#L1169-L1170)).
Without this patch, the “base_complex” test case is **UNKNOWN** instead of **TRUE**.
>From 1aeac20735676070c8549688bb9348d261a5d669 Mon Sep 17 00:00:00 2001
From: guillem-bartrina-sonarsource <guillem.bartrina at sonarsource.com>
Date: Wed, 1 Oct 2025 17:14:11 +0200
Subject: [PATCH] [analyzer] SValBuilder::evalBinOpLN: try simplifying the RHS
first
---
.../StaticAnalyzer/Core/SimpleSValBuilder.cpp | 6 ++
clang/test/Analysis/loc-folding.cpp | 60 +++++++++++++++++++
2 files changed, 66 insertions(+)
create mode 100644 clang/test/Analysis/loc-folding.cpp
diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 84a9c43d3572e..975172a2b1f79 100644
--- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -1111,6 +1111,12 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
assert(!BinaryOperator::isComparisonOp(op) &&
"arguments to comparison ops must be of the same type");
+ // Constraints may have changed since the creation of a bound SVal. Check if
+ // the value can be simplified based on those new constraints.
+ SVal simplifiedRhs = simplifySVal(state, rhs);
+ if (auto simplifiedRhsAsNonLoc = simplifiedRhs.getAs<NonLoc>())
+ rhs = *simplifiedRhsAsNonLoc;
+
// Special case: rhs is a zero constant.
if (rhs.isZeroConstant())
return lhs;
diff --git a/clang/test/Analysis/loc-folding.cpp b/clang/test/Analysis/loc-folding.cpp
new file mode 100644
index 0000000000000..ec70143b972ef
--- /dev/null
+++ b/clang/test/Analysis/loc-folding.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -Wno-tautological-compare -analyzer-config eagerly-assume=false %s
+
+void clang_analyzer_eval(bool);
+
+void element_constant() {
+ char arr[10];
+ clang_analyzer_eval(arr + 1 > arr); // expected-warning{{TRUE}}
+}
+
+void element_known() {
+ char arr[10];
+ int off = 1;
+ clang_analyzer_eval(arr + off > arr); // expected-warning{{TRUE}}
+}
+
+void element_constrained(int off) {
+ char arr[10];
+ if (off == 1) {
+ clang_analyzer_eval(arr + off > arr); // expected-warning{{TRUE}}
+ }
+}
+
+void element_unknown(int off) {
+ char arr[10];
+ clang_analyzer_eval(arr + off > arr); // expected-warning{{UNKNOWN}}
+}
+
+void element_complex(int off) {
+ char arr[10];
+ int comp = off * 2;
+ if (off == 1) {
+ clang_analyzer_eval(arr + comp); // expected-warning{{TRUE}}
+ }
+}
+
+void base_constant(int *arr) {
+ clang_analyzer_eval(arr + 1 > arr); // expected-warning{{TRUE}}
+}
+
+void base_known(int *arr) {
+ int off = 1;
+ clang_analyzer_eval(arr + off > arr); // expected-warning{{TRUE}}
+}
+
+void base_constrained(int *arr, int off) {
+ if (off == 1) {
+ clang_analyzer_eval(arr + off > arr); // expected-warning{{TRUE}}
+ }
+}
+
+void base_unknown(int *arr, int off) {
+ clang_analyzer_eval(arr + off > arr); // expected-warning{{UNKNOWN}}
+}
+
+void base_complex(int *arr, int off) {
+ int comp = off * 2;
+ if (off == 1) {
+ clang_analyzer_eval(arr + comp > arr); // expected-warning{{TRUE}}
+ }
+}
More information about the cfe-commits
mailing list