| 1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=text -analyzer-config c++-inlining=destructors -std=c++11 -verify -Wno-tautological-undefined-compare %s |
| 2 | // RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=plist-multi-file -analyzer-config c++-inlining=destructors -std=c++11 %s -o %t.plist -Wno-tautological-undefined-compare |
| 3 | // RUN: cat %t.plist | %diff_plist %S/Inputs/expected-plists/path-notes.cpp.plist - |
| 4 | |
| 5 | class Foo { |
| 6 | public: |
| 7 | static void use(int *p) { |
| 8 | *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}} |
| 9 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'p')}} |
| 10 | } |
| 11 | |
| 12 | Foo(int *p) { |
| 13 | use(p); |
| 14 | // expected-note@-1 {{Passing null pointer value via 1st parameter 'p'}} |
| 15 | // expected-note@-2 {{Calling 'Foo::use'}} |
| 16 | } |
| 17 | }; |
| 18 | |
| 19 | static int *globalPtr; |
| 20 | |
| 21 | class Bar { |
| 22 | public: |
| 23 | ~Bar() { |
| 24 | Foo f(globalPtr); |
| 25 | // expected-note@-1 {{Passing null pointer value via 1st parameter 'p'}} |
| 26 | // expected-note@-2 {{Calling constructor for 'Foo'}} |
| 27 | } |
| 28 | }; |
| 29 | |
| 30 | void test() { |
| 31 | Bar b; |
| 32 | globalPtr = 0; |
| 33 | // expected-note@-1 {{Null pointer value stored to 'globalPtr'}} |
| 34 | } // expected-note {{Calling '~Bar'}} |
| 35 | |
| 36 | |
| 37 | void testAnonymous() { |
| 38 | class { |
| 39 | public: |
| 40 | void method(int *p) { |
| 41 | *p = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'p')}} |
| 42 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'p')}} |
| 43 | } |
| 44 | } anonymous; |
| 45 | |
| 46 | anonymous.method(0); |
| 47 | // expected-note@-1 {{Passing null pointer value via 1st parameter 'p'}} |
| 48 | // expected-note@-2 {{Calling 'method'}} |
| 49 | } |
| 50 | |
| 51 | |
| 52 | // A simplified version of std::move. |
| 53 | template <typename T> |
| 54 | T &&move(T &obj) { |
| 55 | return static_cast<T &&>(obj); |
| 56 | } |
| 57 | |
| 58 | |
| 59 | namespace defaulted { |
| 60 | class Dereferencer { |
| 61 | public: |
| 62 | Dereferencer() { |
| 63 | *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
| 64 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
| 65 | } |
| 66 | |
| 67 | Dereferencer(const Dereferencer &Other) { |
| 68 | *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
| 69 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
| 70 | } |
| 71 | |
| 72 | Dereferencer(Dereferencer &&Other) { |
| 73 | *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
| 74 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
| 75 | } |
| 76 | |
| 77 | void operator=(const Dereferencer &Other) { |
| 78 | *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
| 79 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
| 80 | } |
| 81 | |
| 82 | void operator=(Dereferencer &&Other) { |
| 83 | *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
| 84 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
| 85 | } |
| 86 | |
| 87 | ~Dereferencer() { |
| 88 | *globalPtr = 1; // expected-warning {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
| 89 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'globalPtr')}} |
| 90 | } |
| 91 | }; |
| 92 | |
| 93 | class Wrapper { |
| 94 | Dereferencer d; |
| 95 | }; |
| 96 | |
| 97 | class MovableWrapper { |
| 98 | Dereferencer d; |
| 99 | public: |
| 100 | MovableWrapper() = default; |
| 101 | |
| 102 | MovableWrapper(MovableWrapper &&Other) = default; |
| 103 | // expected-note@-1 {{Calling move constructor for 'Dereferencer'}} |
| 104 | |
| 105 | MovableWrapper &operator=(MovableWrapper &&Other) = default; |
| 106 | // expected-note@-1 {{Calling move assignment operator for 'Dereferencer'}} |
| 107 | }; |
| 108 | |
| 109 | void testDefaultConstruction() { |
| 110 | globalPtr = 0; |
| 111 | // expected-note@-1 {{Null pointer value stored to 'globalPtr'}} |
| 112 | Wrapper w; |
| 113 | // expected-note@-1 {{Calling implicit default constructor for 'Wrapper'}} |
| 114 | // expected-note@-2 {{Calling default constructor for 'Dereferencer'}} |
| 115 | } |
| 116 | |
| 117 | void testCopyConstruction(const Wrapper &input) { |
| 118 | globalPtr = 0; |
| 119 | // expected-note@-1 {{Null pointer value stored to 'globalPtr'}} |
| 120 | Wrapper w{input}; |
| 121 | // expected-note@-1 {{Calling implicit copy constructor for 'Wrapper'}} |
| 122 | // expected-note@-2 {{Calling copy constructor for 'Dereferencer'}} |
| 123 | } |
| 124 | |
| 125 | void testMoveConstruction(MovableWrapper &&input) { |
| 126 | globalPtr = 0; |
| 127 | // expected-note@-1 {{Null pointer value stored to 'globalPtr'}} |
| 128 | MovableWrapper w{move(input)}; |
| 129 | // expected-note@-1 {{Calling defaulted move constructor for 'MovableWrapper'}} |
| 130 | } |
| 131 | |
| 132 | void testCopyAssignment(const Wrapper &input) { |
| 133 | Wrapper w; |
| 134 | globalPtr = 0; |
| 135 | // expected-note@-1 {{Null pointer value stored to 'globalPtr'}} |
| 136 | w = input; |
| 137 | // expected-note@-1 {{Calling implicit copy assignment operator for 'Wrapper'}} |
| 138 | // expected-note@-2 {{Calling copy assignment operator for 'Dereferencer'}} |
| 139 | } |
| 140 | |
| 141 | void testMoveAssignment(MovableWrapper &&input) { |
| 142 | MovableWrapper w; |
| 143 | globalPtr = 0; |
| 144 | // expected-note@-1 {{Null pointer value stored to 'globalPtr'}} |
| 145 | w = move(input); |
| 146 | // expected-note@-1 {{Calling defaulted move assignment operator for 'MovableWrapper'}} |
| 147 | } |
| 148 | |
| 149 | void testDestruction() { |
| 150 | Wrapper w; |
| 151 | globalPtr = 0; |
| 152 | // expected-note@-1 {{Null pointer value stored to 'globalPtr'}} |
| 153 | } |
| 154 | // expected-note@-1 {{Calling implicit destructor for 'Wrapper'}} |
| 155 | // expected-note@-2 {{Calling '~Dereferencer'}} |
| 156 | } |
| 157 | |
| 158 | namespace ReturnZeroNote { |
| 159 | int getZero() { |
| 160 | return 0; |
| 161 | // expected-note@-1 {{Returning zero}} |
| 162 | } |
| 163 | |
| 164 | const int &getZeroByRef() { |
| 165 | static int zeroVar; |
| 166 | zeroVar = 0; |
| 167 | // expected-note@-1 {{The value 0 is assigned to 'zeroVar'}} |
| 168 | return zeroVar; |
| 169 | // expected-note@-1 {{Returning zero (reference to 'zeroVar')}} |
| 170 | } |
| 171 | |
| 172 | void test() { |
| 173 | int problem = 1 / getZero(); // expected-warning {{Division by zero}} |
| 174 | // expected-note@-1 {{Calling 'getZero'}} |
| 175 | // expected-note@-2 {{Returning from 'getZero'}} |
| 176 | // expected-note@-3 {{Division by zero}} |
| 177 | } |
| 178 | |
| 179 | void testRef() { |
| 180 | int problem = 1 / getZeroByRef(); // expected-warning {{Division by zero}} |
| 181 | // expected-note@-1 {{Calling 'getZeroByRef'}} |
| 182 | // expected-note@-2 {{Returning from 'getZeroByRef'}} |
| 183 | // expected-note@-3 {{Division by zero}} |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | int &returnNullReference() { |
| 188 | int *x = 0; |
| 189 | // expected-note@-1 {{'x' initialized to a null pointer value}} |
| 190 | return *x; // expected-warning{{Returning null reference}} |
| 191 | // expected-note@-1 {{Returning null reference}} |
| 192 | } |
| 193 | |
| 194 | struct FooWithInitializer { |
| 195 | int *ptr; |
| 196 | FooWithInitializer(int *p) : ptr(p) { // expected-note {{Null pointer value stored to 'f.ptr'}} |
| 197 | *ptr = 1; // expected-note {{Dereference of null pointer (loaded from field 'ptr')}} |
| 198 | // expected-warning@-1 {{Dereference of null pointer (loaded from field 'ptr')}} |
| 199 | } |
| 200 | }; |
| 201 | |
| 202 | void testPathNoteOnInitializer() { |
| 203 | int *p = 0; // expected-note {{'p' initialized to a null pointer value}} |
| 204 | |
| 205 | FooWithInitializer f(p); // expected-note {{Passing null pointer value via 1st parameter 'p'}} |
| 206 | // expected-note@-1 {{Calling constructor for 'FooWithInitializer'}} |
| 207 | } |
| 208 | |
| 209 | int testNonPrintableAssignment(int **p) { |
| 210 | int *&y = *p; // expected-note {{'y' initialized here}} |
| 211 | y = 0; // expected-note {{Storing null pointer value}} |
| 212 | return *y; // expected-warning {{Dereference of null pointer (loaded from variable 'y')}} |
| 213 | // expected-note@-1 {{Dereference of null pointer (loaded from variable 'y')}} |
| 214 | } |
| 215 | |
| 216 | struct Base { int *x; }; |
| 217 | struct Derived : public Base {}; |
| 218 | |
| 219 | void test(Derived d) { |
| 220 | d.x = 0; //expected-note {{Null pointer value stored to 'd.x'}} |
| 221 | *d.x = 1; // expected-warning {{Dereference of null pointer (loaded from field 'x')}} |
| 222 | // expected-note@-1 {{Dereference of null pointer (loaded from field 'x')}} |
| 223 | } |
| 224 | |
| 225 | struct Owner { |
| 226 | struct Wrapper { |
| 227 | int x; |
| 228 | }; |
| 229 | Wrapper *arr; |
| 230 | void testGetDerefExprOnMemberExprWithADot(); |
| 231 | }; |
| 232 | |
| 233 | void Owner::testGetDerefExprOnMemberExprWithADot() { |
| 234 | if (arr) // expected-note {{Assuming pointer value is null}} |
| 235 | // expected-note@-1 {{Taking false branch}} |
| 236 | ; |
| 237 | arr[1].x = 1; //expected-warning {{Dereference of null pointer}} |
| 238 | //expected-note@-1 {{Dereference of null pointer}} |
| 239 | } |
| 240 | |
| 241 | void testGetDerefExprOnMemberExprWithADot() { |
| 242 | Owner::Wrapper *arr; // expected-note {{'arr' declared without an initial value}} |
| 243 | arr[2].x = 1; // expected-warning {{Dereference of undefined pointer value}} |
| 244 | // expected-note@-1 {{Dereference of undefined pointer value}} |
| 245 | } |
| 246 | |
| 247 | |
| 248 | |
| 249 | class A { |
| 250 | public: |
| 251 | void bar() const {} |
| 252 | }; |
| 253 | const A& testDeclRefExprToReferenceInGetDerefExpr(const A *ptr) { |
| 254 | const A& val = *ptr; //expected-note {{'val' initialized here}} |
| 255 | |
| 256 | // This is not valid C++; if 'ptr' were null, creating 'ref' would be illegal. |
| 257 | // However, this is not checked at runtime, so this branch is actually |
| 258 | // possible. |
| 259 | if (&val == 0) { //expected-note {{Assuming pointer value is null}} |
| 260 | // expected-note@-1 {{Taking true branch}} |
| 261 | val.bar(); // expected-warning {{Called C++ object pointer is null}} |
| 262 | // expected-note@-1 {{Called C++ object pointer is null}} |
| 263 | } |
| 264 | |
| 265 | return val; |
| 266 | } |
| 267 | |
| 268 | int generateNoteOnDefaultArgument(int one, int two = 0) { |
| 269 | return one/two; // expected-warning {{Division by zero}} |
| 270 | // expected-note@-1 {{Division by zero}} |
| 271 | } |
| 272 | int callGenerateNoteOnDefaultArgument(int o) { |
| 273 | return generateNoteOnDefaultArgument(o); //expected-note{{Calling 'generateNoteOnDefaultArgument'}} |
| 274 | //expected-note@-1 {{Passing the value 0 via 2nd parameter 'two'}} |
| 275 | } |
| 276 | |
| 277 | namespace PR17746 { |
| 278 | class Inner { |
| 279 | public: |
| 280 | ~Inner() { |
| 281 | *(volatile int *)0 = 1; // expected-warning {{Dereference of null pointer}} |
| 282 | // expected-note@-1 {{Dereference of null pointer}} |
| 283 | } |
| 284 | }; |
| 285 | |
| 286 | class Outer { |
| 287 | public: |
| 288 | Inner *inner; |
| 289 | ~Outer() { |
| 290 | delete inner; |
| 291 | // expected-note@-1 {{Calling '~Inner'}} |
| 292 | } |
| 293 | }; |
| 294 | |
| 295 | void test(Outer *outer) { |
| 296 | delete outer; |
| 297 | // expected-note@-1 {{Calling '~Outer'}} |
| 298 | } |
| 299 | } |
| 300 | |
| 301 | |