summaryrefslogtreecommitdiffstats
path: root/test/Analysis/cxx-uninitialized-object-unguarded-access.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/Analysis/cxx-uninitialized-object-unguarded-access.cpp')
-rw-r--r--test/Analysis/cxx-uninitialized-object-unguarded-access.cpp440
1 files changed, 440 insertions, 0 deletions
diff --git a/test/Analysis/cxx-uninitialized-object-unguarded-access.cpp b/test/Analysis/cxx-uninitialized-object-unguarded-access.cpp
new file mode 100644
index 0000000000..53e72e7c5f
--- /dev/null
+++ b/test/Analysis/cxx-uninitialized-object-unguarded-access.cpp
@@ -0,0 +1,440 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.UninitializedObject \
+// RUN: -analyzer-config optin.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \
+// RUN: -analyzer-config optin.cplusplus.UninitializedObject:IgnoreGuardedFields=true \
+// RUN: -std=c++11 -verify %s
+
+//===----------------------------------------------------------------------===//
+// Helper functions for tests.
+//===----------------------------------------------------------------------===//
+
+[[noreturn]] void halt();
+
+void assert(int b) {
+ if (!b)
+ halt();
+}
+
+int rand();
+
+//===----------------------------------------------------------------------===//
+// Tests for fields properly guarded by asserts.
+//===----------------------------------------------------------------------===//
+
+class NoUnguardedFieldsTest {
+public:
+ enum Kind {
+ V,
+ A
+ };
+
+private:
+ int Volume, Area;
+ Kind K;
+
+public:
+ NoUnguardedFieldsTest(Kind K) : K(K) {
+ switch (K) {
+ case V:
+ Volume = 0;
+ break;
+ case A:
+ Area = 0;
+ break;
+ }
+ }
+
+ void operator-() {
+ assert(K == Kind::A);
+ (void)Area;
+ }
+
+ void operator+() {
+ assert(K == Kind::V);
+ (void)Volume;
+ }
+};
+
+void fNoUnguardedFieldsTest() {
+ NoUnguardedFieldsTest T1(NoUnguardedFieldsTest::Kind::A);
+ NoUnguardedFieldsTest T2(NoUnguardedFieldsTest::Kind::V);
+}
+
+class NoUngardedFieldsNoReturnFuncCalledTest {
+public:
+ enum Kind {
+ V,
+ A
+ };
+
+private:
+ int Volume, Area;
+ Kind K;
+
+public:
+ NoUngardedFieldsNoReturnFuncCalledTest(Kind K) : K(K) {
+ switch (K) {
+ case V:
+ Volume = 0;
+ break;
+ case A:
+ Area = 0;
+ break;
+ }
+ }
+
+ void operator-() {
+ halt();
+ (void)Area;
+ }
+
+ void operator+() {
+ halt();
+ (void)Volume;
+ }
+};
+
+void fNoUngardedFieldsNoReturnFuncCalledTest() {
+ NoUngardedFieldsNoReturnFuncCalledTest
+ T1(NoUngardedFieldsNoReturnFuncCalledTest::Kind::A);
+ NoUngardedFieldsNoReturnFuncCalledTest
+ T2(NoUngardedFieldsNoReturnFuncCalledTest::Kind::V);
+}
+
+class NoUnguardedFieldsWithUndefMethodTest {
+public:
+ enum Kind {
+ V,
+ A
+ };
+
+private:
+ int Volume, Area;
+ Kind K;
+
+public:
+ NoUnguardedFieldsWithUndefMethodTest(Kind K) : K(K) {
+ switch (K) {
+ case V:
+ Volume = 0;
+ break;
+ case A:
+ Area = 0;
+ break;
+ }
+ }
+
+ void operator-() {
+ assert(K == Kind::A);
+ (void)Area;
+ }
+
+ void operator+() {
+ assert(K == Kind::V);
+ (void)Volume;
+ }
+
+ // We're checking method definitions for guards, so this is a no-crash test
+ // whether we handle methods without definitions.
+ void methodWithoutDefinition();
+};
+
+void fNoUnguardedFieldsWithUndefMethodTest() {
+ NoUnguardedFieldsWithUndefMethodTest
+ T1(NoUnguardedFieldsWithUndefMethodTest::Kind::A);
+ NoUnguardedFieldsWithUndefMethodTest
+ T2(NoUnguardedFieldsWithUndefMethodTest::Kind::V);
+}
+
+class UnguardedFieldThroughMethodTest {
+public:
+ enum Kind {
+ V,
+ A
+ };
+
+private:
+ int Volume, Area; // expected-note {{uninitialized field 'this->Volume'}}
+ Kind K;
+
+public:
+ UnguardedFieldThroughMethodTest(Kind K) : K(K) {
+ switch (K) {
+ case V:
+ Volume = 0;
+ break;
+ case A:
+ Area = 0; // expected-warning {{1 uninitialized field}}
+ break;
+ }
+ }
+
+ void operator-() {
+ assert(K == Kind::A);
+ (void)Area;
+ }
+
+ void operator+() {
+ (void)Volume;
+ }
+};
+
+void fUnguardedFieldThroughMethodTest() {
+ UnguardedFieldThroughMethodTest T1(UnguardedFieldThroughMethodTest::Kind::A);
+}
+
+class UnguardedPublicFieldsTest {
+public:
+ enum Kind {
+ V,
+ A
+ };
+
+public:
+ // Note that fields are public.
+ int Volume, Area; // expected-note {{uninitialized field 'this->Volume'}}
+ Kind K;
+
+public:
+ UnguardedPublicFieldsTest(Kind K) : K(K) {
+ switch (K) {
+ case V:
+ Volume = 0;
+ break;
+ case A:
+ Area = 0; // expected-warning {{1 uninitialized field}}
+ break;
+ }
+ }
+
+ void operator-() {
+ assert(K == Kind::A);
+ (void)Area;
+ }
+
+ void operator+() {
+ assert(K == Kind::V);
+ (void)Volume;
+ }
+};
+
+void fUnguardedPublicFieldsTest() {
+ UnguardedPublicFieldsTest T1(UnguardedPublicFieldsTest::Kind::A);
+}
+
+//===----------------------------------------------------------------------===//
+// Highlights of some false negatives due to syntactic checking.
+//===----------------------------------------------------------------------===//
+
+class UnguardedFalseNegativeTest1 {
+public:
+ enum Kind {
+ V,
+ A
+ };
+
+private:
+ int Volume, Area;
+ Kind K;
+
+public:
+ UnguardedFalseNegativeTest1(Kind K) : K(K) {
+ switch (K) {
+ case V:
+ Volume = 0;
+ break;
+ case A:
+ Area = 0;
+ break;
+ }
+ }
+
+ void operator-() {
+ if (rand())
+ assert(K == Kind::A);
+ (void)Area;
+ }
+
+ void operator+() {
+ if (rand())
+ assert(K == Kind::V);
+ (void)Volume;
+ }
+};
+
+void fUnguardedFalseNegativeTest1() {
+ UnguardedFalseNegativeTest1 T1(UnguardedFalseNegativeTest1::Kind::A);
+}
+
+class UnguardedFalseNegativeTest2 {
+public:
+ enum Kind {
+ V,
+ A
+ };
+
+private:
+ int Volume, Area;
+ Kind K;
+
+public:
+ UnguardedFalseNegativeTest2(Kind K) : K(K) {
+ switch (K) {
+ case V:
+ Volume = 0;
+ break;
+ case A:
+ Area = 0;
+ break;
+ }
+ }
+
+ void operator-() {
+ assert(rand());
+ (void)Area;
+ }
+
+ void operator+() {
+ assert(rand());
+ (void)Volume;
+ }
+};
+
+void fUnguardedFalseNegativeTest2() {
+ UnguardedFalseNegativeTest2 T1(UnguardedFalseNegativeTest2::Kind::A);
+}
+
+//===----------------------------------------------------------------------===//
+// Tests for other guards. These won't be as thorough, as other guards are
+// matched the same way as asserts, so if they are recognized, they are expected
+// to work as well as asserts do.
+//
+// None of these tests expect warnings, since the flag works correctly if these
+// fields are regarded properly guarded.
+//===----------------------------------------------------------------------===//
+
+class IfGuardedFieldsTest {
+public:
+ enum Kind {
+ V,
+ A
+ };
+
+private:
+ int Volume, Area;
+ Kind K;
+
+public:
+ IfGuardedFieldsTest(Kind K) : K(K) {
+ switch (K) {
+ case V:
+ Volume = 0;
+ break;
+ case A:
+ Area = 0;
+ break;
+ }
+ }
+
+ void operator-() {
+ if (K != Kind::A)
+ return;
+ (void)Area;
+ }
+
+ void operator+() {
+ if (K != Kind::V)
+ return;
+ (void)Volume;
+ }
+};
+
+void fIfGuardedFieldsTest() {
+ IfGuardedFieldsTest T1(IfGuardedFieldsTest::Kind::A);
+ IfGuardedFieldsTest T2(IfGuardedFieldsTest::Kind::V);
+}
+
+class SwitchGuardedFieldsTest {
+public:
+ enum Kind {
+ V,
+ A
+ };
+
+private:
+ int Volume, Area;
+ Kind K;
+
+public:
+ SwitchGuardedFieldsTest(Kind K) : K(K) {
+ switch (K) {
+ case V:
+ Volume = 0;
+ break;
+ case A:
+ Area = 0;
+ break;
+ }
+ }
+
+ int operator-() {
+ switch (K) {
+ case Kind::A:
+ return Area;
+ case Kind::V:
+ return -1;
+ }
+ }
+
+ int operator+() {
+ switch (K) {
+ case Kind::A:
+ return Area;
+ case Kind::V:
+ return -1;
+ }
+ }
+};
+
+void fSwitchGuardedFieldsTest() {
+ SwitchGuardedFieldsTest T1(SwitchGuardedFieldsTest::Kind::A);
+ SwitchGuardedFieldsTest T2(SwitchGuardedFieldsTest::Kind::V);
+}
+
+class ConditionalOperatorGuardedFieldsTest {
+public:
+ enum Kind {
+ V,
+ A
+ };
+
+private:
+ int Volume, Area;
+ Kind K;
+
+public:
+ ConditionalOperatorGuardedFieldsTest(Kind K) : K(K) {
+ switch (K) {
+ case V:
+ Volume = 0;
+ break;
+ case A:
+ Area = 0;
+ break;
+ }
+ }
+
+ int operator-() {
+ return K == Kind::A ? Area : -1;
+ }
+
+ int operator+() {
+ return K == Kind::V ? Volume : -1;
+ }
+};
+
+void fConditionalOperatorGuardedFieldsTest() {
+ ConditionalOperatorGuardedFieldsTest
+ T1(ConditionalOperatorGuardedFieldsTest::Kind::A);
+ ConditionalOperatorGuardedFieldsTest
+ T2(ConditionalOperatorGuardedFieldsTest::Kind::V);
+}