Home | History | Annotate | Download | only in Analysis
      1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config ipa=inlining -analyzer-config c++-allocator-inlining=true -verify %s
      2 
      3 void clang_analyzer_eval(bool);
      4 void clang_analyzer_checkInlined(bool);
      5 
      6 typedef __typeof__(sizeof(int)) size_t;
      7 extern "C" void *malloc(size_t);
      8 
      9 // This is the standard placement new.
     10 inline void* operator new(size_t, void* __p) throw()
     11 {
     12   clang_analyzer_checkInlined(true);// expected-warning{{TRUE}}
     13   return __p;
     14 }
     15 
     16 
     17 class A {
     18 public:
     19   int getZero() { return 0; }
     20   virtual int getNum() { return 0; }
     21 };
     22 
     23 void test(A &a) {
     24   clang_analyzer_eval(a.getZero() == 0); // expected-warning{{TRUE}}
     25   clang_analyzer_eval(a.getNum() == 0); // expected-warning{{UNKNOWN}}
     26 
     27   A copy(a);
     28   clang_analyzer_eval(copy.getZero() == 0); // expected-warning{{TRUE}}
     29   clang_analyzer_eval(copy.getNum() == 0); // expected-warning{{TRUE}}
     30 }
     31 
     32 
     33 class One : public A {
     34 public:
     35   virtual int getNum() { return 1; }
     36 };
     37 
     38 void testPathSensitivity(int x) {
     39   A a;
     40   One b;
     41 
     42   A *ptr;
     43   switch (x) {
     44   case 0:
     45     ptr = &a;
     46     break;
     47   case 1:
     48     ptr = &b;
     49     break;
     50   default:
     51     return;
     52   }
     53 
     54   // This should be true on both branches.
     55   clang_analyzer_eval(ptr->getNum() == x); // expected-warning {{TRUE}}
     56 }
     57 
     58 
     59 namespace PureVirtualParent {
     60   class Parent {
     61   public:
     62     virtual int pureVirtual() const = 0;
     63     int callVirtual() const {
     64       return pureVirtual();
     65     }
     66   };
     67 
     68   class Child : public Parent {
     69   public:
     70     virtual int pureVirtual() const {
     71       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
     72       return 42;
     73     }
     74   };
     75 
     76   void testVirtual() {
     77     Child x;
     78 
     79     clang_analyzer_eval(x.pureVirtual() == 42); // expected-warning{{TRUE}}
     80     clang_analyzer_eval(x.callVirtual() == 42); // expected-warning{{TRUE}}
     81   }
     82 }
     83 
     84 
     85 namespace PR13569 {
     86   class Parent {
     87   protected:
     88     int m_parent;
     89     virtual int impl() const = 0;
     90 
     91     Parent() : m_parent(0) {}
     92 
     93   public:
     94     int interface() const {
     95       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
     96       return impl();
     97     }
     98   };
     99 
    100   class Child : public Parent {
    101   protected:
    102     virtual int impl() const {
    103       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
    104       return m_parent + m_child;
    105     }
    106 
    107   public:
    108     Child() : m_child(0) {}
    109 
    110     int m_child;
    111   };
    112 
    113   void testVirtual() {
    114     Child x;
    115     x.m_child = 42;
    116 
    117     // Don't crash when inlining and devirtualizing.
    118     x.interface();
    119   }
    120 
    121 
    122   class Grandchild : public Child {};
    123 
    124   void testDevirtualizeToMiddle() {
    125     Grandchild x;
    126     x.m_child = 42;
    127 
    128     // Don't crash when inlining and devirtualizing.
    129     x.interface();
    130   }
    131 }
    132 
    133 namespace PR13569_virtual {
    134   class Parent {
    135   protected:
    136     int m_parent;
    137     virtual int impl() const = 0;
    138 
    139     Parent() : m_parent(0) {}
    140 
    141   public:
    142     int interface() const {
    143       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
    144       return impl();
    145     }
    146   };
    147 
    148   class Child : virtual public Parent {
    149   protected:
    150     virtual int impl() const {
    151       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
    152       return m_parent + m_child;
    153     }
    154 
    155   public:
    156     Child() : m_child(0) {}
    157 
    158     int m_child;
    159   };
    160 
    161   void testVirtual() {
    162     Child x;
    163     x.m_child = 42;
    164 
    165     // Don't crash when inlining and devirtualizing.
    166     x.interface();
    167   }
    168 
    169 
    170   class Grandchild : virtual public Child {};
    171 
    172   void testDevirtualizeToMiddle() {
    173     Grandchild x;
    174     x.m_child = 42;
    175 
    176     // Don't crash when inlining and devirtualizing.
    177     x.interface();
    178   }
    179 }
    180 
    181 namespace Invalidation {
    182   struct X {
    183     void touch(int &x) const {
    184       x = 0;
    185     }
    186 
    187     void touch2(int &x) const;
    188 
    189     virtual void touchV(int &x) const {
    190       x = 0;
    191     }
    192 
    193     virtual void touchV2(int &x) const;
    194 
    195     int test() const {
    196       // We were accidentally not invalidating under inlining
    197       // at one point for virtual methods with visible definitions.
    198       int a, b, c, d;
    199       touch(a);
    200       touch2(b);
    201       touchV(c);
    202       touchV2(d);
    203       return a + b + c + d; // no-warning
    204     }
    205   };
    206 }
    207 
    208 namespace DefaultArgs {
    209   int takesDefaultArgs(int i = 42) {
    210     return -i;
    211   }
    212 
    213   void testFunction() {
    214     clang_analyzer_eval(takesDefaultArgs(1) == -1); // expected-warning{{TRUE}}
    215     clang_analyzer_eval(takesDefaultArgs() == -42); // expected-warning{{TRUE}}
    216   }
    217 
    218   class Secret {
    219   public:
    220     static const int value = 40 + 2;
    221     int get(int i = value) {
    222       return i;
    223     }
    224   };
    225 
    226   void testMethod() {
    227     Secret obj;
    228     clang_analyzer_eval(obj.get(1) == 1); // expected-warning{{TRUE}}
    229     clang_analyzer_eval(obj.get() == 42); // expected-warning{{TRUE}}
    230     clang_analyzer_eval(Secret::value == 42); // expected-warning{{TRUE}}
    231   }
    232 
    233   enum ABC {
    234     A = 0,
    235     B = 1,
    236     C = 2
    237   };
    238 
    239   int enumUser(ABC input = B) {
    240     return static_cast<int>(input);
    241   }
    242 
    243   void testEnum() {
    244     clang_analyzer_eval(enumUser(C) == 2); // expected-warning{{TRUE}}
    245     clang_analyzer_eval(enumUser() == 1); // expected-warning{{TRUE}}
    246   }
    247 
    248 
    249   int exprUser(int input = 2 * 4) {
    250     return input;
    251   }
    252 
    253   int complicatedExprUser(int input = 2 * Secret::value) {
    254     return input;
    255   }
    256 
    257   void testExprs() {
    258     clang_analyzer_eval(exprUser(1) == 1); // expected-warning{{TRUE}}
    259     clang_analyzer_eval(exprUser() == 8); // expected-warning{{TRUE}}
    260 
    261     clang_analyzer_eval(complicatedExprUser(1) == 1); // expected-warning{{TRUE}}
    262     clang_analyzer_eval(complicatedExprUser() == 84); // expected-warning{{TRUE}}
    263   }
    264 
    265   int defaultReference(const int &input = 42) {
    266     return -input;
    267   }
    268   int defaultReferenceZero(const int &input = 0) {
    269     return -input;
    270   }
    271 
    272   void testReference() {
    273     clang_analyzer_eval(defaultReference(1) == -1); // expected-warning{{TRUE}}
    274     clang_analyzer_eval(defaultReference() == -42); // expected-warning{{TRUE}}
    275 
    276     clang_analyzer_eval(defaultReferenceZero(1) == -1); // expected-warning{{TRUE}}
    277     clang_analyzer_eval(defaultReferenceZero() == 0); // expected-warning{{TRUE}}
    278   }
    279 
    280   double defaultFloatReference(const double &i = 42) {
    281     return -i;
    282   }
    283   double defaultFloatReferenceZero(const double &i = 0) {
    284     return -i;
    285   }
    286 
    287   void testFloatReference() {
    288     clang_analyzer_eval(defaultFloatReference(1) == -1); // expected-warning{{UNKNOWN}}
    289     clang_analyzer_eval(defaultFloatReference() == -42); // expected-warning{{UNKNOWN}}
    290 
    291     clang_analyzer_eval(defaultFloatReferenceZero(1) == -1); // expected-warning{{UNKNOWN}}
    292     clang_analyzer_eval(defaultFloatReferenceZero() == 0); // expected-warning{{UNKNOWN}}
    293   }
    294 
    295   char defaultString(const char *s = "abc") {
    296     return s[1];
    297   }
    298 
    299   void testString() {
    300     clang_analyzer_eval(defaultString("xyz") == 'y'); // expected-warning{{TRUE}}
    301     clang_analyzer_eval(defaultString() == 'b'); // expected-warning{{TRUE}}
    302   }
    303 
    304   const void * const void_string = "abc";
    305 
    306   void testBitcastedString() {
    307     clang_analyzer_eval(0 != void_string); // expected-warning{{TRUE}}
    308     clang_analyzer_eval('b' == ((char *)void_string)[1]); // expected-warning{{TRUE}}
    309   }
    310 }
    311 
    312 namespace OperatorNew {
    313   class IntWrapper {
    314   public:
    315     int value;
    316 
    317     IntWrapper(int input) : value(input) {
    318       // We don't want this constructor to be inlined unless we can actually
    319       // use the proper region for operator new.
    320       // See PR12014 and <rdar://problem/12180598>.
    321       clang_analyzer_checkInlined(false); // no-warning
    322     }
    323   };
    324 
    325   void test() {
    326     IntWrapper *obj = new IntWrapper(42);
    327     // should be TRUE
    328     clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}}
    329     delete obj;
    330   }
    331 
    332   void testPlacement() {
    333     IntWrapper *obj = static_cast<IntWrapper *>(malloc(sizeof(IntWrapper)));
    334     IntWrapper *alias = new (obj) IntWrapper(42);
    335 
    336     clang_analyzer_eval(alias == obj); // expected-warning{{TRUE}}
    337 
    338     // should be TRUE
    339     clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}}
    340   }
    341 }
    342 
    343 
    344 namespace VirtualWithSisterCasts {
    345   // This entire set of tests exercises casts from sister classes and
    346   // from classes outside the hierarchy, which can very much confuse
    347   // code that uses DynamicTypeInfo or needs to construct CXXBaseObjectRegions.
    348   // These examples used to cause crashes in +Asserts builds.
    349   struct Parent {
    350     virtual int foo();
    351     int x;
    352   };
    353 
    354   struct A : Parent {
    355     virtual int foo() { return 42; }
    356   };
    357 
    358   struct B : Parent {
    359     virtual int foo();
    360   };
    361 
    362   struct Grandchild : public A {};
    363 
    364   struct Unrelated {};
    365 
    366   void testDowncast(Parent *b) {
    367     A *a = (A *)(void *)b;
    368     clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
    369 
    370     a->x = 42;
    371     clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}}
    372   }
    373 
    374   void testRelated(B *b) {
    375     A *a = (A *)(void *)b;
    376     clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
    377 
    378     a->x = 42;
    379     clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}}
    380   }
    381 
    382   void testUnrelated(Unrelated *b) {
    383     A *a = (A *)(void *)b;
    384     clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
    385 
    386     a->x = 42;
    387     clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}}
    388   }
    389 
    390   void testCastViaNew(B *b) {
    391     Grandchild *g = new (b) Grandchild();
    392     clang_analyzer_eval(g->foo() == 42); // expected-warning{{TRUE}}
    393 
    394     g->x = 42;
    395     clang_analyzer_eval(g->x == 42); // expected-warning{{TRUE}}
    396   }
    397 }
    398 
    399 
    400 namespace QualifiedCalls {
    401   void test(One *object) {
    402     // This uses the One class from the top of the file.
    403     clang_analyzer_eval(object->getNum() == 1); // expected-warning{{UNKNOWN}}
    404     clang_analyzer_eval(object->One::getNum() == 1); // expected-warning{{TRUE}}
    405     clang_analyzer_eval(object->A::getNum() == 0); // expected-warning{{TRUE}}
    406 
    407     // getZero is non-virtual.
    408     clang_analyzer_eval(object->getZero() == 0); // expected-warning{{TRUE}}
    409     clang_analyzer_eval(object->One::getZero() == 0); // expected-warning{{TRUE}}
    410     clang_analyzer_eval(object->A::getZero() == 0); // expected-warning{{TRUE}}
    411 }
    412 }
    413 
    414 
    415 namespace rdar12409977  {
    416   struct Base {
    417     int x;
    418   };
    419 
    420   struct Parent : public Base {
    421     virtual Parent *vGetThis();
    422     Parent *getThis() { return vGetThis(); }
    423   };
    424 
    425   struct Child : public Parent {
    426     virtual Child *vGetThis() { return this; }
    427   };
    428 
    429   void test() {
    430     Child obj;
    431     obj.x = 42;
    432 
    433     // Originally, calling a devirtualized method with a covariant return type
    434     // caused a crash because the return value had the wrong type. When we then
    435     // go to layer a CXXBaseObjectRegion on it, the base isn't a direct base of
    436     // the object region and we get an assertion failure.
    437     clang_analyzer_eval(obj.getThis()->x == 42); // expected-warning{{TRUE}}
    438   }
    439 }
    440 
    441 namespace bug16307 {
    442   void one_argument(int a) { }
    443   void call_with_less() {
    444     reinterpret_cast<void (*)()>(one_argument)(); // expected-warning{{Function taking 1 argument}}
    445   }
    446 }
    447