1 // RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.DeleteWithNonVirtualDtor -std=c++11 -verify -analyzer-output=text %s 2 3 struct Virtual { ~VirtualVirtual4 virtual ~Virtual() {} 5 }; 6 7 struct VDerived : public Virtual {}; 8 9 struct NonVirtual { ~NonVirtualNonVirtual10 ~NonVirtual() {} 11 }; 12 13 struct NVDerived : public NonVirtual {}; 14 struct NVDoubleDerived : public NVDerived {}; 15 16 struct Base { 17 virtual void destroy() = 0; 18 }; 19 20 class PrivateDtor final : public Base { 21 public: destroy()22 void destroy() { delete this; } 23 private: ~PrivateDtor()24 ~PrivateDtor() {} 25 }; 26 27 struct ImplicitNV { 28 virtual void f(); 29 }; 30 31 struct ImplicitNVDerived : public ImplicitNV {}; 32 33 NVDerived *get(); 34 create()35NonVirtual *create() { 36 NonVirtual *x = new NVDerived(); // expected-note{{Conversion from derived to base happened here}} 37 return x; 38 } 39 sink(NonVirtual * x)40void sink(NonVirtual *x) { 41 delete x; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} 42 // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} 43 } 44 sinkCast(NonVirtual * y)45void sinkCast(NonVirtual *y) { 46 delete reinterpret_cast<NVDerived*>(y); 47 } 48 sinkParamCast(NVDerived * z)49void sinkParamCast(NVDerived *z) { 50 delete z; 51 } 52 singleDerived()53void singleDerived() { 54 NonVirtual *sd; 55 sd = new NVDerived(); // expected-note{{Conversion from derived to base happened here}} 56 delete sd; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} 57 // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} 58 } 59 singleDerivedArr()60void singleDerivedArr() { 61 NonVirtual *sda = new NVDerived[5]; // expected-note{{Conversion from derived to base happened here}} 62 delete[] sda; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} 63 // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} 64 } 65 doubleDerived()66void doubleDerived() { 67 NonVirtual *dd = new NVDoubleDerived(); // expected-note{{Conversion from derived to base happened here}} 68 delete (dd); // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} 69 // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} 70 } 71 assignThroughFunction()72void assignThroughFunction() { 73 NonVirtual *atf = get(); // expected-note{{Conversion from derived to base happened here}} 74 delete atf; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} 75 // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} 76 } 77 assignThroughFunction2()78void assignThroughFunction2() { 79 NonVirtual *atf2; 80 atf2 = get(); // expected-note{{Conversion from derived to base happened here}} 81 delete atf2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} 82 // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} 83 } 84 createThroughFunction()85void createThroughFunction() { 86 NonVirtual *ctf = create(); // expected-note{{Calling 'create'}} 87 // expected-note@-1{{Returning from 'create'}} 88 delete ctf; // expected-warning {{Destruction of a polymorphic object with no virtual destructor}} 89 // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} 90 } 91 deleteThroughFunction()92void deleteThroughFunction() { 93 NonVirtual *dtf = new NVDerived(); // expected-note{{Conversion from derived to base happened here}} 94 sink(dtf); // expected-note{{Calling 'sink'}} 95 } 96 singleCastCStyle()97void singleCastCStyle() { 98 NVDerived *sccs = new NVDerived(); 99 NonVirtual *sccs2 = (NonVirtual*)sccs; // expected-note{{Conversion from derived to base happened here}} 100 delete sccs2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} 101 // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} 102 } 103 doubleCastCStyle()104void doubleCastCStyle() { 105 NonVirtual *dccs = new NVDerived(); 106 NVDerived *dccs2 = (NVDerived*)dccs; 107 dccs = (NonVirtual*)dccs2; // expected-note{{Conversion from derived to base happened here}} 108 delete dccs; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} 109 // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} 110 } 111 singleCast()112void singleCast() { 113 NVDerived *sc = new NVDerived(); 114 NonVirtual *sc2 = reinterpret_cast<NonVirtual*>(sc); // expected-note{{Conversion from derived to base happened here}} 115 delete sc2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} 116 // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} 117 } 118 doubleCast()119void doubleCast() { 120 NonVirtual *dd = new NVDerived(); 121 NVDerived *dd2 = reinterpret_cast<NVDerived*>(dd); 122 dd = reinterpret_cast<NonVirtual*>(dd2); // expected-note {{Conversion from derived to base happened here}} 123 delete dd; // expected-warning {{Destruction of a polymorphic object with no virtual destructor}} 124 // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} 125 } 126 implicitNV()127void implicitNV() { 128 ImplicitNV *invd = new ImplicitNVDerived(); // expected-note{{Conversion from derived to base happened here}} 129 delete invd; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} 130 // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} 131 } 132 doubleDecl()133void doubleDecl() { 134 ImplicitNV *dd1, *dd2; 135 dd1 = new ImplicitNVDerived(); // expected-note{{Conversion from derived to base happened here}} 136 delete dd1; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} 137 // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} 138 } 139 virtualBase()140void virtualBase() { 141 Virtual *vb = new VDerived(); 142 delete vb; // no-warning 143 } 144 notDerived()145void notDerived() { 146 NonVirtual *nd = new NonVirtual(); 147 delete nd; // no-warning 148 } 149 notDerivedArr()150void notDerivedArr() { 151 NonVirtual *nda = new NonVirtual[3]; 152 delete[] nda; // no-warning 153 } 154 cast()155void cast() { 156 NonVirtual *c = new NVDerived(); 157 delete reinterpret_cast<NVDerived*>(c); // no-warning 158 } 159 deleteThroughFunction2()160void deleteThroughFunction2() { 161 NonVirtual *dtf2 = new NVDerived(); 162 sinkCast(dtf2); // no-warning 163 } 164 deleteThroughFunction3()165void deleteThroughFunction3() { 166 NVDerived *dtf3; 167 dtf3 = new NVDerived(); 168 sinkParamCast(dtf3); // no-warning 169 } 170 stackVar()171void stackVar() { 172 NonVirtual sv2; 173 delete &sv2; // no-warning 174 } 175 176 // Deleting a polymorphic object with a non-virtual dtor 177 // is not a problem if it is referenced by its precise type. 178 preciseType()179void preciseType() { 180 NVDerived *pt = new NVDerived(); 181 delete pt; // no-warning 182 } 183 privateDtor()184void privateDtor() { 185 Base *pd = new PrivateDtor(); 186 pd->destroy(); // no-warning 187 } 188