1 | // RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.DeleteWithNonVirtualDtor -std=c++11 -verify -analyzer-output=text %s |
2 | |
3 | struct Virtual { |
4 | virtual ~Virtual() {} |
5 | }; |
6 | |
7 | struct VDerived : public Virtual {}; |
8 | |
9 | struct NonVirtual { |
10 | ~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: |
22 | void destroy() { delete this; } |
23 | private: |
24 | ~PrivateDtor() {} |
25 | }; |
26 | |
27 | struct ImplicitNV { |
28 | virtual void f(); |
29 | }; |
30 | |
31 | struct ImplicitNVDerived : public ImplicitNV {}; |
32 | |
33 | NVDerived *get(); |
34 | |
35 | NonVirtual *create() { |
36 | NonVirtual *x = new NVDerived(); // expected-note{{Conversion from derived to base happened here}} |
37 | return x; |
38 | } |
39 | |
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 | |
45 | void sinkCast(NonVirtual *y) { |
46 | delete reinterpret_cast<NVDerived*>(y); |
47 | } |
48 | |
49 | void sinkParamCast(NVDerived *z) { |
50 | delete z; |
51 | } |
52 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
140 | void virtualBase() { |
141 | Virtual *vb = new VDerived(); |
142 | delete vb; // no-warning |
143 | } |
144 | |
145 | void notDerived() { |
146 | NonVirtual *nd = new NonVirtual(); |
147 | delete nd; // no-warning |
148 | } |
149 | |
150 | void notDerivedArr() { |
151 | NonVirtual *nda = new NonVirtual[3]; |
152 | delete[] nda; // no-warning |
153 | } |
154 | |
155 | void cast() { |
156 | NonVirtual *c = new NVDerived(); |
157 | delete reinterpret_cast<NVDerived*>(c); // no-warning |
158 | } |
159 | |
160 | void deleteThroughFunction2() { |
161 | NonVirtual *dtf2 = new NVDerived(); |
162 | sinkCast(dtf2); // no-warning |
163 | } |
164 | |
165 | void deleteThroughFunction3() { |
166 | NVDerived *dtf3; |
167 | dtf3 = new NVDerived(); |
168 | sinkParamCast(dtf3); // no-warning |
169 | } |
170 | |
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 | |
179 | void preciseType() { |
180 | NVDerived *pt = new NVDerived(); |
181 | delete pt; // no-warning |
182 | } |
183 | |
184 | void privateDtor() { |
185 | Base *pd = new PrivateDtor(); |
186 | pd->destroy(); // no-warning |
187 | } |
188 | |