aboutsummaryrefslogtreecommitdiff
path: root/test/Analysis/inlining
diff options
context:
space:
mode:
Diffstat (limited to 'test/Analysis/inlining')
-rw-r--r--test/Analysis/inlining/containers.cpp241
-rw-r--r--test/Analysis/inlining/dyn-dispatch-bifurcate.cpp5
-rw-r--r--test/Analysis/inlining/eager-reclamation-path-notes.c144
-rw-r--r--test/Analysis/inlining/eager-reclamation-path-notes.cpp36
-rw-r--r--test/Analysis/inlining/false-positive-suppression.c97
-rw-r--r--test/Analysis/inlining/false-positive-suppression.cpp99
-rw-r--r--test/Analysis/inlining/false-positive-suppression.m38
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.c13
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.cpp43
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.m85
-rw-r--r--test/Analysis/inlining/path-notes.c934
-rw-r--r--test/Analysis/inlining/path-notes.cpp1685
-rw-r--r--test/Analysis/inlining/path-notes.m438
-rw-r--r--test/Analysis/inlining/stl.cpp4
14 files changed, 3325 insertions, 537 deletions
diff --git a/test/Analysis/inlining/containers.cpp b/test/Analysis/inlining/containers.cpp
new file mode 100644
index 0000000000..73b2957ad6
--- /dev/null
+++ b/test/Analysis/inlining/containers.cpp
@@ -0,0 +1,241 @@
+// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -analyzer-config c++-container-inlining=false -verify %s
+// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -analyzer-config c++-container-inlining=true -DINLINE=1 -verify %s
+
+#ifndef HEADER
+
+void clang_analyzer_eval(bool);
+void clang_analyzer_checkInlined(bool);
+
+#define HEADER
+#include "containers.cpp"
+#undef HEADER
+
+void test() {
+ MySet set(0);
+
+ clang_analyzer_eval(set.isEmpty());
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+
+ clang_analyzer_eval(set.raw_begin() == set.raw_end());
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+
+ clang_analyzer_eval(set.begin().impl == set.end().impl);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+}
+
+void testSubclass(MySetSubclass &sub) {
+ sub.useIterator(sub.begin());
+
+ MySetSubclass local;
+}
+
+void testWrappers(BeginOnlySet &w1, IteratorStructOnlySet &w2,
+ IteratorTypedefOnlySet &w3, IteratorUsingOnlySet &w4) {
+ BeginOnlySet local1;
+ IteratorStructOnlySet local2;
+ IteratorTypedefOnlySet local3;
+ IteratorUsingOnlySet local4;
+
+ clang_analyzer_eval(w1.begin().impl.impl == w1.begin().impl.impl);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+
+ clang_analyzer_eval(w2.start().impl == w2.start().impl);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+
+ clang_analyzer_eval(w3.start().impl == w3.start().impl);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+
+ clang_analyzer_eval(w4.start().impl == w4.start().impl);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#else
+ // expected-warning@-4 {{UNKNOWN}}
+#endif
+}
+
+
+#else // HEADER
+
+#include "../Inputs/system-header-simulator-cxx.h"
+
+class MySet {
+ int *storage;
+ unsigned size;
+public:
+ MySet() : storage(0), size(0) {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+
+ MySet(unsigned n) : storage(new int[n]), size(n) {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+
+ ~MySet() { delete[] storage; }
+
+ bool isEmpty() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return size == 0;
+ }
+
+ struct iterator {
+ int *impl;
+
+ iterator(int *p) : impl(p) {}
+ };
+
+ iterator begin() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return iterator(storage);
+ }
+
+ iterator end() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return iterator(storage+size);
+ }
+
+ typedef int *raw_iterator;
+
+ raw_iterator raw_begin() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return storage;
+ }
+ raw_iterator raw_end() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return storage + size;
+ }
+};
+
+class MySetSubclass : public MySet {
+public:
+ MySetSubclass() {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+
+ void useIterator(iterator i) {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ }
+};
+
+class BeginOnlySet {
+ MySet impl;
+public:
+ struct IterImpl {
+ MySet::iterator impl;
+ typedef std::forward_iterator_tag iterator_category;
+
+ IterImpl(MySet::iterator i) : impl(i) {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+ };
+
+ BeginOnlySet() {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+
+ typedef IterImpl wrapped_iterator;
+
+ wrapped_iterator begin() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return IterImpl(impl.begin());
+ }
+};
+
+class IteratorTypedefOnlySet {
+ MySet impl;
+public:
+
+ IteratorTypedefOnlySet() {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+
+ typedef MySet::iterator iterator;
+
+ iterator start() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return impl.begin();
+ }
+};
+
+class IteratorUsingOnlySet {
+ MySet impl;
+public:
+
+ IteratorUsingOnlySet() {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+
+ using iterator = MySet::iterator;
+
+ iterator start() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return impl.begin();
+ }
+};
+
+class IteratorStructOnlySet {
+ MySet impl;
+public:
+
+ IteratorStructOnlySet() {
+ clang_analyzer_checkInlined(true);
+#if INLINE
+ // expected-warning@-2 {{TRUE}}
+#endif
+ }
+
+ struct iterator {
+ int *impl;
+ };
+
+ iterator start() {
+ clang_analyzer_checkInlined(true); // expected-warning {{TRUE}}
+ return iterator{impl.begin().impl};
+ }
+};
+
+#endif // HEADER
diff --git a/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp b/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp
index 890e5640ce..d219446fc9 100644
--- a/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp
+++ b/test/Analysis/inlining/dyn-dispatch-bifurcate.cpp
@@ -16,6 +16,11 @@ void testKnown() {
clang_analyzer_eval(a.get() == 0); // expected-warning{{TRUE}}
}
+void testNew() {
+ A *a = new A();
+ clang_analyzer_eval(a->get() == 0); // expected-warning{{TRUE}}
+}
+
namespace ReinterpretDisruptsDynamicTypeInfo {
class Parent {};
diff --git a/test/Analysis/inlining/eager-reclamation-path-notes.c b/test/Analysis/inlining/eager-reclamation-path-notes.c
index f3e7376156..65613658fc 100644
--- a/test/Analysis/inlining/eager-reclamation-path-notes.c
+++ b/test/Analysis/inlining/eager-reclamation-path-notes.c
@@ -120,40 +120,6 @@ void testChainedCalls() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>21</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>21</integer>
// CHECK-NEXT: <key>col</key><integer>10</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -286,11 +252,45 @@ void testChainedCalls() {
// CHECK-NEXT: </array>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>6</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>6</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <key>ranges</key>
@@ -324,7 +324,7 @@ void testChainedCalls() {
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>6</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </dict>
@@ -577,40 +577,6 @@ void testChainedCalls() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>33</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>33</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>33</integer>
-// CHECK-NEXT: <key>col</key><integer>11</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>33</integer>
-// CHECK-NEXT: <key>col</key><integer>17</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>33</integer>
// CHECK-NEXT: <key>col</key><integer>11</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
@@ -743,11 +709,45 @@ void testChainedCalls() {
// CHECK-NEXT: </array>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>28</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>28</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>28</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>28</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>kind</key><string>event</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>28</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: <key>ranges</key>
@@ -781,7 +781,7 @@ void testChainedCalls() {
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>28</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </dict>
diff --git a/test/Analysis/inlining/eager-reclamation-path-notes.cpp b/test/Analysis/inlining/eager-reclamation-path-notes.cpp
index 3ee9d92b01..05411bbc77 100644
--- a/test/Analysis/inlining/eager-reclamation-path-notes.cpp
+++ b/test/Analysis/inlining/eager-reclamation-path-notes.cpp
@@ -202,7 +202,7 @@ int memberCallBaseDisappears() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
// CHECK-NEXT: <key>extended_message</key>
// CHECK-NEXT: <string>Returning from &apos;getNullWrapper&apos;</string>
// CHECK-NEXT: <key>message</key>
@@ -217,40 +217,6 @@ int memberCallBaseDisappears() {
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>
// CHECK-NEXT: <key>line</key><integer>24</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>24</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>24</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>24</integer>
-// CHECK-NEXT: <key>col</key><integer>34</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>24</integer>
// CHECK-NEXT: <key>col</key><integer>21</integer>
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
diff --git a/test/Analysis/inlining/false-positive-suppression.c b/test/Analysis/inlining/false-positive-suppression.c
index bed64f1837..c5c6bb875e 100644
--- a/test/Analysis/inlining/false-positive-suppression.c
+++ b/test/Analysis/inlining/false-positive-suppression.c
@@ -9,6 +9,8 @@ int *getNull() {
return 0;
}
+int* getPtr();
+
int *dynCastToInt(void *ptr) {
if (opaquePropertyCheck(ptr))
return (int *)ptr;
@@ -141,6 +143,27 @@ void testTrackNullVariable() {
#endif
}
+void inlinedIsDifferent(int inlined) {
+ int i;
+
+ // We were erroneously picking up the inner stack frame's initialization,
+ // even though the error occurs in the outer stack frame!
+ int *p = inlined ? &i : getNull();
+
+ if (!inlined)
+ inlinedIsDifferent(1);
+
+ *p = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+void testInlinedIsDifferent() {
+ // <rdar://problem/13787723>
+ inlinedIsDifferent(0);
+}
+
// ---------------------------------------
// FALSE NEGATIVES (over-suppression)
@@ -191,3 +214,77 @@ void testAlwaysReturnNull(void *input) {
#endif
}
+int derefArg(int *p) {
+ return *p;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+void ternaryArg(char cond) {
+ static int x;
+ derefArg(cond ? &x : getNull());
+}
+
+int derefArgCast(char *p) {
+ return *p;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+void ternaryArgCast(char cond) {
+ static int x;
+ derefArgCast((char*)((unsigned)cond ? &x : getNull()));
+}
+
+int derefAssignment(int *p) {
+ return *p;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+void ternaryAssignment(char cond) {
+ static int x;
+ int *p = cond ? getNull() : getPtr();
+ derefAssignment(p);
+}
+
+int *retNull(char cond) {
+ static int x;
+ return cond ? &x : getNull();
+}
+int ternaryRetNull(char cond) {
+ int *p = retNull(cond);
+ return *p;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+// Test suppression of nested conditional operators.
+int testConditionalOperatorSuppress(int x) {
+ return *(x ? getNull() : getPtr());
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+int testNestedConditionalOperatorSuppress(int x) {
+ return *(x ? (x ? getNull() : getPtr()) : getPtr());
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+int testConditionalOperator(int x) {
+ return *(x ? 0 : getPtr()); // expected-warning {{Dereference of null pointer}}
+}
+int testNestedConditionalOperator(int x) {
+ return *(x ? (x ? 0 : getPtr()) : getPtr()); // expected-warning {{Dereference of null pointer}}
+}
+
+int testConditionalOperatorSuppressFloatCond(float x) {
+ return *(x ? getNull() : getPtr());
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
diff --git a/test/Analysis/inlining/false-positive-suppression.cpp b/test/Analysis/inlining/false-positive-suppression.cpp
index f27c7cf364..bff6907809 100644
--- a/test/Analysis/inlining/false-positive-suppression.cpp
+++ b/test/Analysis/inlining/false-positive-suppression.cpp
@@ -40,6 +40,11 @@ inline void* operator new(__typeof__(sizeof(int)), void* __p) throw()
extern bool coin();
+class SomeClass {
+public:
+ void doSomething();
+};
+
namespace References {
class Map {
int *&getNewBox();
@@ -79,15 +84,10 @@ namespace References {
*box = 1; // no-warning
int *&box2 = m.getValue(i);
- box = 0;
- *box = 1; // expected-warning {{Dereference of null pointer}}
+ box2 = 0;
+ *box2 = 1; // expected-warning {{Dereference of null pointer}}
}
- class SomeClass {
- public:
- void doSomething();
- };
-
SomeClass *&getSomeClass() {
if (coin()) {
extern SomeClass *&opaqueClass();
@@ -125,3 +125,88 @@ namespace References {
#endif
}
}
+
+class X{
+public:
+ void get();
+};
+
+X *getNull() {
+ return 0;
+}
+
+void deref1(X *const &p) {
+ return p->get();
+ #ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+ #endif
+}
+
+void test1() {
+ return deref1(getNull());
+}
+
+void deref2(X *p3) {
+ p3->get();
+ #ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+ #endif
+}
+
+void pass2(X *const &p2) {
+ deref2(p2);
+}
+
+void test2() {
+ pass2(getNull());
+}
+
+void deref3(X *const &p2) {
+ X *p3 = p2;
+ p3->get();
+ #ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+ #endif
+}
+
+void test3() {
+ deref3(getNull());
+}
+
+
+namespace Cleanups {
+ class NonTrivial {
+ public:
+ ~NonTrivial();
+
+ SomeClass *getNull() {
+ return 0;
+ }
+ };
+
+ void testImmediate() {
+ NonTrivial().getNull()->doSomething();
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+#endif
+ }
+
+ void testAssignment() {
+ SomeClass *ptr = NonTrivial().getNull();
+ ptr->doSomething();
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+#endif
+ }
+
+ void testArgumentHelper(SomeClass *arg) {
+ arg->doSomething();
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Called C++ object pointer is null}}
+#endif
+ }
+
+ void testArgument() {
+ testArgumentHelper(NonTrivial().getNull());
+ }
+}
diff --git a/test/Analysis/inlining/false-positive-suppression.m b/test/Analysis/inlining/false-positive-suppression.m
new file mode 100644
index 0000000000..53ec138367
--- /dev/null
+++ b/test/Analysis/inlining/false-positive-suppression.m
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config suppress-null-return-paths=false -verify %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify -DSUPPRESSED=1 %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config avoid-suppressing-null-argument-paths=true -DSUPPRESSED=1 -DNULL_ARGS=1 -verify %s
+
+#ifdef SUPPRESSED
+// expected-no-diagnostics
+#endif
+
+@interface PointerWrapper
+- (int *)getPtr;
+- (id)getObject;
+@end
+
+id getNil() {
+ return 0;
+}
+
+void testNilReceiverHelperA(int *x) {
+ *x = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+void testNilReceiverHelperB(int *x) {
+ *x = 1;
+#ifndef SUPPRESSED
+ // expected-warning@-2 {{Dereference of null pointer}}
+#endif
+}
+
+void testNilReceiver(int coin) {
+ id x = getNil();
+ if (coin)
+ testNilReceiverHelperA([x getPtr]);
+ else
+ testNilReceiverHelperB([[x getObject] getPtr]);
+}
diff --git a/test/Analysis/inlining/inline-defensive-checks.c b/test/Analysis/inlining/inline-defensive-checks.c
index df3a8f2281..aa7f70030c 100644
--- a/test/Analysis/inlining/inline-defensive-checks.c
+++ b/test/Analysis/inlining/inline-defensive-checks.c
@@ -97,3 +97,16 @@ void test24(char *buffer) {
use(buffer);
buffer[1] = 'b';
}
+
+// Ensure idc works on pointers with constant offset.
+void idcchar(const char *s2) {
+ if(s2)
+ ;
+}
+void testConstantOffset(char *value) {
+ char *cursor = value + 5;
+ idcchar(cursor);
+ if (*cursor) {
+ cursor++;
+ }
+}
diff --git a/test/Analysis/inlining/inline-defensive-checks.cpp b/test/Analysis/inlining/inline-defensive-checks.cpp
index c77961d03c..b69c535657 100644
--- a/test/Analysis/inlining/inline-defensive-checks.cpp
+++ b/test/Analysis/inlining/inline-defensive-checks.cpp
@@ -1,6 +1,12 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -verify %s
// expected-no-diagnostics
+extern void __assert_fail (__const char *__assertion, __const char *__file,
+ unsigned int __line, __const char *__function)
+__attribute__ ((__noreturn__));
+#define assert(expr) \
+((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__))
+
class ButterFly {
private:
ButterFly() { }
@@ -29,4 +35,39 @@ class X{
subtest1();
return subtest2();
}
-}; \ No newline at end of file
+};
+
+typedef const int *Ty;
+extern
+Ty notNullArg(Ty cf) __attribute__((nonnull));
+typedef const void *CFTypeRef;
+extern Ty getTyVal();
+inline void radar13224271_callee(Ty def, Ty& result ) {
+ result = def;
+ // Clearly indicates that result cannot be 0 if def is not NULL.
+ assert( (result != 0) || (def == 0) );
+}
+void radar13224271_caller()
+{
+ Ty value;
+ radar13224271_callee(getTyVal(), value );
+ notNullArg(value); // no-warning
+}
+
+struct Foo {
+ int *ptr;
+ Foo(int *p) {
+ *p = 1; // no-warning
+ }
+};
+void idc(int *p3) {
+ if (p3)
+ ;
+}
+int *retNull() {
+ return 0;
+}
+void test(int *p1, int *p2) {
+ idc(p1);
+ Foo f(p1);
+} \ No newline at end of file
diff --git a/test/Analysis/inlining/inline-defensive-checks.m b/test/Analysis/inlining/inline-defensive-checks.m
index bafc812486..0404ee6df8 100644
--- a/test/Analysis/inlining/inline-defensive-checks.m
+++ b/test/Analysis/inlining/inline-defensive-checks.m
@@ -16,7 +16,6 @@ typedef struct objc_object {
-(id)retain;
@end
-// expected-no-diagnostics
// Check that inline defensive checks is triggered for null expressions
// within CompoundLiteralExpr.
typedef union {
@@ -44,3 +43,87 @@ dispatch_resume(dispatch_object_t object);
dispatch_resume(p); // no warning
}
@end
+
+// Test nil receiver suppression.
+// We only suppress on nil receiver if the nil value is directly causing the bug.
+@interface Foo {
+@public
+ int x;
+}
+- (Foo *)getFooPtr;
+@end
+
+Foo *retNil() {
+ return 0;
+}
+
+Foo *retInputOrNil(Foo *p) {
+ if (p)
+ return p;
+ return 0;
+}
+
+void idc(Foo *p) {
+ if (p)
+ ;
+}
+
+int testNilReceiver(Foo* fPtr) {
+ if (fPtr)
+ ;
+ // On a path where fPtr is nil, mem should be nil.
+ Foo *mem = [fPtr getFooPtr];
+ return mem->x; // expected-warning {{Access to instance variable 'x' results in a dereference of a null pointer}}
+}
+
+int suppressNilReceiverRetNullCond(Foo* fPtr) {
+ unsigned zero = 0;
+ fPtr = retInputOrNil(fPtr);
+ // On a path where fPtr is nzil, mem should be nil.
+ Foo *mem = [fPtr getFooPtr];
+ return mem->x;
+}
+
+int suppressNilReceiverRetNullCondCast(id fPtr) {
+ unsigned zero = 0;
+ fPtr = retInputOrNil(fPtr);
+ // On a path where fPtr is nzil, mem should be nil.
+ Foo *mem = ((id)([(Foo*)(fPtr) getFooPtr]));
+ return mem->x;
+}
+
+int dontSuppressNilReceiverRetNullCond(Foo* fPtr) {
+ unsigned zero = 0;