forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			444 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			444 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config ipa=inlining -analyzer-config c++-allocator-inlining=true -verify -analyzer-config eagerly-assume=false %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()
 | 
						|
{
 | 
						|
  clang_analyzer_checkInlined(true);// expected-warning{{TRUE}}
 | 
						|
  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}}
 | 
						|
  }
 | 
						|
 | 
						|
  const void * const void_string = "abc";
 | 
						|
 | 
						|
  void testBitcastedString() {
 | 
						|
    clang_analyzer_eval(0 != void_string); // expected-warning{{TRUE}}
 | 
						|
    clang_analyzer_eval('b' == ((char *)void_string)[1]); // expected-warning{{TRUE}}
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
namespace OperatorNew {
 | 
						|
  class IntWrapper {
 | 
						|
  public:
 | 
						|
    int value;
 | 
						|
 | 
						|
    IntWrapper(int input) : value(input) {
 | 
						|
      clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
 | 
						|
    }
 | 
						|
  };
 | 
						|
 | 
						|
  void test() {
 | 
						|
    IntWrapper *obj = new IntWrapper(42);
 | 
						|
    clang_analyzer_eval(obj->value == 42); // expected-warning{{TRUE}}
 | 
						|
    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}}
 | 
						|
 | 
						|
    clang_analyzer_eval(obj->value == 42); // expected-warning{{TRUE}}
 | 
						|
    // Because malloc() was never free()d:
 | 
						|
    // expected-warning@-2{{Potential leak of memory pointed to by 'alias'}}
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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 is called with fewer (0)}}
 | 
						|
  }
 | 
						|
}
 |