// RUN: %clang_analyze_cc1 -triple i386-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions -Wno-tautological-undefined-compare // RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin9 -analyzer-checker=core,alpha.core,debug.ExprInspection -analyzer-store=region -verify -fblocks -analyzer-opt-analyze-nested-blocks %s -fexceptions -fcxx-exceptions -Wno-tautological-undefined-compare void clang_analyzer_warnIfReached(); // Test basic handling of references. char &test1_aux(); char *test1() { return &test1_aux(); } // Test test1_aux() evaluates to char &. char test1_as_rvalue() { return test1_aux(); } // Test passing a value as a reference. The 'const' in test2_aux() adds // an ImplicitCastExpr, which is evaluated as an lvalue. int test2_aux(const int &n); int test2(int n) { return test2_aux(n); } int test2_b_aux(const short &n); int test2_b(int n) { return test2_b_aux(n); } // Test getting the lvalue of a derived and converting it to a base. This // previously crashed. class Test3_Base {}; class Test3_Derived : public Test3_Base {}; int test3_aux(Test3_Base &x); int test3(Test3_Derived x) { return test3_aux(x); } //===---------------------------------------------------------------------===// // Test CFG support for C++ condition variables. //===---------------------------------------------------------------------===// int test_init_in_condition_aux(); int test_init_in_condition() { if (int x = test_init_in_condition_aux()) { // no-warning return 1; } return 0; } int test_init_in_condition_switch() { switch (int x = test_init_in_condition_aux()) { // no-warning case 1: return 0; case 2: if (x == 2) return 0; else { clang_analyzer_warnIfReached(); // unreachable } default: break; } return 0; } int test_init_in_condition_while() { int z = 0; while (int x = ++z) { // no-warning if (x == 2) break; } if (z == 2) return 0; clang_analyzer_warnIfReached(); // unreachable return 0; } int test_init_in_condition_for() { int z = 0; for (int x = 0; int y = ++z; ++x) { if (x == y) // no-warning break; } if (z == 1) return 0; clang_analyzer_warnIfReached(); // unreachable return 0; } //===---------------------------------------------------------------------===// // Test handling of 'this' pointer. //===---------------------------------------------------------------------===// class TestHandleThis { int x; TestHandleThis(); int foo(); int null_deref_negative(); int null_deref_positive(); }; int TestHandleThis::foo() { // Assume that 'x' is initialized. return x + 1; // no-warning } int TestHandleThis::null_deref_negative() { x = 10; if (x == 10) { return 1; } clang_analyzer_warnIfReached(); // unreachable return 0; } int TestHandleThis::null_deref_positive() { x = 10; if (x == 9) { return 1; } clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} return 0; } // PR 7675 - passing literals by-reference void pr7675(const double &a); void pr7675(const int &a); void pr7675(const char &a); void pr7675_i(const _Complex double &a); void pr7675_test() { pr7675(10.0); pr7675(10); pr7675('c'); pr7675_i(4.0j); // Add check to ensure we are analyzing the code up to this point. clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } // - CFGBuilder should handle temporaries. struct R8375510 { R8375510(); ~R8375510(); R8375510 operator++(int); }; int r8375510(R8375510 x, R8375510 y) { for (; ; x++) { } } // PR8419 -- this used to crash. class String8419 { public: char& get(int n); char& operator[](int n); }; char& get8419(); void Test8419() { String8419 s; ++(s.get(0)); get8419()--; // used to crash --s[0]; // used to crash s[0] &= 1; // used to crash s[0]++; // used to crash } // PR8426 -- this used to crash. void Use(void* to); template class Foo { ~Foo(); struct Bar; Bar* bar_; }; template Foo::~Foo() { Use(bar_); T::DoSomething(); bar_->Work(); } // PR8427 -- this used to crash. class Dummy {}; bool operator==(Dummy, int); template class Foo2 { bool Bar(); }; template bool Foo2::Bar() { return 0 == T(); } // PR8433 -- this used to crash. template class Foo3 { public: void Bar(); void Baz(); T value_; }; template void Foo3::Bar() { Baz(); value_(); } //===---------------------------------------------------------------------===// // Handle misc. C++ constructs. //===---------------------------------------------------------------------===// namespace fum { int i = 3; }; void test_namespace() { // Previously triggered a crash. using namespace fum; int x = i; } // Test handling methods that accept references as parameters, and that // variables are properly invalidated. class RDar9203355 { bool foo(unsigned valA, long long &result) const; bool foo(unsigned valA, int &result) const; }; bool RDar9203355::foo(unsigned valA, int &result) const { long long val; if (foo(valA, val) || (int)val != val) // no-warning return true; result = val; // no-warning return false; } // Test handling of new[]. void rdar9212512() { int *x = new int[10]; for (unsigned i = 0 ; i < 2 ; ++i) { // This previously triggered an uninitialized values warning. x[i] = 1; // no-warning } } // Test basic support for dynamic_cast<>. struct Rdar9212495_C { virtual void bar() const; }; class Rdar9212495_B : public Rdar9212495_C {}; class Rdar9212495_A : public Rdar9212495_B {}; const Rdar9212495_A& rdar9212495(const Rdar9212495_C* ptr) { const Rdar9212495_A& val = dynamic_cast(*ptr); // This is not valid C++; dynamic_cast with a reference type will throw an // exception if the pointer does not match the expected type. However, our // implementation of dynamic_cast will pass through a null pointer...or a // "null reference"! So this branch is actually possible. if (&val == 0) { val.bar(); // expected-warning{{Called C++ object pointer is null}} } return val; } const Rdar9212495_A* rdar9212495_ptr(const Rdar9212495_C* ptr) { const Rdar9212495_A* val = dynamic_cast(ptr); if (val == 0) { val->bar(); // expected-warning{{Called C++ object pointer is null}} } return val; } // Test constructors invalidating arguments. Previously this raised // an uninitialized value warning. extern "C" void __attribute__((noreturn)) PR9645_exit(int i); class PR9645_SideEffect { public: PR9645_SideEffect(int *pi); // caches pi in i_ void Read(int *pi); // copies *pi into *i_ private: int *i_; }; void PR9645() { int i; PR9645_SideEffect se(&i); int j = 1; se.Read(&j); // this has a side-effect of initializing i. PR9645_exit(i); // no-warning } PR9645_SideEffect::PR9645_SideEffect(int *pi) : i_(pi) {} void PR9645_SideEffect::Read(int *pi) { *i_ = *pi; } // Invalidate fields during C++ method calls. class RDar9267815 { int x; void test(); void test_pos(); void test2(); void invalidate(); }; void RDar9267815::test_pos() { if (x == 42) return; clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } void RDar9267815::test() { if (x == 42) return; if (x == 42) clang_analyzer_warnIfReached(); // no-warning } void RDar9267815::test2() { if (x == 42) return; invalidate(); if (x == 42) clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} } // Test reference parameters. void test_ref_double_aux(double &Value); float test_ref_double() { double dVal; test_ref_double_aux(dVal); // This previously warned because 'dVal' was thought to be uninitialized. float Val = (float)dVal; // no-warning return Val; } // Test invalidation of class fields. class TestInvalidateClass { public: int x; }; void test_invalidate_class_aux(TestInvalidateClass &x); int test_invalidate_class() { TestInvalidateClass y; test_invalidate_class_aux(y); return y.x; // no-warning } // Test correct pointer arithmetic using 'p--'. This is to warn that we // were loading beyond the written characters in buf. char *RDar9269695(char *dst, unsigned int n) { char buff[40], *p; p = buff; do *p++ = '0' + n % 10; while (n /= 10); do *dst++ = *--p; // no-warning while (p != buff); return dst; } // Test that we invalidate byref arguments passed to constructors. class TestInvalidateInCtor { public: TestInvalidateInCtor(unsigned &x); }; unsigned test_invalidate_in_ctor() { unsigned x; TestInvalidateInCtor foo(x); return x; // no-warning } unsigned test_invalidate_in_ctor_new() { unsigned x; delete (new TestInvalidateInCtor(x)); return x; // no-warning } // Test assigning into a symbolic offset. struct TestAssignIntoSymbolicOffset { int **stuff[100]; void test(int x, int y); }; void TestAssignIntoSymbolicOffset::test(int x, int y) { x--; if (x > 8 || x < 0) return; if (stuff[x]) return; if (!stuff[x]) { stuff[x] = new int*[y+1]; // Previously triggered a null dereference. stuff[x][y] = 0; // no-warning } } // Test loads from static fields. This previously triggered an uninitialized // value warning. class ClassWithStatic { public: static const unsigned value = 1; }; int rdar9948787_negative() { ClassWithStatic classWithStatic; unsigned value = classWithStatic.value; if (value == 1) return 1; clang_analyzer_warnIfReached(); // no-warning return 0; } int rdar9948787_positive() { ClassWithStatic classWithStatic; unsigned value = classWithStatic.value; if (value == 0) return 1; clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} return 0; } // Regression test against global constants and switches. enum rdar10202899_ValT { rdar10202899_ValTA, rdar10202899_ValTB, rdar10202899_ValTC }; const rdar10202899_ValT val = rdar10202899_ValTA; void rdar10202899_test1() { switch (val) { case rdar10202899_ValTA: {} }; } void rdar10202899_test2() { if (val == rdar10202899_ValTA) return; clang_analyzer_warnIfReached(); // no-warning } void rdar10202899_test3() { switch (val) { case rdar10202899_ValTA: return; default: ; }; clang_analyzer_warnIfReached(); // no-warning } // This used to crash the analyzer because of the unnamed bitfield. void PR11249() { struct { char f1:4; char :4; char f2[1]; char f3; } V = { 1, {2}, 3 }; if (V.f1 != 1) clang_analyzer_warnIfReached(); // no-warning if (V.f2[0] != 2) clang_analyzer_warnIfReached(); // no-warning if (V.f3 != 3) clang_analyzer_warnIfReached(); // no-warning } // Handle doing a load from the memory associated with the code for // a function. extern double nan( const char * ); double PR11450() { double NaN = *(double*) nan; return NaN; } // Test that 'this' is assumed non-null upon analyzing the entry to a "top-level" // function (i.e., when not analyzing from a specific caller). struct TestNullThis { int field; void test(); }; void TestNullThis::test() { int *p = &field; if (p) return; field = 2; // no-warning } // Test handling of 'catch' exception variables, and not warning // about uninitialized values. enum MyEnum { MyEnumValue }; MyEnum rdar10892489() { try { throw MyEnumValue; } catch (MyEnum e) { return e; // no-warning } return MyEnumValue; } MyEnum rdar10892489_positive() { try { throw MyEnumValue; } catch (MyEnum e) { int *p = 0; // FALSE NEGATIVE *p = 0xDEADBEEF; // {{null}} return e; } return MyEnumValue; } // Test handling of catch with no condition variable. void PR11545() { try { throw; } catch (...) { } } void PR11545_positive() { try { throw; } catch (...) { int *p = 0; // FALSE NEGATIVE *p = 0xDEADBEEF; // {{null}} } } // Test handling taking the address of a field. While the analyzer // currently doesn't do anything intelligent here, this previously // resulted in a crash. class PR11146 { public: struct Entry; void baz(); }; struct PR11146::Entry { int x; }; void PR11146::baz() { (void) &Entry::x; } // Test symbolicating a reference. In this example, the // analyzer (originally) didn't know how to handle x[index - index2], // returning an UnknownVal. The conjured symbol wasn't a location, // and would result in a crash. void rdar10924675(unsigned short x[], int index, int index2) { unsigned short &y = x[index - index2]; if (y == 0) return; } // Test handling CXXScalarValueInitExprs. void rdar11401827() { int x = int(); if (!x) { clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}} ; // Suppress warning that both branches are identical } else { clang_analyzer_warnIfReached(); // no-warning } } //===---------------------------------------------------------------------===// // Handle inlining of C++ method calls. //===---------------------------------------------------------------------===// struct A { int *p; void foo(int *q) { p = q; } void bar() { *p = 0; // expected-warning {{null pointer}} } }; void test_inline() { A a; a.foo(0); a.bar(); } void test_alloca_in_a_recursive_function(int p1) { __builtin_alloca (p1); test_alloca_in_a_recursive_function(1); test_alloca_in_a_recursive_function(2); } //===---------------------------------------------------------------------===// // Random tests. //===---------------------------------------------------------------------===// // Tests assigning using a C-style initializer to a struct // variable whose sub-field is also a struct. This currently // results in a CXXTempObjectRegion being created, but not // properly handled. For now, we just ignore that value // to avoid a crash (). struct RDar12753384_ClassA { unsigned z; }; struct RDar12753384_ClassB { unsigned x; RDar12753384_ClassA y[ 8 ] ; }; unsigned RDar12753384() { RDar12753384_ClassB w = { 0x00 }; RDar12753384_ClassA y[8]; return w.x; } // This testcase tests whether we treat the anonymous union and union // the same way. This previously resulted in a "return of stack address" // warning because the anonymous union resulting in a temporary object // getting put into the initializer. We still aren't handling this correctly, // but now if a temporary object appears in an initializer we just ignore it. // Fixes . struct Rdar12755044_foo { struct Rdar12755044_bar { union baz { int i; }; } aBar; }; struct Rdar12755044_foo_anon { struct Rdar12755044_bar { union { int i; }; } aBar; }; const Rdar12755044_foo_anon *radar12755044_anon() { static const Rdar12755044_foo_anon Rdar12755044_foo_list[] = { { { } } }; return Rdar12755044_foo_list; // no-warning } const Rdar12755044_foo *radar12755044() { static const Rdar12755044_foo Rdar12755044_foo_list[] = { { { } } }; return Rdar12755044_foo_list; // no-warning } // Test the correct handling of integer to bool conversions. Previously // this resulted in a false positive because integers were being truncated // and not tested for non-zero. void rdar12759044() { int flag = 512; if (!(flag & 512)) { clang_analyzer_warnIfReached(); // no-warning } } // The analyzer currently does not model complex types. Test that the load // from 'x' is not flagged as being uninitialized. typedef __complex__ float _ComplexT; void rdar12964481(_ComplexT *y) { _ComplexT x; __real__ x = 1.0; __imag__ x = 1.0; *y *= x; // no-warning } void rdar12964481_b(_ComplexT *y) { _ComplexT x; // Eventually this should be a warning. *y *= x; // no-warning } // Test case for PR 12921. This previously produced // a bogus warning. static const int pr12921_arr[] = { 0, 1 }; static const int pr12921_arrcount = sizeof(pr12921_arr)/sizeof(int); int pr12921(int argc, char **argv) { int i, retval; for (i = 0; i < pr12921_arrcount; i++) { if (argc == i) { retval = i; break; } } // No match if (i == pr12921_arrcount) return 66; return pr12921_arr[retval]; }