Home | History | Annotate | Download | only in Analysis
      1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -fobjc-arc -analyzer-config c++-inlining=constructors -Wno-null-dereference -std=c++11 -verify %s
      2 
      3 void clang_analyzer_eval(bool);
      4 void clang_analyzer_checkInlined(bool);
      5 
      6 // A simplified version of std::move.
      7 template <typename T>
      8 T &&move(T &obj) {
      9   return static_cast<T &&>(obj);
     10 }
     11 
     12 
     13 struct Wrapper {
     14   __strong id obj;
     15 };
     16 
     17 void test() {
     18   Wrapper w;
     19   // force a diagnostic
     20   *(char *)0 = 1; // expected-warning{{Dereference of null pointer}}
     21 }
     22 
     23 
     24 struct IntWrapper {
     25   int x;
     26 };
     27 
     28 void testCopyConstructor() {
     29   IntWrapper a;
     30   a.x = 42;
     31 
     32   IntWrapper b(a);
     33   clang_analyzer_eval(b.x == 42); // expected-warning{{TRUE}}
     34 }
     35 
     36 struct NonPODIntWrapper {
     37   int x;
     38 
     39   virtual int get();
     40 };
     41 
     42 void testNonPODCopyConstructor() {
     43   NonPODIntWrapper a;
     44   a.x = 42;
     45 
     46   NonPODIntWrapper b(a);
     47   clang_analyzer_eval(b.x == 42); // expected-warning{{TRUE}}
     48 }
     49 
     50 
     51 namespace ConstructorVirtualCalls {
     52   class A {
     53   public:
     54     int *out1, *out2, *out3;
     55 
     56     virtual int get() { return 1; }
     57 
     58     A(int *out1) {
     59       *out1 = get();
     60     }
     61   };
     62 
     63   class B : public A {
     64   public:
     65     virtual int get() { return 2; }
     66 
     67     B(int *out1, int *out2) : A(out1) {
     68       *out2 = get();
     69     }
     70   };
     71 
     72   class C : public B {
     73   public:
     74     virtual int get() { return 3; }
     75 
     76     C(int *out1, int *out2, int *out3) : B(out1, out2) {
     77       *out3 = get();
     78     }
     79   };
     80 
     81   void test() {
     82     int a, b, c;
     83 
     84     C obj(&a, &b, &c);
     85     clang_analyzer_eval(a == 1); // expected-warning{{TRUE}}
     86     clang_analyzer_eval(b == 2); // expected-warning{{TRUE}}
     87     clang_analyzer_eval(c == 3); // expected-warning{{TRUE}}
     88 
     89     clang_analyzer_eval(obj.get() == 3); // expected-warning{{TRUE}}
     90 
     91     // Sanity check for devirtualization.
     92     A *base = &obj;
     93     clang_analyzer_eval(base->get() == 3); // expected-warning{{TRUE}}
     94   }
     95 }
     96 
     97 namespace TemporaryConstructor {
     98   class BoolWrapper {
     99   public:
    100     BoolWrapper() {
    101       clang_analyzer_checkInlined(true); // expected-warning{{TRUE}}
    102       value = true;
    103     }
    104     bool value;
    105   };
    106 
    107   void test() {
    108     // PR13717 - Don't crash when a CXXTemporaryObjectExpr is inlined.
    109     if (BoolWrapper().value)
    110       return;
    111   }
    112 }
    113 
    114 
    115 namespace ConstructorUsedAsRValue {
    116   using TemporaryConstructor::BoolWrapper;
    117 
    118   bool extractValue(BoolWrapper b) {
    119     return b.value;
    120   }
    121 
    122   void test() {
    123     bool result = extractValue(BoolWrapper());
    124     clang_analyzer_eval(result); // expected-warning{{TRUE}}
    125   }
    126 }
    127 
    128 namespace PODUninitialized {
    129   class POD {
    130   public:
    131     int x, y;
    132   };
    133 
    134   class PODWrapper {
    135   public:
    136     POD p;
    137   };
    138 
    139   class NonPOD {
    140   public:
    141     int x, y;
    142 
    143     NonPOD() {}
    144     NonPOD(const NonPOD &Other)
    145       : x(Other.x), y(Other.y) // expected-warning {{undefined}}
    146     {
    147     }
    148     NonPOD(NonPOD &&Other)
    149     : x(Other.x), y(Other.y) // expected-warning {{undefined}}
    150     {
    151     }
    152 
    153     NonPOD &operator=(const NonPOD &Other)
    154     {
    155       x = Other.x;
    156       y = Other.y; // expected-warning {{undefined}}
    157       return *this;
    158     }
    159     NonPOD &operator=(NonPOD &&Other)
    160     {
    161       x = Other.x;
    162       y = Other.y; // expected-warning {{undefined}}
    163       return *this;
    164     }
    165   };
    166 
    167   class NonPODWrapper {
    168   public:
    169     class Inner {
    170     public:
    171       int x, y;
    172 
    173       Inner() {}
    174       Inner(const Inner &Other)
    175         : x(Other.x), y(Other.y) // expected-warning {{undefined}}
    176       {
    177       }
    178       Inner(Inner &&Other)
    179       : x(Other.x), y(Other.y) // expected-warning {{undefined}}
    180       {
    181       }
    182 
    183       Inner &operator=(const Inner &Other)
    184       {
    185         x = Other.x; // expected-warning {{undefined}}
    186         y = Other.y;
    187         return *this;
    188       }
    189       Inner &operator=(Inner &&Other)
    190       {
    191         x = Other.x; // expected-warning {{undefined}}
    192         y = Other.y;
    193         return *this;
    194       }
    195     };
    196 
    197     Inner p;
    198   };
    199 
    200   void testPOD() {
    201     POD p;
    202     p.x = 1;
    203     POD p2 = p; // no-warning
    204     clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}}
    205     POD p3 = move(p); // no-warning
    206     clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}}
    207 
    208     // Use rvalues as well.
    209     clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}}
    210 
    211     PODWrapper w;
    212     w.p.y = 1;
    213     PODWrapper w2 = w; // no-warning
    214     clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}}
    215     PODWrapper w3 = move(w); // no-warning
    216     clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}}
    217 
    218     // Use rvalues as well.
    219     clang_analyzer_eval(PODWrapper(w3).p.y == 1); // expected-warning{{TRUE}}
    220   }
    221 
    222   void testNonPOD() {
    223     NonPOD p;
    224     p.x = 1;
    225     NonPOD p2 = p;
    226   }
    227 
    228   void testNonPODMove() {
    229     NonPOD p;
    230     p.x = 1;
    231     NonPOD p2 = move(p);
    232   }
    233 
    234   void testNonPODWrapper() {
    235     NonPODWrapper w;
    236     w.p.y = 1;
    237     NonPODWrapper w2 = w;
    238   }
    239 
    240   void testNonPODWrapperMove() {
    241     NonPODWrapper w;
    242     w.p.y = 1;
    243     NonPODWrapper w2 = move(w);
    244   }
    245 
    246   // Not strictly about constructors, but trivial assignment operators should
    247   // essentially work the same way.
    248   namespace AssignmentOperator {
    249     void testPOD() {
    250       POD p;
    251       p.x = 1;
    252       POD p2;
    253       p2 = p; // no-warning
    254       clang_analyzer_eval(p2.x == 1); // expected-warning{{TRUE}}
    255       POD p3;
    256       p3 = move(p); // no-warning
    257       clang_analyzer_eval(p3.x == 1); // expected-warning{{TRUE}}
    258 
    259       PODWrapper w;
    260       w.p.y = 1;
    261       PODWrapper w2;
    262       w2 = w; // no-warning
    263       clang_analyzer_eval(w2.p.y == 1); // expected-warning{{TRUE}}
    264       PODWrapper w3;
    265       w3 = move(w); // no-warning
    266       clang_analyzer_eval(w3.p.y == 1); // expected-warning{{TRUE}}
    267     }
    268 
    269     void testReturnValue() {
    270       POD p;
    271       p.x = 1;
    272       POD p2;
    273       clang_analyzer_eval(&(p2 = p) == &p2); // expected-warning{{TRUE}}
    274 
    275       PODWrapper w;
    276       w.p.y = 1;
    277       PODWrapper w2;
    278       clang_analyzer_eval(&(w2 = w) == &w2); // expected-warning{{TRUE}}
    279     }
    280 
    281     void testNonPOD() {
    282       NonPOD p;
    283       p.x = 1;
    284       NonPOD p2;
    285       p2 = p;
    286     }
    287 
    288     void testNonPODMove() {
    289       NonPOD p;
    290       p.x = 1;
    291       NonPOD p2;
    292       p2 = move(p);
    293     }
    294 
    295     void testNonPODWrapper() {
    296       NonPODWrapper w;
    297       w.p.y = 1;
    298       NonPODWrapper w2;
    299       w2 = w;
    300     }
    301 
    302     void testNonPODWrapperMove() {
    303       NonPODWrapper w;
    304       w.p.y = 1;
    305       NonPODWrapper w2;
    306       w2 = move(w);
    307     }
    308   }
    309 }
    310