This checker reports cases where an array of polymorphic objects are deleted as their base class. Deleting an array where the array's static type is different from its dynamic type is undefined. Since the checker is similar to DeleteWithNonVirtualDtorChecker, I refactored that checker to support more detection types. This checker corresponds to the SEI Cert rule EXP51-CPP: Do not delete an array through a pointer of the incorrect type. Differential Revision: https://reviews.llvm.org/D158156
112 lines
5.4 KiB
C++
112 lines
5.4 KiB
C++
// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.ArrayDelete -std=c++11 -verify -analyzer-output=text %s
|
|
|
|
struct Base {
|
|
virtual ~Base() = default;
|
|
};
|
|
|
|
struct Derived : public Base {};
|
|
|
|
struct DoubleDerived : public Derived {};
|
|
|
|
Derived *get();
|
|
|
|
Base *create() {
|
|
Base *b = new Derived[3]; // expected-note{{Casting from 'Derived' to 'Base' here}}
|
|
return b;
|
|
}
|
|
|
|
void sink(Base *b) {
|
|
delete[] b; // expected-warning{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}}
|
|
// expected-note@-1{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}}
|
|
}
|
|
|
|
void sink_cast(Base *b) {
|
|
delete[] static_cast<Derived*>(b); // no-warning
|
|
}
|
|
|
|
void sink_derived(Derived *d) {
|
|
delete[] d; // no-warning
|
|
}
|
|
|
|
void same_function() {
|
|
Base *sd = new Derived[10]; // expected-note{{Casting from 'Derived' to 'Base' here}}
|
|
delete[] sd; // expected-warning{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}}
|
|
// expected-note@-1{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}}
|
|
|
|
Base *dd = new DoubleDerived[10]; // expected-note{{Casting from 'DoubleDerived' to 'Base' here}}
|
|
delete[] dd; // expected-warning{{Deleting an array of 'DoubleDerived' objects as their base class 'Base' is undefined}}
|
|
// expected-note@-1{{Deleting an array of 'DoubleDerived' objects as their base class 'Base' is undefined}}
|
|
}
|
|
|
|
void different_function() {
|
|
Base *assigned = get(); // expected-note{{Casting from 'Derived' to 'Base' here}}
|
|
delete[] assigned; // expected-warning{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}}
|
|
// expected-note@-1{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}}
|
|
|
|
Base *indirect;
|
|
indirect = get(); // expected-note{{Casting from 'Derived' to 'Base' here}}
|
|
delete[] indirect; // expected-warning{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}}
|
|
// expected-note@-1{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}}
|
|
|
|
Base *created = create(); // expected-note{{Calling 'create'}}
|
|
// expected-note@-1{{Returning from 'create'}}
|
|
delete[] created; // expected-warning{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}}
|
|
// expected-note@-1{{Deleting an array of 'Derived' objects as their base class 'Base' is undefined}}
|
|
|
|
Base *sb = new Derived[10]; // expected-note{{Casting from 'Derived' to 'Base' here}}
|
|
sink(sb); // expected-note{{Calling 'sink'}}
|
|
}
|
|
|
|
void safe_function() {
|
|
Derived *d = new Derived[10];
|
|
delete[] d; // no-warning
|
|
|
|
Base *b = new Derived[10];
|
|
delete[] static_cast<Derived*>(b); // no-warning
|
|
|
|
Base *sb = new Derived[10];
|
|
sink_cast(sb); // no-warning
|
|
|
|
Derived *sd = new Derived[10];
|
|
sink_derived(sd); // no-warning
|
|
}
|
|
|
|
void multiple_derived() {
|
|
Base *b = new DoubleDerived[10]; // expected-note{{Casting from 'DoubleDerived' to 'Base' here}}
|
|
delete[] b; // expected-warning{{Deleting an array of 'DoubleDerived' objects as their base class 'Base' is undefined}}
|
|
// expected-note@-1{{Deleting an array of 'DoubleDerived' objects as their base class 'Base' is undefined}}
|
|
|
|
Base *b2 = new DoubleDerived[10]; // expected-note{{Casting from 'DoubleDerived' to 'Base' here}}
|
|
Derived *d2 = static_cast<Derived*>(b2); // expected-note{{Casting from 'Base' to 'Derived' here}}
|
|
delete[] d2; // expected-warning{{Deleting an array of 'DoubleDerived' objects as their base class 'Derived' is undefined}}
|
|
// expected-note@-1{{Deleting an array of 'DoubleDerived' objects as their base class 'Derived' is undefined}}
|
|
|
|
Derived *d3 = new DoubleDerived[10]; // expected-note{{Casting from 'DoubleDerived' to 'Derived' here}}
|
|
Base *b3 = d3; // expected-note{{Casting from 'Derived' to 'Base' here}}
|
|
delete[] b3; // expected-warning{{Deleting an array of 'DoubleDerived' objects as their base class 'Base' is undefined}}
|
|
// expected-note@-1{{Deleting an array of 'DoubleDerived' objects as their base class 'Base' is undefined}}
|
|
|
|
Base *b4 = new DoubleDerived[10];
|
|
Derived *d4 = static_cast<Derived*>(b4);
|
|
DoubleDerived *dd4 = static_cast<DoubleDerived*>(d4);
|
|
delete[] dd4; // no-warning
|
|
|
|
Base *b5 = new DoubleDerived[10]; // expected-note{{Casting from 'DoubleDerived' to 'Base' here}}
|
|
DoubleDerived *dd5 = static_cast<DoubleDerived*>(b5); // expected-note{{Casting from 'Base' to 'DoubleDerived' here}}
|
|
Derived *d5 = dd5; // expected-note{{Casting from 'DoubleDerived' to 'Derived' here}}
|
|
delete[] d5; // expected-warning{{Deleting an array of 'DoubleDerived' objects as their base class 'Derived' is undefined}}
|
|
// expected-note@-1{{Deleting an array of 'DoubleDerived' objects as their base class 'Derived' is undefined}}
|
|
}
|
|
|
|
void unrelated_casts() {
|
|
Base *b = new DoubleDerived[10]; // expected-note{{Casting from 'DoubleDerived' to 'Base' here}}
|
|
Base &b2 = *b; // no-note: See the FIXME.
|
|
|
|
// FIXME: Displaying casts of reference types is not supported.
|
|
Derived &d2 = static_cast<Derived&>(b2); // no-note: See the FIXME.
|
|
|
|
Derived *d = &d2; // no-note: See the FIXME.
|
|
delete[] d; // expected-warning{{Deleting an array of 'DoubleDerived' objects as their base class 'Derived' is undefined}}
|
|
// expected-note@-1{{Deleting an array of 'DoubleDerived' objects as their base class 'Derived' is undefined}}
|
|
}
|