mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 18:06:05 +00:00

The checker finds a type of undefined behavior, where if the type of a pointer to an object-array is different from the objects' underlying type, calling `delete[]` is undefined, as the size of the two objects might be different. The checker has been in alpha for a while now, it is a simple checker that causes no crashes, and considering the severity of the issue, it has a low result-count on open-source projects (in my last test-run on my usual projects, it had 0 results). This commit cleans up the documentation and adds docs for the limitation related to tracking through references, in addition to moving it to `cplusplus`. --------- Co-authored-by: Balazs Benics <benicsbalazs@gmail.com> Co-authored-by: whisperity <whisperity@gmail.com>
112 lines
5.4 KiB
C++
112 lines
5.4 KiB
C++
// RUN: %clang_cc1 -analyze -analyzer-checker=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}}
|
|
}
|