[analyzer][NFC] Add tests for D132236
authorTomasz Kamiński <tomasz.kamiński@sonarsource.com>
Mon, 3 Oct 2022 13:14:04 +0000 (15:14 +0200)
committerTomasz Kamiński <tomasz.kamiński@sonarsource.com>
Mon, 3 Oct 2022 13:42:38 +0000 (15:42 +0200)
D132236 would have introduced regressions in the symbol lifetime
handling. However, the testsuite did not catch this, so here we have
some tests, which would have break if D132236 had landed.

This patch addresses the comment https://reviews.llvm.org/D132236#3753238

Co-authored-by: Balazs Benics <balazs.benics@sonarsource.com>
Reviewed By: martong

Differential Revision: https://reviews.llvm.org/D134941

clang/test/Analysis/NewDeleteLeaks.cpp
clang/test/Analysis/symbol-reaper-lambda.cpp [new file with mode: 0644]
clang/test/Analysis/trivial-copy-struct.cpp

index 19a6aff..b2bad7e 100644 (file)
@@ -192,3 +192,29 @@ void use_ret() {
 // expected-note@-1 {{Potential leak of memory pointed to by 'v'}}
 
 } // namespace refkind_from_unoallocated_to_allocated
+
+// Check that memory leak is reported against a symbol if the last place it's
+// mentioned is a base region of a lazy compound value, as the program cannot
+// possibly free that memory.
+namespace symbol_reaper_lifetime {
+struct Nested {
+  int buf[2];
+};
+struct Wrapping {
+  Nested data;
+};
+
+Nested allocateWrappingAndReturnNested() {
+  // expected-note@+1 {{Memory is allocated}}
+  Wrapping const* p = new Wrapping();
+  // expected-warning@+2 {{Potential leak of memory pointed to by 'p'}}
+  // expected-note@+1    {{Potential leak of memory pointed to by 'p'}}
+  return p->data;
+}
+
+void caller() {
+  // expected-note@+1 {{Calling 'allocateWrappingAndReturnNested'}}
+  Nested n = allocateWrappingAndReturnNested();
+  (void)n;
+} // no-warning: No potential memory leak here, because that's been already reported.
+} // namespace symbol_reaper_lifetime
diff --git a/clang/test/Analysis/symbol-reaper-lambda.cpp b/clang/test/Analysis/symbol-reaper-lambda.cpp
new file mode 100644 (file)
index 0000000..c63562b
--- /dev/null
@@ -0,0 +1,26 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+// expected-no-diagnostics
+
+template <typename... Ts>
+void escape(Ts&...);
+struct Dummy {};
+
+int strange(Dummy param) {
+  Dummy local_pre_lambda;
+  int ref_captured = 0;
+
+  // LambdaExpr is modeled as lazyCompoundVal of tempRegion, that contains
+  // all captures. In this instance, this region contains a pointer/reference
+  // to ref_captured variable.
+  auto fn = [&] {
+    escape(param, local_pre_lambda);
+    return ref_captured; // no-warning: The value is not garbage.
+  };
+
+  int local_defined_after_lambda; // Unused, but necessary! Important that it's before the call.
+
+  // The ref_captured binding should not be pruned at this point, as it is still
+  // accessed via reference captured in operator() of fn.
+  return fn();
+}
+
index b9a2b1d..cd9cfde 100644 (file)
@@ -1,6 +1,7 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
 
 template <typename T> void clang_analyzer_dump(T);
+template <typename T> void clang_analyzer_value(T);
 void clang_analyzer_warnIfReached();
 
 struct Node { int* ptr; };
@@ -34,3 +35,25 @@ void copy_on_heap(Node* n1) {
   (void)(n1->ptr);
   (void)(n2->ptr);
 }
+
+struct List {
+  List* next;
+  int value;
+  int padding;
+};
+
+void deadCode(List orig) {
+  List c = orig;
+  clang_analyzer_dump(c.value);
+  // expected-warning-re@-1 {{reg_${{[0-9]+}}<int orig.value>}}
+  if (c.value == 42)
+    return;
+  clang_analyzer_value(c.value);
+  // expected-warning@-1 {{32s:{ [-2147483648, 2147483647] }}}
+  // The symbol was garbage collected too early, hence we lose the constraints.
+  if (c.value != 42)
+    return;
+
+  // Dead code should be unreachable
+  clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}