forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			254 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			254 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=none -verify %s
 | 
						|
 | 
						|
void clang_analyzer_eval(bool);
 | 
						|
 | 
						|
class A {
 | 
						|
public:
 | 
						|
    virtual void f(){};
 | 
						|
 | 
						|
};
 | 
						|
class B : public A{
 | 
						|
public:
 | 
						|
  int m;
 | 
						|
};
 | 
						|
class C : public A{};
 | 
						|
 | 
						|
class BB: public B{};
 | 
						|
 | 
						|
// A lot of the tests below have the if statement in them, which forces the
 | 
						|
// analyzer to explore both path - when the result is 0 and not. This makes
 | 
						|
// sure that we definitely know that the result is non-0 (as the result of
 | 
						|
// the cast).
 | 
						|
int testDynCastFromRadar() {
 | 
						|
    B aa;
 | 
						|
    A *a = &aa;
 | 
						|
    const int* res = 0;
 | 
						|
    B *b = dynamic_cast<B*>(a);
 | 
						|
    static const int i = 5;
 | 
						|
    if(b) {
 | 
						|
        res = &i;
 | 
						|
    } else {
 | 
						|
        res = 0;
 | 
						|
    }
 | 
						|
    return *res; // no warning
 | 
						|
}
 | 
						|
 | 
						|
int testBaseToBase1() {
 | 
						|
  B b;
 | 
						|
  B *pb = &b;
 | 
						|
  B *pbb = dynamic_cast<B*>(pb);
 | 
						|
  const int* res = 0;
 | 
						|
  static const int i = 5;
 | 
						|
  if (pbb) {
 | 
						|
      res = &i;
 | 
						|
  } else {
 | 
						|
      res = 0;
 | 
						|
  }
 | 
						|
  return *res; // no warning
 | 
						|
}
 | 
						|
 | 
						|
int testMultipleLevelsOfSubclassing1() {
 | 
						|
  BB bb;
 | 
						|
  B *pb = &bb;
 | 
						|
  A *pa = pb;
 | 
						|
  B *b = dynamic_cast<B*>(pa);
 | 
						|
  const int* res = 0;
 | 
						|
  static const int i = 5;
 | 
						|
  if (b) {
 | 
						|
      res = &i;
 | 
						|
  } else {
 | 
						|
      res = 0;
 | 
						|
  }
 | 
						|
  return *res; // no warning
 | 
						|
}
 | 
						|
 | 
						|
int testMultipleLevelsOfSubclassing2() {
 | 
						|
  BB bb;
 | 
						|
  A *pbb = &bb;
 | 
						|
  B *b = dynamic_cast<B*>(pbb);
 | 
						|
  BB *s = dynamic_cast<BB*>(b);
 | 
						|
  const int* res = 0;
 | 
						|
  static const int i = 5;
 | 
						|
  if (s) {
 | 
						|
      res = &i;
 | 
						|
  } else {
 | 
						|
      res = 0;
 | 
						|
  }
 | 
						|
  return *res; // no warning
 | 
						|
}
 | 
						|
 | 
						|
int testMultipleLevelsOfSubclassing3() {
 | 
						|
  BB bb;
 | 
						|
  A *pbb = &bb;
 | 
						|
  B *b = dynamic_cast<B*>(pbb);
 | 
						|
  return b->m; // no warning
 | 
						|
}
 | 
						|
 | 
						|
int testLHS() {
 | 
						|
    B aa;
 | 
						|
    A *a = &aa;
 | 
						|
    return (dynamic_cast<B*>(a))->m;
 | 
						|
}
 | 
						|
 | 
						|
int testLHS2() {
 | 
						|
    B aa;
 | 
						|
    A *a = &aa;
 | 
						|
    return (*dynamic_cast<B*>(a)).m;
 | 
						|
}
 | 
						|
 | 
						|
int testDynCastUnknown2(class A *a) {
 | 
						|
  B *b = dynamic_cast<B*>(a);
 | 
						|
  return b->m; // no warning
 | 
						|
}
 | 
						|
 | 
						|
int testDynCastUnknown(class A *a) {
 | 
						|
  B *b = dynamic_cast<B*>(a);
 | 
						|
  const int* res = 0;
 | 
						|
  static const int i = 5;
 | 
						|
  if (b) {
 | 
						|
    res = &i;
 | 
						|
  } else {
 | 
						|
    res = 0;
 | 
						|
  }
 | 
						|
  return *res; // expected-warning {{Dereference of null pointer}}
 | 
						|
}
 | 
						|
 | 
						|
int testDynCastFail2() {
 | 
						|
  C c;
 | 
						|
  A *pa = &c;
 | 
						|
  B *b = dynamic_cast<B*>(pa);
 | 
						|
  return b->m; // expected-warning {{dereference of a null pointer}}
 | 
						|
}
 | 
						|
 | 
						|
int testLHSFail() {
 | 
						|
    C c;
 | 
						|
    A *a = &c;
 | 
						|
    return (*dynamic_cast<B*>(a)).m; // expected-warning {{Dereference of null pointer}}
 | 
						|
}
 | 
						|
 | 
						|
int testBaseToDerivedFail() {
 | 
						|
  A a;
 | 
						|
  B *b = dynamic_cast<B*>(&a);
 | 
						|
  return b->m; // expected-warning {{dereference of a null pointer}}
 | 
						|
}
 | 
						|
 | 
						|
int testConstZeroFail() {
 | 
						|
  B *b = dynamic_cast<B*>((A *)0);
 | 
						|
  return b->m; // expected-warning {{dereference of a null pointer}}
 | 
						|
}
 | 
						|
 | 
						|
int testConstZeroFail2() {
 | 
						|
  A *a = 0;
 | 
						|
  B *b = dynamic_cast<B*>(a);
 | 
						|
  return b->m; // expected-warning {{dereference of a null pointer}}
 | 
						|
}
 | 
						|
 | 
						|
int testUpcast() {
 | 
						|
  B b;
 | 
						|
  A *a = dynamic_cast<A*>(&b);
 | 
						|
  const int* res = 0;
 | 
						|
  static const int i = 5;
 | 
						|
  if (a) {
 | 
						|
      res = &i;
 | 
						|
  } else {
 | 
						|
      res = 0;
 | 
						|
  }
 | 
						|
  return *res; // no warning
 | 
						|
}
 | 
						|
 | 
						|
int testCastToVoidStar() {
 | 
						|
  A a;
 | 
						|
  void *b = dynamic_cast<void*>(&a);
 | 
						|
  const int* res = 0;
 | 
						|
  static const int i = 5;
 | 
						|
  if (b) {
 | 
						|
      res = &i;
 | 
						|
  } else {
 | 
						|
      res = 0;
 | 
						|
  }
 | 
						|
  return *res; // no warning
 | 
						|
}
 | 
						|
 | 
						|
int testReferenceSuccessfulCast() {
 | 
						|
  B rb;
 | 
						|
  B &b = dynamic_cast<B&>(rb);
 | 
						|
  int *x = 0;
 | 
						|
  return *x; // expected-warning {{Dereference of null pointer}}
 | 
						|
}
 | 
						|
 | 
						|
int testReferenceFailedCast() {
 | 
						|
  A a;
 | 
						|
  B &b = dynamic_cast<B&>(a);
 | 
						|
  int *x = 0;
 | 
						|
  return *x; // no warning (An exception is thrown by the cast.)
 | 
						|
}
 | 
						|
 | 
						|
// Here we allow any outcome of the cast and this is good because there is a
 | 
						|
// situation where this will fail. So if the user has written the code in this
 | 
						|
// way, we assume they expect the cast to succeed.
 | 
						|
// Note, this might need special handling if we track types of symbolic casts
 | 
						|
// and use them for dynamic_cast handling.
 | 
						|
int testDynCastMostLikelyWillFail(C *c) {
 | 
						|
  B *b = 0;
 | 
						|
  b = dynamic_cast<B*>(c);
 | 
						|
  const int* res = 0;
 | 
						|
  static const int i = 5;
 | 
						|
  if (b) {
 | 
						|
      res = &i;
 | 
						|
  } else {
 | 
						|
      res = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  // Note: IPA is turned off for this test because the code below shows how the
 | 
						|
  // dynamic_cast could succeed.
 | 
						|
  return *res; // expected-warning{{Dereference of null pointer}}
 | 
						|
}
 | 
						|
 | 
						|
class M : public B, public C {};
 | 
						|
void callTestDynCastMostLikelyWillFail() {
 | 
						|
  M m;
 | 
						|
  testDynCastMostLikelyWillFail(&m);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void testDynCastToMiddleClass () {
 | 
						|
  class BBB : public BB {};
 | 
						|
  BBB obj;
 | 
						|
  A &ref = obj;
 | 
						|
 | 
						|
  // These didn't always correctly layer base regions.
 | 
						|
  B *ptr = dynamic_cast<B*>(&ref);
 | 
						|
  clang_analyzer_eval(ptr != 0); // expected-warning{{TRUE}}
 | 
						|
 | 
						|
  // This is actually statically resolved to be a DerivedToBase cast.
 | 
						|
  ptr = dynamic_cast<B*>(&obj);
 | 
						|
  clang_analyzer_eval(ptr != 0); // expected-warning{{TRUE}}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// -----------------------------
 | 
						|
// False positives/negatives.
 | 
						|
// -----------------------------
 | 
						|
 | 
						|
// Due to symbolic regions not being typed.
 | 
						|
int testDynCastFalsePositive(BB *c) {
 | 
						|
  B *b = 0;
 | 
						|
  b = dynamic_cast<B*>(c);
 | 
						|
  const int* res = 0;
 | 
						|
  static const int i = 5;
 | 
						|
  if (b) {
 | 
						|
      res = &i;
 | 
						|
  } else {
 | 
						|
      res = 0;
 | 
						|
  }
 | 
						|
  return *res; // expected-warning{{Dereference of null pointer}}
 | 
						|
}
 | 
						|
 | 
						|
// Does not work when we new an object.
 | 
						|
int testDynCastFail3() {
 | 
						|
  A *a = new A();
 | 
						|
  B *b = dynamic_cast<B*>(a);
 | 
						|
  return b->m;
 | 
						|
}
 | 
						|
 |