Skip to content

Commit d2b991b

Browse files
authored
Merge pull request github#5541 from MathiasVP/definitions-for-unique_ptr
C++: Add shared_ptr and unique_ptr implementations
2 parents 2dadc75 + 09ba25f commit d2b991b

File tree

4 files changed

+212
-0
lines changed

4 files changed

+212
-0
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
2+
namespace std {
3+
namespace detail {
4+
template<typename T>
5+
class compressed_pair_element {
6+
T element;
7+
8+
public:
9+
compressed_pair_element() = default;
10+
compressed_pair_element(const T& t) : element(t) {}
11+
12+
T& get() { return element; }
13+
14+
const T& get() const { return element; }
15+
};
16+
17+
template<typename T, typename U>
18+
struct compressed_pair : private compressed_pair_element<T>, private compressed_pair_element<U> {
19+
compressed_pair() = default;
20+
compressed_pair(T& t) : compressed_pair_element<T>(t), compressed_pair_element<U>() {}
21+
compressed_pair(const compressed_pair&) = delete;
22+
compressed_pair(compressed_pair<T, U>&&) noexcept = default;
23+
24+
T& first() { return static_cast<compressed_pair_element<T>&>(*this).get(); }
25+
U& second() { return static_cast<compressed_pair_element<U>&>(*this).get(); }
26+
27+
const T& first() const { return static_cast<const compressed_pair_element<T>&>(*this).get(); }
28+
const U& second() const { return static_cast<const compressed_pair_element<U>&>(*this).get(); }
29+
};
30+
}
31+
32+
template<class T>
33+
struct default_delete {
34+
void operator()(T* ptr) const { delete ptr; }
35+
};
36+
37+
template<class T>
38+
struct default_delete<T[]> {
39+
template<class U>
40+
void operator()(U* ptr) const { delete[] ptr; }
41+
};
42+
43+
template<class T, class Deleter = default_delete<T> >
44+
class unique_ptr {
45+
private:
46+
detail::compressed_pair<T*, Deleter> data;
47+
public:
48+
constexpr unique_ptr() noexcept {}
49+
explicit unique_ptr(T* ptr) noexcept : data(ptr) {}
50+
unique_ptr(const unique_ptr& ptr) = delete;
51+
unique_ptr(unique_ptr&& ptr) noexcept = default;
52+
53+
unique_ptr& operator=(unique_ptr&& ptr) noexcept = default;
54+
55+
T& operator*() const { return *get(); }
56+
T* operator->() const noexcept { return get(); }
57+
58+
T* get() const noexcept { return data.first(); }
59+
60+
~unique_ptr() {
61+
Deleter& d = data.second();
62+
d(data.first());
63+
}
64+
};
65+
66+
template<typename T, class... Args> unique_ptr<T> make_unique(Args&&... args) {
67+
return unique_ptr<T>(new T(args...)); // std::forward calls elided for simplicity.
68+
}
69+
70+
class ctrl_block {
71+
unsigned uses;
72+
73+
public:
74+
ctrl_block() : uses(1) {}
75+
76+
void inc() { ++uses; }
77+
bool dec() { return --uses == 0; }
78+
79+
virtual void destroy() = 0;
80+
virtual ~ctrl_block() {}
81+
};
82+
83+
template<typename T, class Deleter = default_delete<T> >
84+
struct ctrl_block_impl: public ctrl_block {
85+
T* ptr;
86+
Deleter d;
87+
88+
ctrl_block_impl(T* ptr, Deleter d) : ptr(ptr), d(d) {}
89+
virtual void destroy() override { d(ptr); }
90+
};
91+
92+
template<class T>
93+
class shared_ptr {
94+
private:
95+
ctrl_block* ctrl;
96+
T* ptr;
97+
98+
void dec() {
99+
if(ctrl->dec()) {
100+
ctrl->destroy();
101+
delete ctrl;
102+
}
103+
}
104+
105+
void inc() {
106+
ctrl->inc();
107+
}
108+
109+
public:
110+
constexpr shared_ptr() noexcept = default;
111+
shared_ptr(T* ptr) : ctrl(new ctrl_block_impl<T>(ptr, default_delete<T>())) {}
112+
shared_ptr(const shared_ptr& s) noexcept : ptr(s.ptr), ctrl(s.ctrl) {
113+
inc();
114+
}
115+
shared_ptr(shared_ptr&& s) noexcept = default;
116+
117+
T* operator->() const { return ptr; }
118+
119+
T& operator*() const { return *ptr; }
120+
121+
~shared_ptr() { dec(); }
122+
};
123+
124+
template<typename T, class... Args> shared_ptr<T> make_shared(Args&&... args) {
125+
return shared_ptr<T>(new T(args...)); // std::forward calls elided for simplicity.
126+
}
127+
}

cpp/ql/test/library-tests/dataflow/smart-pointers-taint/taint.expected

Whitespace-only changes.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import TestUtilities.dataflow.FlowTestCommon
2+
3+
module ASTTest {
4+
private import semmle.code.cpp.dataflow.TaintTracking
5+
6+
class ASTSmartPointerTaintConfig extends TaintTracking::Configuration {
7+
ASTSmartPointerTaintConfig() { this = "ASTSmartPointerTaintConfig" }
8+
9+
override predicate isSource(DataFlow::Node source) {
10+
source.asExpr().(FunctionCall).getTarget().getName() = "source"
11+
}
12+
13+
override predicate isSink(DataFlow::Node sink) {
14+
exists(FunctionCall call |
15+
call.getTarget().getName() = "sink" and
16+
sink.asExpr() = call.getAnArgument()
17+
)
18+
}
19+
}
20+
}
21+
22+
module IRTest {
23+
private import semmle.code.cpp.ir.dataflow.TaintTracking
24+
25+
class IRSmartPointerTaintConfig extends TaintTracking::Configuration {
26+
IRSmartPointerTaintConfig() { this = "IRSmartPointerTaintConfig" }
27+
28+
override predicate isSource(DataFlow::Node source) {
29+
source.asExpr().(FunctionCall).getTarget().getName() = "source"
30+
}
31+
32+
override predicate isSink(DataFlow::Node sink) {
33+
exists(FunctionCall call |
34+
call.getTarget().getName() = "sink" and
35+
sink.asExpr() = call.getAnArgument()
36+
)
37+
}
38+
}
39+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include "memory.h"
2+
3+
int source();
4+
void sink(int);
5+
6+
void test_unique_ptr_int() {
7+
std::unique_ptr<int> p1(new int(source()));
8+
std::unique_ptr<int> p2 = std::make_unique<int>(source());
9+
10+
sink(*p1); // $ MISSING: ast,ir
11+
sink(*p2); // $ ast ir=8:50
12+
}
13+
14+
struct A {
15+
int x, y;
16+
17+
A(int x, int y) : x(x), y(y) {}
18+
};
19+
20+
void test_unique_ptr_struct() {
21+
std::unique_ptr<A> p1(new A{source(), 0});
22+
std::unique_ptr<A> p2 = std::make_unique<A>(source(), 0);
23+
24+
sink(p1->x); // $ MISSING: ast,ir
25+
sink(p1->y);
26+
sink(p2->x); // $ MISSING: ast,ir
27+
sink(p2->y);
28+
}
29+
30+
void test_shared_ptr_int() {
31+
std::shared_ptr<int> p1(new int(source()));
32+
std::shared_ptr<int> p2 = std::make_shared<int>(source());
33+
34+
sink(*p1); // $ ast
35+
sink(*p2); // $ ast ir=32:50
36+
}
37+
38+
void test_shared_ptr_struct() {
39+
std::shared_ptr<A> p1(new A{source(), 0});
40+
std::shared_ptr<A> p2 = std::make_shared<A>(source(), 0);
41+
42+
sink(p1->x); // $ MISSING: ast,ir
43+
sink(p1->y);
44+
sink(p2->x); // $ MISSING: ast,ir
45+
sink(p2->y);
46+
}

0 commit comments

Comments
 (0)