aboutsummaryrefslogtreecommitdiff
path: root/test/Analysis
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-06-21 14:00:56 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-06-21 14:00:56 +0000
commit2e645aa5697838f16ec570eb07c2bee7e13d0e0b (patch)
treea764184c2fc9486979b074250b013a0937ee64e5 /test/Analysis
parent798321d8eb5630cd4a8f490a4f25e32ef195fb07 (diff)
Notes
Diffstat (limited to 'test/Analysis')
-rw-r--r--test/Analysis/CFContainers.mm22
-rw-r--r--test/Analysis/designated-initializer.c41
-rw-r--r--test/Analysis/retain-release.m34
3 files changed, 97 insertions, 0 deletions
diff --git a/test/Analysis/CFContainers.mm b/test/Analysis/CFContainers.mm
index b01942310f7b2..f315bc9f045cb 100644
--- a/test/Analysis/CFContainers.mm
+++ b/test/Analysis/CFContainers.mm
@@ -19,6 +19,7 @@ typedef struct {
} CFArrayCallBacks;
typedef const struct __CFArray * CFArrayRef;
CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks);
+typedef struct __CFArray * CFMutableArrayRef;
typedef const struct __CFString * CFStringRef;
enum {
kCFNumberSInt8Type = 1,
@@ -202,3 +203,24 @@ void TestConst(CFArrayRef A, CFIndex sIndex, void* x[]) {
void TestNullArray() {
CFArrayGetValueAtIndex(0, 0);
}
+
+void ArrayRefMutableEscape(CFMutableArrayRef a);
+void ArrayRefEscape(CFArrayRef a);
+
+void TestCFMutableArrayRefEscapeViaMutableArgument(CFMutableArrayRef a) {
+ CFIndex aLen = CFArrayGetCount(a);
+ ArrayRefMutableEscape(a);
+
+ // ArrayRefMutableEscape could mutate a to make it have
+ // at least aLen + 1 elements, so do not report an error here.
+ CFArrayGetValueAtIndex(a, aLen);
+}
+
+void TestCFMutableArrayRefEscapeViaImmutableArgument(CFMutableArrayRef a) {
+ CFIndex aLen = CFArrayGetCount(a);
+ ArrayRefEscape(a);
+
+ // ArrayRefEscape is declared to take a CFArrayRef (i.e, an immutable array)
+ // so we assume it does not change the length of a.
+ CFArrayGetValueAtIndex(a, aLen); // expected-warning {{Index is out of bounds}}
+}
diff --git a/test/Analysis/designated-initializer.c b/test/Analysis/designated-initializer.c
new file mode 100644
index 0000000000000..b601f872571f0
--- /dev/null
+++ b/test/Analysis/designated-initializer.c
@@ -0,0 +1,41 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG %s 2>&1 \
+// RUN: | FileCheck %s
+
+struct Q { int a, b, c; };
+union UQ { struct Q q; };
+union UQ getUQ() {
+ union UQ u = { { 1, 2, 3 } };
+ return u;
+}
+
+void test() {
+ struct LUQ { union UQ uq; } var = { getUQ(), .uq.q.a = 100 };
+ struct Q s[] = {
+ [0] = (struct Q){1, 2},
+ [0].c = 3
+ };
+}
+
+// CHECK: void test()
+// CHECK: [B1]
+// CHECK: 1: getUQ
+// CHECK: 2: [B1.1] (ImplicitCastExpr, FunctionToPointerDecay, union UQ (*)())
+// CHECK: 3: [B1.2]()
+// CHECK: 4: 100
+// CHECK: 5: /*no init*/
+// CHECK: 6: /*no init*/
+// CHECK: 7: {[B1.4], [B1.5], [B1.6]}
+// CHECK: 8: {[B1.7]}
+// CHECK: 9: {/*base*/[B1.3], /*updater*/[B1.8]}
+// CHECK: 10: {[B1.3], .uq.q.a = [B1.4]}
+// CHECK: 11: struct LUQ var = {getUQ(), .uq.q.a = 100};
+// CHECK: 12: 1
+// CHECK: 13: 2
+// CHECK: 14: /*implicit*/(int)0
+// CHECK: 15: {[B1.12], [B1.13]}
+// CHECK: 18: /*no init*/
+// CHECK: 19: /*no init*/
+// CHECK: 20: 3
+// CHECK: 21: {[B1.18], [B1.19], [B1.20]}
+// CHECK: 22: {/*base*/[B1.17], /*updater*/[B1.21]}
+// CHECK: 24: struct Q s[] = {[0] = (struct Q){1, 2}, [0].c = 3};
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 6973f9bcd67df..1dbcda507c174 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -2153,6 +2153,40 @@ id returnNSNull() {
return [NSNull null]; // no-warning
}
+//===----------------------------------------------------------------------===//
+// cf_returns_[not_]retained on parameters
+//===----------------------------------------------------------------------===//
+
+void testCFReturnsNotRetained() {
+ extern void getViaParam(CFTypeRef * CF_RETURNS_NOT_RETAINED outObj);
+ CFTypeRef obj;
+ getViaParam(&obj);
+ CFRelease(obj); // // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
+void testCFReturnsNotRetainedAnnotated() {
+ extern void getViaParam2(CFTypeRef * __nonnull CF_RETURNS_NOT_RETAINED outObj);
+ CFTypeRef obj;
+ getViaParam2(&obj);
+ CFRelease(obj); // // expected-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
+void testCFReturnsRetained() {
+ extern int copyViaParam(CFTypeRef * CF_RETURNS_RETAINED outObj);
+ CFTypeRef obj;
+ copyViaParam(&obj);
+ CFRelease(obj);
+ CFRelease(obj); // // FIXME-warning {{Incorrect decrement of the reference count of an object that is not owned at this point by the caller}}
+}
+
+void testCFReturnsRetainedError() {
+ extern int copyViaParam(CFTypeRef * CF_RETURNS_RETAINED outObj);
+ CFTypeRef obj;
+ if (copyViaParam(&obj) == -42)
+ return; // no-warning
+ CFRelease(obj);
+}
+
// CHECK: <key>diagnostics</key>
// CHECK-NEXT: <array>
// CHECK-NEXT: <dict>