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