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 
    305 namespace OperatorNew {
    306   class IntWrapper {
    307   public:
    308     int value;
    309 
    310     IntWrapper(int input) : value(input) {
    311       // We don't want this constructor to be inlined unless we can actually
    312       // use the proper region for operator new.
    313       // See PR12014 and <rdar://problem/12180598>.
    314       clang_analyzer_checkInlined(false); // no-warning
    315     }
    316   };
    317 
    318   void test() {
    319     IntWrapper *obj = new IntWrapper(42);
    320     // should be TRUE
    321     clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}}
    322     delete obj;
    323   }
    324 
    325   void testPlacement() {
    326     IntWrapper *obj = static_cast<IntWrapper *>(malloc(sizeof(IntWrapper)));
    327     IntWrapper *alias = new (obj) IntWrapper(42);
    328 
    329     clang_analyzer_eval(alias == obj); // expected-warning{{TRUE}}
    330 
    331     // should be TRUE
    332     clang_analyzer_eval(obj->value == 42); // expected-warning{{UNKNOWN}}
    333   }
    334 }
    335 
    336 
    337 namespace VirtualWithSisterCasts {
    338   // This entire set of tests exercises casts from sister classes and
    339   // from classes outside the hierarchy, which can very much confuse
    340   // code that uses DynamicTypeInfo or needs to construct CXXBaseObjectRegions.
    341   // These examples used to cause crashes in +Asserts builds.
    342   struct Parent {
    343     virtual int foo();
    344     int x;
    345   };
    346 
    347   struct A : Parent {
    348     virtual int foo() { return 42; }
    349   };
    350 
    351   struct B : Parent {
    352     virtual int foo();
    353   };
    354 
    355   struct Grandchild : public A {};
    356 
    357   struct Unrelated {};
    358 
    359   void testDowncast(Parent *b) {
    360     A *a = (A *)(void *)b;
    361     clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
    362 
    363     a->x = 42;
    364     clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}}
    365   }
    366 
    367   void testRelated(B *b) {
    368     A *a = (A *)(void *)b;
    369     clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
    370 
    371     a->x = 42;
    372     clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}}
    373   }
    374 
    375   void testUnrelated(Unrelated *b) {
    376     A *a = (A *)(void *)b;
    377     clang_analyzer_eval(a->foo() == 42); // expected-warning{{UNKNOWN}}
    378 
    379     a->x = 42;
    380     clang_analyzer_eval(a->x == 42); // expected-warning{{TRUE}}
    381   }
    382 
    383   void testCastViaNew(B *b) {
    384     Grandchild *g = new (b) Grandchild();
    385     clang_analyzer_eval(g->foo() == 42); // expected-warning{{TRUE}}
    386 
    387     g->x = 42;
    388     clang_analyzer_eval(g->x == 42); // expected-warning{{TRUE}}
    389   }
    390 }
    391 
    392 
    393 namespace QualifiedCalls {
    394   void test(One *object) {
    395     // This uses the One class from the top of the file.
    396     clang_analyzer_eval(object->getNum() == 1); // expected-warning{{UNKNOWN}}
    397     clang_analyzer_eval(object->One::getNum() == 1); // expected-warning{{TRUE}}
    398     clang_analyzer_eval(object->A::getNum() == 0); // expected-warning{{TRUE}}
    399 
    400     // getZero is non-virtual.
    401     clang_analyzer_eval(object->getZero() == 0); // expected-warning{{TRUE}}
    402     clang_analyzer_eval(object->One::getZero() == 0); // expected-warning{{TRUE}}
    403     clang_analyzer_eval(object->A::getZero() == 0); // expected-warning{{TRUE}}
    404 }
    405 }
    406 
    407 
    408 namespace rdar12409977  {
    409   struct Base {
    410     int x;
    411   };
    412 
    413   struct Parent : public Base {
    414     virtual Parent *vGetThis();
    415     Parent *getThis() { return vGetThis(); }
    416   };
    417 
    418   struct Child : public Parent {
    419     virtual Child *vGetThis() { return this; }
    420   };
    421 
    422   void test() {
    423     Child obj;
    424     obj.x = 42;
    425 
    426     // Originally, calling a devirtualized method with a covariant return type
    427     // caused a crash because the return value had the wrong type. When we then
    428     // go to layer a CXXBaseObjectRegion on it, the base isn't a direct base of
    429     // the object region and we get an assertion failure.
    430     clang_analyzer_eval(obj.getThis()->x == 42); // expected-warning{{TRUE}}
    431   }
    432 }
    433 
    434 namespace bug16307 {
    435   void one_argument(int a) { }
    436   void call_with_less() {
    437     reinterpret_cast<void (*)()>(one_argument)(); // expected-warning{{Function taking 1 argument}}
    438   }
    439 }
    440