Skip to content

Commit fed973f

Browse files
authored
Merge pull request #4229 from MathiasVP/mathiasvp/make_shared_make_unique-models
C++: Add taint models for std::make_unique and std::make_shared
2 parents 34a03ec + bb9cf72 commit fed973f

File tree

8 files changed

+223
-0
lines changed

8 files changed

+223
-0
lines changed

change-notes/1.26/analysis-cpp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ The following changes in version 1.26 affect C/C++ analysis in all applications.
2424
* The models library now models many taint flows through `std::array`, `std::vector`, `std::deque`, `std::list` and `std::forward_list`.
2525
* The models library now models many more taint flows through `std::string`.
2626
* The models library now models some taint flows through `std::ostream`.
27+
* The models library now models some taint flows through `std::shared_ptr`, `std::unique_ptr`, `std::make_shared` and `std::make_unique`.
2728
* The `SimpleRangeAnalysis` library now supports multiplications of the form
2829
`e1 * e2` and `x *= e2` when `e1` and `e2` are unsigned or constant.

cpp/ql/src/semmle/code/cpp/models/Models.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ private import implementations.StdContainer
1818
private import implementations.StdString
1919
private import implementations.Swap
2020
private import implementations.GetDelim
21+
private import implementations.SmartPointer
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import semmle.code.cpp.models.interfaces.Taint
2+
3+
/**
4+
* The `std::shared_ptr` and `std::unique_ptr` template classes.
5+
*/
6+
class UniqueOrSharedPtr extends Class {
7+
UniqueOrSharedPtr() { this.hasQualifiedName("std", ["shared_ptr", "unique_ptr"]) }
8+
}
9+
10+
/**
11+
* The `std::make_shared` and `std::make_unique` template functions.
12+
*/
13+
class MakeUniqueOrShared extends TaintFunction {
14+
MakeUniqueOrShared() { this.hasQualifiedName("std", ["make_shared", "make_unique"]) }
15+
16+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
17+
// Exclude the specializations of `std::make_shared` and `std::make_unique` that allocate arrays
18+
// since these just take a size argument, which we don't want to propagate taint through.
19+
not this.isArray() and
20+
input.isParameter(_) and
21+
output.isReturnValue()
22+
}
23+
24+
/**
25+
* Holds if the function returns a `shared_ptr<T>` (or `unique_ptr<T>`) where `T` is an
26+
* array type (i.e., `U[]` for some type `U`).
27+
*/
28+
predicate isArray() {
29+
this.getTemplateArgument(0).(Type).getUnderlyingType() instanceof ArrayType
30+
}
31+
}
32+
33+
/**
34+
* A prefix `operator*` member function for a `shared_ptr` or `unique_ptr` type.
35+
*/
36+
class UniqueOrSharedDereferenceMemberOperator extends MemberFunction, TaintFunction {
37+
UniqueOrSharedDereferenceMemberOperator() {
38+
this.hasName("operator*") and
39+
this.getDeclaringType() instanceof UniqueOrSharedPtr
40+
}
41+
42+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
43+
input.isQualifierObject() and
44+
output.isReturnValueDeref()
45+
}
46+
}
47+
48+
/**
49+
* The `std::shared_ptr` or `std::unique_ptr` function `get`.
50+
*/
51+
class UniqueOrSharedGet extends TaintFunction {
52+
UniqueOrSharedGet() {
53+
this.hasName("get") and
54+
this.getDeclaringType() instanceof UniqueOrSharedPtr
55+
}
56+
57+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
58+
input.isQualifierObject() and
59+
output.isReturnValue()
60+
}
61+
}

cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,46 @@
439439
| movableclass.cpp:65:13:65:18 | call to source | movableclass.cpp:65:13:65:20 | call to MyMovableClass | TAINT |
440440
| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:8:65:9 | ref arg s3 | TAINT |
441441
| movableclass.cpp:65:13:65:20 | call to MyMovableClass | movableclass.cpp:65:11:65:11 | call to operator= | TAINT |
442+
| smart_pointer.cpp:11:30:11:50 | call to make_shared | smart_pointer.cpp:12:11:12:11 | p | |
443+
| smart_pointer.cpp:11:30:11:50 | call to make_shared | smart_pointer.cpp:13:10:13:10 | p | |
444+
| smart_pointer.cpp:11:52:11:57 | call to source | smart_pointer.cpp:11:30:11:50 | call to make_shared | TAINT |
445+
| smart_pointer.cpp:12:11:12:11 | p | smart_pointer.cpp:12:10:12:10 | call to operator* | TAINT |
446+
| smart_pointer.cpp:17:32:17:54 | call to make_shared | smart_pointer.cpp:18:11:18:11 | p | |
447+
| smart_pointer.cpp:17:32:17:54 | call to make_shared | smart_pointer.cpp:19:10:19:10 | p | |
448+
| smart_pointer.cpp:18:11:18:11 | p | smart_pointer.cpp:18:10:18:10 | call to operator* | TAINT |
449+
| smart_pointer.cpp:23:30:23:50 | call to make_unique | smart_pointer.cpp:24:11:24:11 | p | |
450+
| smart_pointer.cpp:23:30:23:50 | call to make_unique | smart_pointer.cpp:25:10:25:10 | p | |
451+
| smart_pointer.cpp:23:52:23:57 | call to source | smart_pointer.cpp:23:30:23:50 | call to make_unique | TAINT |
452+
| smart_pointer.cpp:24:11:24:11 | p | smart_pointer.cpp:24:10:24:10 | call to operator* | TAINT |
453+
| smart_pointer.cpp:29:32:29:54 | call to make_unique | smart_pointer.cpp:30:11:30:11 | p | |
454+
| smart_pointer.cpp:29:32:29:54 | call to make_unique | smart_pointer.cpp:31:10:31:10 | p | |
455+
| smart_pointer.cpp:30:11:30:11 | p | smart_pointer.cpp:30:10:30:10 | call to operator* | TAINT |
456+
| smart_pointer.cpp:35:30:35:50 | call to make_shared | smart_pointer.cpp:37:6:37:6 | p | |
457+
| smart_pointer.cpp:35:30:35:50 | call to make_shared | smart_pointer.cpp:38:10:38:10 | p | |
458+
| smart_pointer.cpp:35:30:35:50 | call to make_shared | smart_pointer.cpp:39:11:39:11 | p | |
459+
| smart_pointer.cpp:37:5:37:17 | ... = ... | smart_pointer.cpp:37:5:37:5 | call to operator* [post update] | |
460+
| smart_pointer.cpp:37:6:37:6 | p | smart_pointer.cpp:37:5:37:5 | call to operator* | TAINT |
461+
| smart_pointer.cpp:37:10:37:15 | call to source | smart_pointer.cpp:37:5:37:17 | ... = ... | |
462+
| smart_pointer.cpp:38:10:38:10 | ref arg p | smart_pointer.cpp:39:11:39:11 | p | |
463+
| smart_pointer.cpp:39:11:39:11 | p | smart_pointer.cpp:39:10:39:10 | call to operator* | TAINT |
464+
| smart_pointer.cpp:43:29:43:51 | call to unique_ptr | smart_pointer.cpp:45:6:45:6 | p | |
465+
| smart_pointer.cpp:43:29:43:51 | call to unique_ptr | smart_pointer.cpp:46:10:46:10 | p | |
466+
| smart_pointer.cpp:43:29:43:51 | call to unique_ptr | smart_pointer.cpp:47:11:47:11 | p | |
467+
| smart_pointer.cpp:45:5:45:17 | ... = ... | smart_pointer.cpp:45:5:45:5 | call to operator* [post update] | |
468+
| smart_pointer.cpp:45:6:45:6 | p | smart_pointer.cpp:45:5:45:5 | call to operator* | TAINT |
469+
| smart_pointer.cpp:45:10:45:15 | call to source | smart_pointer.cpp:45:5:45:17 | ... = ... | |
470+
| smart_pointer.cpp:46:10:46:10 | ref arg p | smart_pointer.cpp:47:11:47:11 | p | |
471+
| smart_pointer.cpp:47:11:47:11 | p | smart_pointer.cpp:47:10:47:10 | call to operator* | TAINT |
472+
| smart_pointer.cpp:51:30:51:50 | call to make_shared | smart_pointer.cpp:52:10:52:10 | p | |
473+
| smart_pointer.cpp:51:52:51:57 | call to source | smart_pointer.cpp:51:30:51:50 | call to make_shared | TAINT |
474+
| smart_pointer.cpp:52:10:52:10 | p | smart_pointer.cpp:52:12:52:14 | call to get | TAINT |
475+
| smart_pointer.cpp:56:30:56:50 | call to make_unique | smart_pointer.cpp:57:10:57:10 | p | |
476+
| smart_pointer.cpp:56:52:56:57 | call to source | smart_pointer.cpp:56:30:56:50 | call to make_unique | TAINT |
477+
| smart_pointer.cpp:57:10:57:10 | p | smart_pointer.cpp:57:12:57:14 | call to get | TAINT |
478+
| smart_pointer.cpp:65:28:65:46 | call to make_unique | smart_pointer.cpp:66:10:66:10 | p | |
479+
| smart_pointer.cpp:65:28:65:46 | call to make_unique | smart_pointer.cpp:67:10:67:10 | p | |
480+
| smart_pointer.cpp:65:48:65:53 | call to source | smart_pointer.cpp:65:28:65:46 | call to make_unique | TAINT |
481+
| smart_pointer.cpp:65:58:65:58 | 0 | smart_pointer.cpp:65:28:65:46 | call to make_unique | TAINT |
442482
| standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:40:11:40:17 | source1 | |
443483
| standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:41:12:41:18 | source1 | |
444484
| standalone_iterators.cpp:39:45:39:51 | source1 | standalone_iterators.cpp:42:14:42:20 | source1 | |
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include "stl.h"
2+
3+
int source();
4+
void sink(int);
5+
void sink(int*);
6+
7+
template<typename T> void sink(std::shared_ptr<T>&);
8+
template<typename T> void sink(std::unique_ptr<T>&);
9+
10+
void test_make_shared() {
11+
std::shared_ptr<int> p = std::make_shared<int>(source());
12+
sink(*p); // tainted
13+
sink(p); // tainted
14+
}
15+
16+
void test_make_shared_array() {
17+
std::shared_ptr<int[]> p = std::make_shared<int[]>(source());
18+
sink(*p); // not tainted
19+
sink(p); // not tainted
20+
}
21+
22+
void test_make_unique() {
23+
std::unique_ptr<int> p = std::make_unique<int>(source());
24+
sink(*p); // tainted
25+
sink(p); // tainted
26+
}
27+
28+
void test_make_unique_array() {
29+
std::unique_ptr<int[]> p = std::make_unique<int[]>(source());
30+
sink(*p); // not tainted
31+
sink(p); // not tainted
32+
}
33+
34+
void test_reverse_taint_shared() {
35+
std::shared_ptr<int> p = std::make_shared<int>();
36+
37+
*p = source();
38+
sink(p); // tainted [NOT DETECTED]
39+
sink(*p); // tainted [NOT DETECTED]
40+
}
41+
42+
void test_reverse_taint_unique() {
43+
std::unique_ptr<int> p = std::unique_ptr<int>();
44+
45+
*p = source();
46+
sink(p); // tainted [NOT DETECTED]
47+
sink(*p); // tainted [NOT DETECTED]
48+
}
49+
50+
void test_shared_get() {
51+
std::shared_ptr<int> p = std::make_shared<int>(source());
52+
sink(p.get()); // tainted
53+
}
54+
55+
void test_unique_get() {
56+
std::unique_ptr<int> p = std::make_unique<int>(source());
57+
sink(p.get()); // tainted
58+
}
59+
60+
struct A {
61+
int x, y;
62+
};
63+
64+
void test_shared_field_member() {
65+
std::unique_ptr<A> p = std::make_unique<A>(source(), 0);
66+
sink(p->x); // tainted [NOT DETECTED]
67+
sink(p->y); // not tainted
68+
}

cpp/ql/test/library-tests/dataflow/taint-tests/stl.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,43 @@ namespace std {
249249
void clear() noexcept;
250250
};
251251
}
252+
253+
// --- make_shared / make_unique ---
254+
255+
namespace std {
256+
template<typename T>
257+
class shared_ptr {
258+
public:
259+
shared_ptr() noexcept;
260+
explicit shared_ptr(T*);
261+
template<class U> shared_ptr(const shared_ptr<U>&) noexcept;
262+
template<class U> shared_ptr(shared_ptr<U>&&) noexcept;
263+
264+
shared_ptr<T>& operator=(const shared_ptr<T>&) noexcept;
265+
shared_ptr<T>& operator=(shared_ptr<T>&&) noexcept;
266+
267+
T& operator*() const noexcept;
268+
T* operator->() const noexcept;
269+
270+
T* get() const noexcept;
271+
};
272+
273+
template<typename T>
274+
class unique_ptr {
275+
public:
276+
constexpr unique_ptr() noexcept;
277+
explicit unique_ptr(T*) noexcept;
278+
unique_ptr(unique_ptr<T>&&) noexcept;
279+
280+
unique_ptr<T>& operator=(unique_ptr<T>&&) noexcept;
281+
282+
T& operator*() const;
283+
T* operator->() const noexcept;
284+
285+
T* get() const noexcept;
286+
};
287+
288+
template<typename T, class... Args> unique_ptr<T> make_unique(Args&&...);
289+
290+
template<typename T, class... Args> shared_ptr<T> make_shared(Args&&...);
291+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@
3737
| movableclass.cpp:55:8:55:9 | s2 | movableclass.cpp:52:23:52:28 | call to source |
3838
| movableclass.cpp:64:8:64:9 | s2 | movableclass.cpp:23:55:23:60 | call to source |
3939
| movableclass.cpp:65:11:65:11 | call to operator= | movableclass.cpp:65:13:65:18 | call to source |
40+
| smart_pointer.cpp:12:10:12:10 | call to operator* | smart_pointer.cpp:11:52:11:57 | call to source |
41+
| smart_pointer.cpp:13:10:13:10 | p | smart_pointer.cpp:11:52:11:57 | call to source |
42+
| smart_pointer.cpp:24:10:24:10 | call to operator* | smart_pointer.cpp:23:52:23:57 | call to source |
43+
| smart_pointer.cpp:25:10:25:10 | p | smart_pointer.cpp:23:52:23:57 | call to source |
44+
| smart_pointer.cpp:52:12:52:14 | call to get | smart_pointer.cpp:51:52:51:57 | call to source |
45+
| smart_pointer.cpp:57:12:57:14 | call to get | smart_pointer.cpp:56:52:56:57 | call to source |
4046
| standalone_iterators.cpp:40:10:40:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |
4147
| standalone_iterators.cpp:41:10:41:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |
4248
| standalone_iterators.cpp:42:10:42:10 | call to operator* | standalone_iterators.cpp:39:45:39:51 | source1 |

cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@
4848
| movableclass.cpp:55:8:55:9 | movableclass.cpp:52:23:52:28 | AST only |
4949
| movableclass.cpp:64:8:64:9 | movableclass.cpp:23:55:23:60 | AST only |
5050
| movableclass.cpp:65:11:65:11 | movableclass.cpp:65:13:65:18 | AST only |
51+
| smart_pointer.cpp:12:10:12:10 | smart_pointer.cpp:11:52:11:57 | AST only |
52+
| smart_pointer.cpp:13:10:13:10 | smart_pointer.cpp:11:52:11:57 | AST only |
53+
| smart_pointer.cpp:24:10:24:10 | smart_pointer.cpp:23:52:23:57 | AST only |
54+
| smart_pointer.cpp:25:10:25:10 | smart_pointer.cpp:23:52:23:57 | AST only |
55+
| smart_pointer.cpp:52:12:52:14 | smart_pointer.cpp:51:52:51:57 | AST only |
56+
| smart_pointer.cpp:57:12:57:14 | smart_pointer.cpp:56:52:56:57 | AST only |
5157
| standalone_iterators.cpp:40:10:40:10 | standalone_iterators.cpp:39:45:39:51 | AST only |
5258
| standalone_iterators.cpp:41:10:41:10 | standalone_iterators.cpp:39:45:39:51 | AST only |
5359
| standalone_iterators.cpp:42:10:42:10 | standalone_iterators.cpp:39:45:39:51 | AST only |

0 commit comments

Comments
 (0)