| // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.cplusplus.DeleteWithNonVirtualDtor -std=c++11 -verify -analyzer-output=text %s | |
| struct Virtual { | |
| virtual ~Virtual() {} | |
| }; | |
| struct VDerived : public Virtual {}; | |
| struct NonVirtual { | |
| ~NonVirtual() {} | |
| }; | |
| struct NVDerived : public NonVirtual {}; | |
| struct NVDoubleDerived : public NVDerived {}; | |
| struct Base { | |
| virtual void destroy() = 0; | |
| }; | |
| class PrivateDtor final : public Base { | |
| public: | |
| void destroy() { delete this; } | |
| private: | |
| ~PrivateDtor() {} | |
| }; | |
| struct ImplicitNV { | |
| virtual void f(); | |
| }; | |
| struct ImplicitNVDerived : public ImplicitNV {}; | |
| NVDerived *get(); | |
| NonVirtual *create() { | |
| NonVirtual *x = new NVDerived(); // expected-note{{Casting from 'NVDerived' to 'NonVirtual' here}} | |
| return x; | |
| } | |
| void sink(NonVirtual *x) { | |
| delete x; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} | |
| // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} | |
| } | |
| void sinkCast(NonVirtual *y) { | |
| delete reinterpret_cast<NVDerived*>(y); | |
| } | |
| void sinkParamCast(NVDerived *z) { | |
| delete z; | |
| } | |
| void singleDerived() { | |
| NonVirtual *sd; | |
| sd = new NVDerived(); // expected-note{{Casting from 'NVDerived' to 'NonVirtual' here}} | |
| delete sd; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} | |
| // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} | |
| } | |
| void singleDerivedArr() { | |
| NonVirtual *sda = new NVDerived[5]; // expected-note{{Casting from 'NVDerived' to 'NonVirtual' here}} | |
| delete[] sda; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} | |
| // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} | |
| } | |
| void doubleDerived() { | |
| NonVirtual *dd = new NVDoubleDerived(); // expected-note{{Casting from 'NVDoubleDerived' to 'NonVirtual' here}} | |
| delete (dd); // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} | |
| // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} | |
| } | |
| void assignThroughFunction() { | |
| NonVirtual *atf = get(); // expected-note{{Casting from 'NVDerived' to 'NonVirtual' here}} | |
| delete atf; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} | |
| // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} | |
| } | |
| void assignThroughFunction2() { | |
| NonVirtual *atf2; | |
| atf2 = get(); // expected-note{{Casting from 'NVDerived' to 'NonVirtual' here}} | |
| delete atf2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} | |
| // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} | |
| } | |
| void createThroughFunction() { | |
| NonVirtual *ctf = create(); // expected-note{{Calling 'create'}} | |
| // expected-note@-1{{Returning from 'create'}} | |
| delete ctf; // expected-warning {{Destruction of a polymorphic object with no virtual destructor}} | |
| // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} | |
| } | |
| void deleteThroughFunction() { | |
| NonVirtual *dtf = new NVDerived(); // expected-note{{Casting from 'NVDerived' to 'NonVirtual' here}} | |
| sink(dtf); // expected-note{{Calling 'sink'}} | |
| } | |
| void singleCastCStyle() { | |
| NVDerived *sccs = new NVDerived(); | |
| NonVirtual *sccs2 = (NonVirtual*)sccs; // expected-note{{Casting from 'NVDerived' to 'NonVirtual' here}} | |
| delete sccs2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} | |
| // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} | |
| } | |
| void doubleCastCStyle() { | |
| NonVirtual *dccs = new NVDerived(); // expected-note{{Casting from 'NVDerived' to 'NonVirtual' here}} | |
| NVDerived *dccs2 = (NVDerived*)dccs; // expected-note{{Casting from 'NonVirtual' to 'NVDerived' here}} | |
| dccs = (NonVirtual*)dccs2; // expected-note{{Casting from 'NVDerived' to 'NonVirtual' here}} | |
| delete dccs; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} | |
| // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} | |
| } | |
| void singleCast() { | |
| NVDerived *sc = new NVDerived(); | |
| NonVirtual *sc2 = reinterpret_cast<NonVirtual*>(sc); // expected-note{{Casting from 'NVDerived' to 'NonVirtual' here}} | |
| delete sc2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} | |
| // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} | |
| } | |
| void doubleCast() { | |
| NonVirtual *dd = new NVDerived(); // expected-note {{Casting from 'NVDerived' to 'NonVirtual' here}} | |
| NVDerived *dd2 = reinterpret_cast<NVDerived*>(dd); // expected-note {{Casting from 'NonVirtual' to 'NVDerived' here}} | |
| dd = reinterpret_cast<NonVirtual*>(dd2); // expected-note {{Casting from 'NVDerived' to 'NonVirtual' here}} | |
| delete dd; // expected-warning {{Destruction of a polymorphic object with no virtual destructor}} | |
| // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} | |
| } | |
| void implicitNV() { | |
| ImplicitNV *invd = new ImplicitNVDerived(); // expected-note{{Casting from 'ImplicitNVDerived' to 'ImplicitNV' here}} | |
| delete invd; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} | |
| // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} | |
| } | |
| void doubleDecl() { | |
| ImplicitNV *dd1, *dd2; | |
| dd1 = new ImplicitNVDerived(); // expected-note{{Casting from 'ImplicitNVDerived' to 'ImplicitNV' here}} | |
| delete dd1; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}} | |
| // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}} | |
| } | |
| void virtualBase() { | |
| Virtual *vb = new VDerived(); | |
| delete vb; // no-warning | |
| } | |
| void notDerived() { | |
| NonVirtual *nd = new NonVirtual(); | |
| delete nd; // no-warning | |
| } | |
| void notDerivedArr() { | |
| NonVirtual *nda = new NonVirtual[3]; | |
| delete[] nda; // no-warning | |
| } | |
| void cast() { | |
| NonVirtual *c = new NVDerived(); | |
| delete reinterpret_cast<NVDerived*>(c); // no-warning | |
| } | |
| void deleteThroughFunction2() { | |
| NonVirtual *dtf2 = new NVDerived(); | |
| sinkCast(dtf2); // no-warning | |
| } | |
| void deleteThroughFunction3() { | |
| NVDerived *dtf3; | |
| dtf3 = new NVDerived(); | |
| sinkParamCast(dtf3); // no-warning | |
| } | |
| void stackVar() { | |
| NonVirtual sv2; | |
| delete &sv2; // no-warning | |
| } | |
| // Deleting a polymorphic object with a non-virtual dtor | |
| // is not a problem if it is referenced by its precise type. | |
| void preciseType() { | |
| NVDerived *pt = new NVDerived(); | |
| delete pt; // no-warning | |
| } | |
| void privateDtor() { | |
| Base *pd = new PrivateDtor(); | |
| pd->destroy(); // no-warning | |
| } |