Skip to content

Commit eccc416

Browse files
committed
Rule 23.11.1 - UseSmarPtrFactoryFunctions.ql
A new query to report uses of the raw pointer constructors of the std::unique_ptr and std::shared_ptr classes. [a]
1 parent efa017f commit eccc416

File tree

5 files changed

+129
-0
lines changed

5 files changed

+129
-0
lines changed

cpp/common/test/includes/standard-library/memory.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class unique_ptr {
2323
unique_ptr(T *ptr) {}
2424
unique_ptr(const unique_ptr<T> &t) = delete;
2525
unique_ptr(unique_ptr<T> &&t) {}
26+
unique_ptr(pointer p, Deleter d) noexcept {}
2627
~unique_ptr() {}
2728
T &operator*() const { return *ptr; }
2829
T *operator->() const noexcept { return ptr; }
@@ -93,8 +94,10 @@ template <typename T> class shared_ptr : public __shared_ptr<T> {
9394
shared_ptr(T *ptr);
9495
shared_ptr(const shared_ptr<T> &r) noexcept;
9596
template <class Y> shared_ptr(const shared_ptr<Y> &r) noexcept;
97+
template <class Y> shared_ptr(const shared_ptr<Y> &r, T *p) noexcept;
9698
shared_ptr(shared_ptr<T> &&r) noexcept;
9799
template <class Y> shared_ptr(shared_ptr<Y> &&r) noexcept;
100+
template <class D> shared_ptr(T *p, D d);
98101
shared_ptr(unique_ptr<T> &&t) {}
99102
~shared_ptr() {}
100103
T &operator*() const noexcept;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* @id cpp/misra/use-smart-ptr-factory-functions
3+
* @name RULE-23-11-1: The raw pointer constructors of std::shared_ptr and std::unique_ptr should not be used
4+
* @description Using raw pointer constructors of std::shared_ptr and std::unique_ptr instead of
5+
* make_shared/make_unique can lead to memory leaks if exceptions occur during
6+
* construction.
7+
* @kind problem
8+
* @precision very-high
9+
* @problem.severity error
10+
* @tags external/misra/id/rule-23-11-1
11+
* scope/single-translation-unit
12+
* external/misra/enforcement/decidable
13+
* external/misra/obligation/advisory
14+
*/
15+
16+
import cpp
17+
import codingstandards.cpp.misra
18+
19+
from ConstructorCall call, Class smartPtrClass
20+
where
21+
not isExcluded(call, BannedAPIsPackage::useSmartPtrFactoryFunctionsQuery()) and
22+
smartPtrClass = call.getTarget().getDeclaringType() and
23+
(
24+
smartPtrClass.hasQualifiedName("std", "shared_ptr") or
25+
smartPtrClass.hasQualifiedName("std", "unique_ptr")
26+
) and
27+
call.getNumberOfArguments() >= 1 and
28+
exists(Type argType |
29+
argType = call.getArgument(0).getType().getUnspecifiedType() and
30+
argType instanceof PointerType
31+
)
32+
select call, "Use of raw pointer constructor for 'std::" + smartPtrClass.getSimpleName() + "'."
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
| test.cpp:23:25:23:27 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. |
2+
| test.cpp:28:25:28:27 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. |
3+
| test.cpp:34:3:34:32 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. |
4+
| test.cpp:40:3:40:32 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. |
5+
| test.cpp:46:6:46:32 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. |
6+
| test.cpp:47:6:47:32 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. |
7+
| test.cpp:57:27:57:29 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. |
8+
| test.cpp:67:25:67:31 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. |
9+
| test.cpp:74:39:74:45 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#include <cstdint>
2+
#include <memory>
3+
4+
struct A {
5+
std::int8_t i;
6+
};
7+
8+
class B {};
9+
10+
void test_make_shared_compliant() {
11+
auto p = std::make_shared<A>(); // COMPLIANT
12+
std::int8_t *pi = &(p->i);
13+
std::shared_ptr<std::int8_t> q(
14+
p, pi); // COMPLIANT - aliasing constructor, not taking ownership
15+
}
16+
17+
void test_make_unique_compliant() {
18+
auto p = std::make_unique<A>(); // COMPLIANT
19+
}
20+
21+
void test_raw_pointer_shared_ptr_non_compliant() {
22+
A *l1 = new A();
23+
std::shared_ptr<A> l2(l1); // NON_COMPLIANT
24+
}
25+
26+
void test_raw_pointer_unique_ptr_non_compliant() {
27+
A *l1 = new A();
28+
std::unique_ptr<A> l2(l1); // NON_COMPLIANT
29+
}
30+
31+
auto test_exception_safety_issue() {
32+
auto *l1 = new A();
33+
auto l2 = std::make_unique<A>(); // may throw
34+
return std::shared_ptr<A>(l1); // NON_COMPLIANT - memory leak
35+
// if make_unique throws
36+
}
37+
38+
auto test_double_delete_issue(std::unique_ptr<A> p) {
39+
auto l1 = p.get();
40+
return std::unique_ptr<A>(l1); // NON_COMPLIANT - causes double delete
41+
}
42+
43+
void f1(std::shared_ptr<A> a, std::shared_ptr<B> b);
44+
45+
void test_function_argument_non_compliant() {
46+
f1(std::shared_ptr<A>(new A()), // NON_COMPLIANT
47+
std::shared_ptr<B>(new B())); // NON_COMPLIANT
48+
}
49+
50+
void test_function_argument_compliant() {
51+
f1(std::make_shared<A>(), // COMPLIANT
52+
std::make_shared<B>()); // COMPLIANT
53+
}
54+
55+
void test_array_raw_pointer_non_compliant() {
56+
A *l1 = new A[10];
57+
std::unique_ptr<A[]> l2(l1); // NON_COMPLIANT
58+
}
59+
60+
void test_array_make_unique_compliant() {
61+
auto l1 = std::make_unique<A[]>(10); // COMPLIANT
62+
}
63+
64+
void test_custom_deleter_shared_ptr() {
65+
A *l1 = new A();
66+
auto l2 = [](A *p) { delete p; };
67+
std::shared_ptr<A> l3(l1, l2); // NON_COMPLIANT - still
68+
// using raw pointer constructor
69+
}
70+
71+
void test_custom_deleter_unique_ptr() {
72+
A *l1 = new A();
73+
auto l2 = [](A *p) { delete p; };
74+
std::unique_ptr<A, decltype(l2)> l3(l1, l2); // NON_COMPLIANT - still
75+
// using raw pointer constructor
76+
}
77+
78+
void test_nullptr_shared_ptr() {
79+
std::shared_ptr<A> l1(nullptr); // COMPLIANT - no ownership taken
80+
}
81+
82+
void test_nullptr_unique_ptr() {
83+
std::unique_ptr<A> l1(nullptr); // COMPLIANT - no ownership taken
84+
}

0 commit comments

Comments
 (0)