// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config ipa=inlining -verify %s void clang_analyzer_eval(bool); void clang_analyzer_checkInlined(bool); typedef __typeof__(sizeof(int)) size_t; extern "C" void *malloc(size_t); // This is the standard placement new. inline void* operator new(size_t, void* __p) throw() { return __p; } class A { public: int getZero() { return 0; } virtual int getNum() { return 0; } }; void test(A &a) { clang_analyzer_eval(a.getZero() == 0); // expected-warning{{TRUE}} clang_analyzer_eval(a.getNum() == 0); // expected-warning{{UNKNOWN}} A copy(a); clang_analyzer_eval(copy.getZero() == 0); // expected-warning{{TRUE}} clang_analyzer_eval(copy.getNum() == 0); // expected-warning{{TRUE}} } class One : public A { public: virtual int getNum() { return 1; } }; void testPathSensitivity(int x) { A a; One b; A *ptr; switch (x) { case 0: ptr = &a; break; case 1: ptr = &b; break; default: return; } // This should be true on both branches. clang_analyzer_eval(ptr->getNum() == x); // expected-warning {{TRUE}} } namespace PureVirtualParent { class Parent { public: virtual int pureVirtual() const = 0; int callVirtual() const { return pureVirtual(); } }; class Child : public Parent { public: virtual int pureVirtual() const { clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} return 42; } }; void testVirtual() { Child x; clang_analyzer_eval(x.pureVirtual() == 42); // expected-warning{{TRUE}} clang_analyzer_eval(x.callVirtual() == 42); // expected-warning{{TRUE}} } } namespace PR13569 { class Parent { protected: int m_parent; virtual int impl() const = 0; Parent() : m_parent(0) {} public: int interface() const { clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} return impl(); } }; class Child : public Parent { protected: virtual int impl() const { clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} return m_parent + m_child; } public: Child() : m_child(0) {} int m_child; }; void testVirtual() { Child x; x.m_child = 42; // Don't crash when inlining and devirtualizing. x.interface(); } class Grandchild : public Child {}; void testDevirtualizeToMiddle() { Grandchild x; x.m_child = 42; // Don't crash when inlining and devirtualizing. x.interface(); } } namespace PR13569_virtual { class Parent { protected: int m_parent; virtual int impl() const = 0; Parent() : m_parent(0) {} public: int interface() const { clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} return impl(); } }; class Child : virtual public Parent { protected: virtual int impl() const { clang_analyzer_checkInlined(true); // expected-warning{{TRUE}} return m_parent + m_child; } public: Child() : m_child(0) {} int m_child; }; void testVirtual() { Child x; x.m_child = 42; // Don't crash when inlining and devirtualizing. x.interface(); } class Grandchild : virtual public Child {}; void testDevirtualizeToMiddle() { Grandchild x; x.m_child = 42; // Don't crash when inlining and devirtualizing. x.interface(); } } namespace Invalidation { struct X { void touch(int &x) const { x = 0; } void touch2(int &x) const; virtual void touchV(int &x) const { x = 0; } virtual void touchV2(int &x) const; int test() const { // We were accidentally not invalidating under inlining // at one point for virtual methods with visible definitions. int a, b, c, d; touch(a); touch2(b); touchV(c); touchV2(d); return a + b + c + d; // no-warning } }; } namespace DefaultArgs { int takesDefaultArgs(int i = 42) { return -i; } void testFunction() { clang_analyzer_eval(takesDefaultArgs(1) == -1); // expected-warning{{TRUE}} clang_analyzer_eval(takesDefaultArgs() == -42); // expected-warning{{TRUE}} } class Secret { public: static const int value = 40 + 2; int get(int i = value) { return i; } }; void testMethod() { Secret obj; clang_analyzer_eval(obj.get(1) == 1); // expected-warning{{TRUE}} clang_analyzer_eval(obj.get() == 42); // expected-warning{{TRUE}} clang_analyzer_eval(Secret::value == 42); // expected-warning{{TRUE}} } enum ABC { A = 0, B = 1, C = 2 }; int enumUser(ABC input = B) { return static_cast<int>(input); } void testEnum() { clang_analyzer_eval(enumUser(C) == 2); // expected-warning{{TRUE}} clang_analyzer_eval(enumUser() == 1); // expected-warning{{TRUE}} } int exprUser(int input = 2 * 4) { return input; } int complicatedExprUser(int input = 2 * Secret::value) { return input; } void testExprs() { clang_analyzer_eval(exprUser(1) == 1); // expected-warning{{TRUE}} clang_analyzer_eval(exprUser() == 8); // expected-warning{{TRUE}} clang_analyzer_eval(complicatedExprUser(1) == 1); // expected-warning{{TRUE}} clang_analyzer_eval(complicatedExprUser() == 84); // expected-warning{{TRUE}} } int defaultReference(const int &input = 42) { return -input; } int defaultReferenceZero(const int &input = 0) { return -input; } void testReference() { clang_analyzer_eval(defaultReference(1) == -1); // expected-warning{{TRUE}} clang_analyzer_eval(defaultReference() == -42); // expected-warning{{TRUE}} clang_analyzer_eval(defaultReferenceZero(1) == -1); // expected-warning{{TRUE}} clang_analyzer_eval(defaultReferenceZero() == 0); // expected-warning{{TRUE}} } double defaultFloatReference(const double &i = 42) { return -i; } double defaultFloatReferenceZero(const double &i = 0) { return -i; } void testFloatReference() { clang_analyzer_eval(defaultFloatReference(1) == -1); // expected-warning{{UNKNOWN}} clang_analyzer_eval(defaultFloatReference() == -42); // expected-warning{{UNKNOWN}} clang_analyzer_eval(defaultFloatReferenceZero(1) == -1); // expected-warning{{UNKNOWN}} clang_analyzer_eval(defaultFloatReferenceZero() == 0); // expected-warning{{UNKNOWN}} } char defaultString(const char *s = "abc") { return s[1]; } void testString() { clang_analyzer_eval(defaultString("xyz") == 'y'); // expected-warning{{TRUE}} clang_analyzer_eval(defaultString() == 'b'); // expected-warning{{TRUE}} } } namespace OperatorNew { class IntWrapper { public: int value; IntWrapper(int input) : value(input) { // We don't want this constructor to be inlined unless we can actually // use the proper region for operator new. // See PR12014 and <rdar://problem/12180598>. clang_analyzer_checkInlined(false); // no-warning } }; void test() { IntWrapper *obj = new IntWrapper(42); // should be TRUE clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}} delete obj; } void testPlacement() { IntWrapper *obj = static_cast<IntWrapper *>(malloc(sizeof(IntWrapper))); IntWrapper *alias = new (obj) IntWrapper(42); clang_analyzer_eval(alias == obj); // expected-warning{{TRUE}} // should be TRUE clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}} } } namespace VirtualWithSisterCasts { // This entire set of tests exercises casts from sister classes and // from classes outside the hierarchy, which can very much confuse // code that uses DynamicTypeInfo or needs to construct CXXBaseObjectRegions. // These examples used to cause crashes in +Asserts builds. struct Parent { virtual int foo(); int x; }; struct A : Parent { virtual int foo() { return 42; } }; struct B : Parent { virtual int foo(); }; struct Grandchild : public A {}; struct Unrelated {}; void testDowncast(Parent *b) { A *a = (A *)(void *)b; clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}} a->x = 42; clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}} } void testRelated(B *b) { A *a = (A *)(void *)b; clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}} a->x = 42; clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}} } void testUnrelated(Unrelated *b) { A *a = (A *)(void *)b; clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}} a->x = 42; clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}} } void testCastViaNew(B *b) { Grandchild *g = new (b) Grandchild(); clang_analyzer_eval(g->foo() == 42); // expected-warning{{TRUE}} g->x = 42; clang_analyzer_eval(g->x == 42); // expected-warning{{TRUE}} } } namespace QualifiedCalls { void test(One *object) { // This uses the One class from the top of the file. clang_analyzer_eval(object->getNum() == 1); // expected-warning{{UNKNOWN}} clang_analyzer_eval(object->One::getNum() == 1); // expected-warning{{TRUE}} clang_analyzer_eval(object->A::getNum() == 0); // expected-warning{{TRUE}} // getZero is non-virtual. clang_analyzer_eval(object->getZero() == 0); // expected-warning{{TRUE}} clang_analyzer_eval(object->One::getZero() == 0); // expected-warning{{TRUE}} clang_analyzer_eval(object->A::getZero() == 0); // expected-warning{{TRUE}} } } namespace rdar12409977 { struct Base { int x; }; struct Parent : public Base { virtual Parent *vGetThis(); Parent *getThis() { return vGetThis(); } }; struct Child : public Parent { virtual Child *vGetThis() { return this; } }; void test() { Child obj; obj.x = 42; // Originally, calling a devirtualized method with a covariant return type // caused a crash because the return value had the wrong type. When we then // go to layer a CXXBaseObjectRegion on it, the base isn't a direct base of // the object region and we get an assertion failure. clang_analyzer_eval(obj.getThis()->x == 42); // expected-warning{{TRUE}} } } namespace bug16307 { void one_argument(int a) { } void call_with_less() { reinterpret_cast<void (*)()>(one_argument)(); // expected-warning{{Function taking 1 argument}} } }