[clang] [analyzer] Reject non-symbolic iterator offsets in alpha iterator checkers (PR #232622)

Balázs Benics via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 22 05:48:16 PDT 2026


================
@@ -0,0 +1,71 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,alpha.cplusplus.IteratorRange,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=false -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,alpha.cplusplus.IteratorRange,debug.DebugIteratorModeling,debug.ExprInspection -analyzer-config aggressive-binary-operation-simplification=true -analyzer-config c++-container-inlining=true -verify %s
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+template <typename Iterator>
+long clang_analyzer_iterator_position(const Iterator &);
+template <typename Iterator>
+void *clang_analyzer_iterator_container(const Iterator &);
+void clang_analyzer_eval(bool);
+
+// Constrain the abstract offset so that advancing it produces a concrete value.
+void prefix_increment(const std::vector<int> &V) {
+  auto I = V.begin();
+  if (clang_analyzer_iterator_position(I) != 1)
+    return;
+
+  auto J = ++I;
+  clang_analyzer_eval(clang_analyzer_iterator_container(I) == &V); // expected-warning{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_container(J) == &V); // expected-warning{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(I) ==
+                      clang_analyzer_iterator_position(J)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(I) == 2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+}
+
+void postfix_increment(const std::vector<int> &V) {
+  auto I = V.begin();
+  if (clang_analyzer_iterator_position(I) != 1)
+    return;
+
+  auto J = I++;
+  clang_analyzer_eval(clang_analyzer_iterator_container(I) == &V); // expected-warning{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_container(J) == &V); // expected-warning{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(J) == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(I) == 2); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+}
+
+void prefix_decrement(const std::vector<int> &V) {
+  auto I = V.end();
+  if (clang_analyzer_iterator_position(I) != 1)
+    return;
+
+  auto J = --I;
+  clang_analyzer_eval(clang_analyzer_iterator_container(I) == &V); // expected-warning{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_container(J) == &V); // expected-warning{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(I) ==
+                      clang_analyzer_iterator_position(J)); // expected-warning at -1{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(I) == 0); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+}
+
+void postfix_decrement(const std::vector<int> &V) {
+  auto I = V.end();
+  if (clang_analyzer_iterator_position(I) != 1)
+    return;
+
+  auto J = I--;
+  clang_analyzer_eval(clang_analyzer_iterator_container(I) == &V); // expected-warning{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_container(J) == &V); // expected-warning{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(J) == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(I) == 0); // expected-warning{{TRUE}} expected-warning{{FALSE}}
+}
+
+void compound_assignment(const std::vector<int> &V) {
+  auto I = V.begin();
+  if (clang_analyzer_iterator_position(I) != 1)
+    return;
+
+  I += 2;
+  clang_analyzer_eval(clang_analyzer_iterator_container(I) == &V); // expected-warning{{TRUE}}
+  clang_analyzer_eval(clang_analyzer_iterator_position(I) == 3); // expected-warning{{TRUE}} expected-warning{{FALSE}}
----------------
steakhal wrote:

I figure the important part is that we know that the iterators correspond to the same container.
However, these lines also set the expectation that we don't know anything about the position.

Given the scope of the PR this seems like an overreach - which is fine as long as the comment would explain that the ideal outcome - which is I suppose `TRUE`.

Just leave the line with the suffix ` FIXME: This should be only TRUE` or something along the lines.

https://github.com/llvm/llvm-project/pull/232622


More information about the cfe-commits mailing list