329 lines · cpp
1// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -std=c++11 -verify -analyzer-config eagerly-assume=false %s2// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -std=c++11 -DTEST_INLINABLE_ALLOCATORS -verify -analyzer-config eagerly-assume=false %s3#include "Inputs/system-header-simulator-cxx.h"4 5void clang_analyzer_eval(bool);6void clang_analyzer_warnIfReached();7 8typedef __typeof__(sizeof(int)) size_t;9extern "C" void *malloc(size_t);10extern "C" void free(void *);11 12int someGlobal;13 14class SomeClass {15public:16 void f(int *p);17};18 19void testImplicitlyDeclaredGlobalNew() {20 if (someGlobal != 0)21 return;22 23 // This used to crash because the global operator new is being implicitly24 // declared and it does not have a valid source location. (PR13090)25 void *x = ::operator new(0);26 ::operator delete(x);27 28 // Check that the new/delete did not invalidate someGlobal;29 clang_analyzer_eval(someGlobal == 0); // expected-warning{{TRUE}}30}31 32void *testPlacementNew() {33 int *x = (int *)malloc(sizeof(int));34 *x = 1;35 clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};36 37 void *y = new (x) int;38 clang_analyzer_eval(x == y); // expected-warning{{TRUE}};39 clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};40 41 return y;42}43 44void *operator new(size_t, size_t, int *);45void *testCustomNew() {46 int x[1] = {1};47 clang_analyzer_eval(*x == 1); // expected-warning{{TRUE}};48 49 void *y = new (0, x) int;50 clang_analyzer_eval(*x == 1); // expected-warning{{UNKNOWN}};51 52 return y; // no-warning53}54 55void *operator new(size_t, void *, void *);56void *testCustomNewMalloc() {57 int *x = (int *)malloc(sizeof(int));58 59 // Should be no-warning (the custom allocator could have freed x).60 void *y = new (0, x) int; // no-warning61 62 return y;63}64 65void testScalarInitialization() {66 int *n = new int(3);67 clang_analyzer_eval(*n == 3); // expected-warning{{TRUE}}68 69 new (n) int();70 clang_analyzer_eval(*n == 0); // expected-warning{{TRUE}}71 72 new (n) int{3};73 clang_analyzer_eval(*n == 3); // expected-warning{{TRUE}}74 75 new (n) int{};76 clang_analyzer_eval(*n == 0); // expected-warning{{TRUE}}77}78 79struct PtrWrapper {80 int *x;81 82 PtrWrapper(int *input) : x(input) {}83};84 85PtrWrapper *testNewInvalidation() {86 // Ensure that we don't consider this a leak.87 return new PtrWrapper(static_cast<int *>(malloc(4))); // no-warning88}89 90void testNewInvalidationPlacement(PtrWrapper *w) {91 // Ensure that we don't consider this a leak.92 new (w) PtrWrapper(static_cast<int *>(malloc(4))); // no-warning93}94 95int **testNewInvalidationScalar() {96 // Ensure that we don't consider this a leak.97 return new (int *)(static_cast<int *>(malloc(4))); // no-warning98}99 100void testNewInvalidationScalarPlacement(int **p) {101 // Ensure that we don't consider this a leak.102 new (p) (int *)(static_cast<int *>(malloc(4))); // no-warning103}104 105void testCacheOut(PtrWrapper w) {106 extern bool coin();107 if (coin())108 w.x = 0;109 new (&w.x) (int*)(0); // we cache out here; don't crash110}111 112void testUseAfter(int *p) {113 SomeClass *c = new SomeClass;114 free(p);115 c->f(p); // expected-warning{{Use of memory after it is released}}116 delete c;117}118 119// new/delete oparators are subjects of cplusplus.NewDelete.120void testNewDeleteNoWarn() {121 int i;122 delete &i; // no-warning123 124 int *p1 = new int;125 delete ++p1; // no-warning126 127 int *p2 = new int;128 delete p2;129 delete p2; // no-warning130 131 int *p3 = new int; // no-warning132}133 134void testDeleteMallocked() {135 int *x = (int *)malloc(sizeof(int));136 // unix.MismatchedDeallocator would catch this, but we're not testing it here.137 delete x;138}139 140void testDeleteOpAfterFree() {141 int *p = (int *)malloc(sizeof(int));142 free(p);143 operator delete(p); // expected-warning{{Use of memory after it is released}}144}145 146void testDeleteAfterFree() {147 int *p = (int *)malloc(sizeof(int));148 free(p);149 delete p; // expected-warning{{Use of memory after it is released}}150}151 152void testStandardPlacementNewAfterFree() {153 int *p = (int *)malloc(sizeof(int));154 free(p);155 p = new(p) int; // expected-warning{{Use of memory after it is released}}156}157 158void testCustomPlacementNewAfterFree() {159 int *p = (int *)malloc(sizeof(int));160 free(p);161 p = new(0, p) int; // expected-warning{{Use of memory after it is released}}162}163 164void testUsingThisAfterDelete() {165 SomeClass *c = new SomeClass;166 delete c;167 c->f(0); // no-warning168}169 170void testAggregateNew() {171 struct Point { int x, y; };172 new Point{1, 2}; // no crash173 174 Point p;175 new (&p) Point{1, 2}; // no crash176 clang_analyzer_eval(p.x == 1); // expected-warning{{TRUE}}177 clang_analyzer_eval(p.y == 2); // expected-warning{{TRUE}}178}179 180int testNoInitialization() {181 int *n = new int;182 183 if (*n) { // expected-warning{{Branch condition evaluates to a garbage value [core.uninitialized.Branch]}}184 delete n;185 return 0;186 }187 delete n;188 return 1;189}190 191//===----------------------------------------------------------------------===//192// Incorrectly-modelled behavior.193//===----------------------------------------------------------------------===//194 195int testNoInitializationPlacement() {196 int n;197 new (&n) int;198 199 if (n) { // expected-warning{{Branch condition evaluates to a garbage value}}200 return 0;201 }202 return 1;203}204 205// Test modelling destructor call on call to delete206class IntPair{207public:208 int x;209 int y;210 IntPair() {};211 ~IntPair() {x = x/y;}; //expected-warning {{Division by zero}}212};213 214void testCallToDestructor() {215 IntPair *b = new IntPair();216 b->x = 1;217 b->y = 0;218 delete b; // This results in divide by zero in destructor219}220 221// Test Deleting a value that's passed as an argument.222class DerefClass{223public:224 int *x;225 DerefClass() {};226 ~DerefClass() {*x = 1;}; //expected-warning {{Dereference of null pointer (loaded from field 'x')}}227};228 229void testDestCall(DerefClass *arg) {230 delete arg;231}232 233void test_delete_dtor_Arg() {234 DerefClass *pair = new DerefClass();235 pair->x = 0;236 testDestCall(pair);237}238 239//Deleting the address of a local variable, null pointer240void abort(void) __attribute__((noreturn));241 242class NoReturnDtor {243public:244 NoReturnDtor() {}245 ~NoReturnDtor() {abort();}246};247 248void test_delete_dtor_LocalVar() {249 NoReturnDtor test;250 delete &test; // no warn or crash251}252 253class DerivedNoReturn:public NoReturnDtor {254public:255 DerivedNoReturn() {};256 ~DerivedNoReturn() {};257};258 259void testNullDtorDerived() {260 DerivedNoReturn *p = new DerivedNoReturn();261 delete p; // Calls the base destructor which aborts, checked below262 clang_analyzer_eval(true); // no warn263}264 265//Deleting a non-class pointer should not crash/warn266void test_var_delete() {267 int *v = new int;268 delete v; // no crash/warn269 clang_analyzer_eval(true); // expected-warning{{TRUE}}270}271 272void test_array_delete() {273 class C {274 public:275 ~C() {}276 };277 278 auto c1 = new C[2][3];279 delete[] c1; // no-crash // no-warning280 281 C c2[4];282 // FIXME: Should warn.283 delete[] &c2; // no-crash284 285 C c3[7][6];286 // FIXME: Should warn.287 delete[] &c3; // no-crash288}289 290void testDeleteNull() {291 NoReturnDtor *foo = 0;292 delete foo; // should not call destructor, checked below293 clang_analyzer_eval(true); // expected-warning{{TRUE}}294}295 296void testNullAssigneddtor() {297 NoReturnDtor *p = 0;298 NoReturnDtor *s = p;299 delete s; // should not call destructor, checked below300 clang_analyzer_eval(true); // expected-warning{{TRUE}}301}302 303void deleteArg(NoReturnDtor *test) {304 delete test;305}306 307void testNulldtorArg() {308 NoReturnDtor *p = 0;309 deleteArg(p);310 clang_analyzer_eval(true); // expected-warning{{TRUE}}311}312 313void testDeleteUnknown(NoReturnDtor *foo) {314 delete foo; // should assume non-null and call noreturn destructor315 clang_analyzer_eval(true); // no-warning316}317 318void testArrayNull() {319 NoReturnDtor *fooArray = 0;320 delete[] fooArray; // should not call destructor, checked below321 clang_analyzer_eval(true); // expected-warning{{TRUE}}322}323 324void testArrayDestr() {325 NoReturnDtor *p = new NoReturnDtor[2];326 delete[] p;327 clang_analyzer_warnIfReached(); // no-warning328}329