...
Do not attempt to cast through a pointer to an object of incomplete type. The cast operation itself is well-formed, but dereferencing the resulting pointer may result in undefined behavior if the downcast is unable to adjust for multiple inheritance.
Noncompliant Code Example
In this noncompliant code example, a class attempts to implement the pimpl idiom, but deletes a pointer to an incomplete class type, resulting in undefined behavior if Body
has a nontrivial destructor:
Code Block | ||||
---|---|---|---|---|
| ||||
class Handle { class Body *Impl; // Declaration of a pointer to an incomplete class. public: ~Handle() { delete Impl; } // Deletion of pointer to an incomplete class. // ... }; |
Compliant Solution (delete
)
In this compliant solution, the deletion of Impl
is moved to a part of the code where Body
is defined:
Code Block | ||||
---|---|---|---|---|
| ||||
class Handle { class Body *Impl; // Declaration of a pointer to an incomplete class. public: ~Handle(); // ... }; // Elsewhere. class Body { /* ... */ }; Handle::~Handle() { delete Impl; } |
Compliant Solution (std::shared_ptr
)
In this compliant solution, a std::shared_ptr
is used to own the memory to Impl
. Note that a std::shared_ptr
is capable of referring to an incomplete type, but a std::unique_ptr
is not.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <memory> class Handle { std::shared_ptr<class Body> Impl; public: Handle(); ~Handle() {} // ... }; |
Noncompliant Code Example
Pointer downcasting (casting a pointer to a base class into a pointer to a derived class) may require adjusting the address of the pointer by a fixed amount that can only be determined when the layout of the class inheritance structure is known. In this noncompliant code example, f()
retrieves a polymorphic pointer of complete type B
from getD()
. That pointer is then cast to a pointer of incomplete type, D
, before being passed to g()
. Casting to a pointer to the derived class may fail to properly adjust the resulting pointer, resulting in undefined behavior when the pointer is dereferenced by calling d->doSomething()
.
...
Similarly unexpected values are printed when the example is run in Microsoft Visual Studio 2013 and GCC 4.9.0.
Compliant Solution
This compliant solution assumes that the intent is to hide implementation details by using incomplete class types. Instead of requiring a D *
to be passed to g()
, it expects a B *
type instead:
Code Block | ||||
---|---|---|---|---|
| ||||
// File1.h class B { protected: double d; public: B() : d(1.0) {} }; // File2.h void g(class B *); // Accepts a B object, expects a D object class B *getD(); // Returns a D object // File1.cpp #include "File1.h" #include "File2.h" void f() { B *v = getD(); g(v); } // File2.cpp #include "File2.h" #include "File1.h" #include <iostream> class Hah { protected: short s; public: Hah() : s(12) {} }; class D : public Hah, public B { float f; public: D() : Hah(), B(), f(1.2f) {} void doSomething() { std::cout << "f: " << f << ", d: " << d << ", s: " << s << std::endl; } }; void g(B *d) { D *t = static_cast<D *>(d); if (t) { t->doSomething(); } else { // Handle error. } } B *getD() { return new D; } |
Risk Assessment
Casting pointers or references to incomplete classes can result in bad addresses. Deleting a pointer to an incomplete class results in undefined behavior if the class has a non-trivial destructor. This can result in program termination, a runtime signal, or resource leaks.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
EXP39-CPP | Medium | Unlikely | Medium | P4 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Coverity | 6.5 | DELETE_VOID | Fully Implemented | ||||||
Clang |
| -Wdelete-incomplete |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
Bibliography
[ISO/IEC 14882-2014] | 5.3.5, "Delete" |
[Sutter 00] | "Compiler Firewalls and the Pimpl Idiom" |
[Dewhurst 03] | Gotcha 39, "Casting Incomplete Types" |
...