Add static analyzer transfer function support for __builtin_offsetof.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81820 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 8214199..0e08cd2 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -2430,10 +2430,15 @@
return;
}
- // FIXME: Just report "Unknown" for OffsetOf.
- case UnaryOperator::OffsetOf:
- Dst.Add(Pred);
+ case UnaryOperator::OffsetOf: {
+ const APSInt &IV = U->EvaluateAsInt(getContext());
+ assert(IV.getBitWidth() == getContext().getTypeSize(U->getType()));
+ assert(U->getType()->isIntegerType());
+ assert(IV.isSigned() == U->getType()->isSignedIntegerType());
+ SVal X = ValMgr.makeIntVal(IV);
+ MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X));
return;
+ }
case UnaryOperator::Plus: assert (!asLValue); // FALL-THROUGH.
case UnaryOperator::Extension: {
diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m
index 34a0953..189fc44 100644
--- a/test/Analysis/misc-ps.m
+++ b/test/Analysis/misc-ps.m
@@ -567,3 +567,45 @@
return self;
}
@end
+
+// Test reasoning of __builtin_offsetof;
+struct test_offsetof_A {
+ int x;
+ int y;
+};
+struct test_offsetof_B {
+ int w;
+ int z;
+};
+void test_offsetof_1() {
+ if (__builtin_offsetof(struct test_offsetof_A, x) ==
+ __builtin_offsetof(struct test_offsetof_B, w))
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+void test_offsetof_2() {
+ if (__builtin_offsetof(struct test_offsetof_A, y) ==
+ __builtin_offsetof(struct test_offsetof_B, z))
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+void test_offsetof_3() {
+ if (__builtin_offsetof(struct test_offsetof_A, y) -
+ __builtin_offsetof(struct test_offsetof_A, x)
+ ==
+ __builtin_offsetof(struct test_offsetof_B, z) -
+ __builtin_offsetof(struct test_offsetof_B, w))
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF; // no-warning
+}
+void test_offsetof_4() {
+ if (__builtin_offsetof(struct test_offsetof_A, y) ==
+ __builtin_offsetof(struct test_offsetof_B, w))
+ return;
+ int *p = 0;
+ *p = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}}
+}
+
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 9625514..397464a 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -1028,3 +1028,39 @@
}
@end
+//===----------------------------------------------------------------------===//
+// Test that leaks post-dominated by "panic" functions are not reported.
+//
+// <rdar://problem/5905851> do not report a leak when post-dominated by a call
+// to a noreturn or panic function
+//===----------------------------------------------------------------------===//
+
+void panic() __attribute__((noreturn));
+
+void test_panic_negative() {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}}
+}
+
+void test_panic_positive() {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // no-warning
+ panic();
+}
+
+void test_panic_neg_2(int x) {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // expected-warning{{leak}}
+ if (x)
+ panic();
+}
+
+void test_panic_pos_2(int x) {
+ signed z = 1;
+ CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &z); // no-warning
+ if (x)
+ panic();
+ if (!x)
+ panic();
+}
+