...
Code Block |
---|
|
#include <memory>
struct B {
virtual ~B() = default; // Polymorphic object
// ...
};
struct D : B {};
void g(std::shared_ptr<D> Derived);
void f() {
std::shared_ptr<B> Poly(new D);
// ...
g(std::dynamic_pointer_cast<D, B>(Poly));
// Poly is still referring to a valid pointer value.
} |
Noncompliant Code Example
In this noncompliant code example, a std::shared_ptr
of type S
is constructed and stored in s1
. Later, S::g()
is called to get another shared pointer to the pointer value managed by s1
. However, the smart pointer returned by S::g()
is not related to the smart pointer stored in s1
. When s2
is destroyed, it will free the pointer managed by s1
, causing a double-free vulnerability when s1
is destroyed.
Code Block |
---|
|
#include <memory>
struct S {
std::shared_ptr<S> g() { return std::shared_ptr<S>(this); }
};
void f() {
std::shared_ptr<S> s1 = std::make_shared<S>();
// ...
std::shared_ptr<S> s2 = s1->g();
} |
Compliant Solution
The compliant solution is to use std::enable_shared_from_this::shared_from_this()
to get a shared pointer from S
that is related to an existing std::shared_ptr
object. A common implementation strategy is for the std::shared_ptr
constructors to detect the presence of a pointer that inherits from std::enable_shared_from_this
, and automatically update the internal bookkeeping required for std::enable_shared_from_this::shared_from_this()
to work.
Code Block |
---|
|
#include <memory>
struct S : std::enable_shared_from_this<S> {
std::shared_ptr<S> g() { return shared_from_this(); }
};
void f() {
std::shared_ptr<S> s1 = std::make_shared<S>();
std::shared_ptr<S> s2 = s1->g();
} |
Risk Assessment
Passing a pointer value to a deallocation function that was not previously obtained by the matching allocation function results in undefined behavior, which can lead to exploitable vulnerabilities.
...