[analyzer] Invalidate placement args; return the pointer given to placement new
The default global placement new just returns the pointer it is given.
Note that other custom 'new' implementations with placement args are not
guaranteed to do this.
In addition, we need to invalidate placement args, since they may be updated by
the allocator function. (Also, right now we don't properly handle the
constructor inside a CXXNewExpr, so we need to invalidate the placement args
just so that callers know something changed!)
This invalidation is not perfect because CallOrObjCMessage doesn't support
CXXNewExpr, and all of our invalidation callbacks expect that if there's no
CallOrObjCMessage, the invalidation is happening manually (e.g. by a direct
assignment) and shouldn't affect checker-specific metadata (like malloc state);
hence the malloc test case in new-fail.cpp. But region values are now
properly invalidated, at least.
The long-term solution to this problem is to rework CallOrObjCMessage into
something more general, rather than the morass of branches it is today.
<rdar://problem/11679031>
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158784 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/Analysis/new.cpp b/test/Analysis/new.cpp
index 5ca8c46..3cf5b0f 100644
--- a/test/Analysis/new.cpp
+++ b/test/Analysis/new.cpp
@@ -1,15 +1,36 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s
-// XFAIL: *
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store region -verify %s
-void f1() {
- int *n = new int;
- if (*n) { // expected-warning {{Branch condition evaluates to a garbage value}}
- }
+void clang_analyzer_eval(bool);
+
+typedef typeof(sizeof(int)) size_t;
+extern "C" void *malloc(size_t);
+
+// This is the standard placement new.
+inline void* operator new(size_t, void* __p) throw()
+{
+ return __p;
}
-void f2() {
- int *n = new int(3);
- if (*n) { // no-warning
- }
+void *testPlacementNew() {
+ int *x = (int *)malloc(sizeof(int));
+ *x = 1;
+ clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};
+
+ void *y = new (x) int;
+ clang_analyzer_eval(x == y); // expected-warning{{TRUE}};
+ clang_analyzer_eval(*x == 1); // expected-warning{{UNKNOWN}};
+
+ return y;
+}
+
+void *operator new(size_t, size_t, int *);
+void *testCustomNew() {
+ int x[1] = {1};
+ clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};
+
+ void *y = new (0, x) int;
+ clang_analyzer_eval(*x == 1); // expected-warning{{UNKNOWN}};
+
+ return y; // no-warning
}