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()35 NonVirtual *create() {
36   NonVirtual *x = new NVDerived(); // expected-note{{Conversion from derived to base happened here}}
37   return x;
38 }
39 
sink(NonVirtual * x)40 void 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)45 void sinkCast(NonVirtual *y) {
46   delete reinterpret_cast<NVDerived*>(y);
47 }
48 
sinkParamCast(NVDerived * z)49 void sinkParamCast(NVDerived *z) {
50   delete z;
51 }
52 
singleDerived()53 void 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()60 void 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()66 void 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()72 void 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()78 void 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()85 void 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()92 void 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()97 void 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()104 void 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()112 void 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()119 void 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()127 void 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()133 void 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()140 void virtualBase() {
141   Virtual *vb = new VDerived();
142   delete vb; // no-warning
143 }
144 
notDerived()145 void notDerived() {
146   NonVirtual *nd = new NonVirtual();
147   delete nd; // no-warning
148 }
149 
notDerivedArr()150 void notDerivedArr() {
151   NonVirtual *nda = new NonVirtual[3];
152   delete[] nda; // no-warning
153 }
154 
cast()155 void cast() {
156   NonVirtual *c = new NVDerived();
157   delete reinterpret_cast<NVDerived*>(c); // no-warning
158 }
159 
deleteThroughFunction2()160 void deleteThroughFunction2() {
161   NonVirtual *dtf2 = new NVDerived();
162   sinkCast(dtf2); // no-warning
163 }
164 
deleteThroughFunction3()165 void deleteThroughFunction3() {
166   NVDerived *dtf3;
167   dtf3 = new NVDerived();
168   sinkParamCast(dtf3); // no-warning
169 }
170 
stackVar()171 void 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()179 void preciseType() {
180   NVDerived *pt = new NVDerived();
181   delete pt; // no-warning
182 }
183 
privateDtor()184 void privateDtor() {
185   Base *pd = new PrivateDtor();
186   pd->destroy(); // no-warning
187 }
188