Skip to content

Commit 5687a7b

Browse files
committed
RULE-8-2-8 - PointerToIntegralCast
Detects pointer-to-integral casts that use types other than std::uintptr_t or std::intptr_t, which may not guarantee representation of all pointer values. [a]
1 parent 03a6499 commit 5687a7b

File tree

4 files changed

+124
-0
lines changed

4 files changed

+124
-0
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* @id cpp/misra/pointer-to-integral-cast
3+
* @name RULE-8-2-8: An object pointer type shall not be cast to an integral type other than std::uintptr_t or
4+
* @description Casting object pointers to integral types other than std::uintptr_t or std::intptr_t
5+
* can lead to implementation-defined behavior and potential loss of pointer
6+
* information.
7+
* @kind problem
8+
* @precision very-high
9+
* @problem.severity error
10+
* @tags external/misra/id/rule-8-2-8
11+
* scope/single-translation-unit
12+
* external/misra/enforcement/decidable
13+
* external/misra/obligation/required
14+
*/
15+
16+
import cpp
17+
import codingstandards.cpp.misra
18+
19+
from ReinterpretCast cast, Type targetType, Type sourceType
20+
where
21+
not isExcluded(cast, Conversions2Package::pointerToIntegralCastQuery()) and
22+
sourceType = cast.getExpr().getType().getUnspecifiedType() and
23+
sourceType instanceof PointerType and
24+
targetType = cast.getType() and
25+
targetType.getUnspecifiedType() instanceof IntegralType and
26+
not (
27+
targetType.(UserType).hasGlobalOrStdName("uintptr_t") or
28+
targetType.(UserType).hasGlobalOrStdName("intptr_t")
29+
)
30+
select cast,
31+
"Cast of object pointer type to integral type '" + targetType.toString() +
32+
"' instead of 'std::uintptr_t' or 'std::intptr_t'."
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
| test.cpp:37:13:37:47 | reinterpret_cast<unsigned long>... | Cast of object pointer type to integral type 'unsigned long' instead of 'std::uintptr_t' or 'std::intptr_t'. |
2+
| test.cpp:42:13:42:46 | reinterpret_cast<unsigned int>... | Cast of object pointer type to integral type 'unsigned int' instead of 'std::uintptr_t' or 'std::intptr_t'. |
3+
| test.cpp:47:13:47:38 | reinterpret_cast<long>... | Cast of object pointer type to integral type 'long' instead of 'std::uintptr_t' or 'std::intptr_t'. |
4+
| test.cpp:52:13:52:45 | reinterpret_cast<size_t>... | Cast of object pointer type to integral type 'size_t' instead of 'std::uintptr_t' or 'std::intptr_t'. |
5+
| test.cpp:57:13:57:43 | reinterpret_cast<hashPtr_t>... | Cast of object pointer type to integral type 'hashPtr_t' instead of 'std::uintptr_t' or 'std::intptr_t'. |
6+
| test.cpp:62:13:62:42 | reinterpret_cast<MyIntPtr>... | Cast of object pointer type to integral type 'MyIntPtr' instead of 'std::uintptr_t' or 'std::intptr_t'. |
7+
| test.cpp:67:13:67:35 | reinterpret_cast<unsigned long>... | Cast of object pointer type to integral type 'unsigned long' instead of 'std::uintptr_t' or 'std::intptr_t'. |
8+
| test.cpp:72:13:72:47 | reinterpret_cast<uint64_t>... | Cast of object pointer type to integral type 'uint64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. |
9+
| test.cpp:77:13:77:46 | reinterpret_cast<int64_t>... | Cast of object pointer type to integral type 'int64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-8-2-8/PointerToIntegralCast.ql
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#include <cstddef>
2+
#include <cstdint>
3+
struct S {};
4+
class C {};
5+
6+
void *g1 = nullptr;
7+
S *g2 = nullptr;
8+
const int *g3 = nullptr;
9+
10+
using hashPtr_t = std::uintptr_t;
11+
using MyIntPtr = std::intptr_t;
12+
13+
void test_compliant_uintptr_t_cast() {
14+
S *l1 = nullptr;
15+
auto l2 = reinterpret_cast<std::uintptr_t>(l1); // COMPLIANT
16+
}
17+
18+
void test_compliant_intptr_t_cast() {
19+
C *l1 = nullptr;
20+
auto l2 = reinterpret_cast<std::intptr_t>(l1); // COMPLIANT
21+
}
22+
23+
void test_compliant_void_pointer_cast() {
24+
void *l1 = nullptr;
25+
auto l2 = reinterpret_cast<std::uintptr_t>(l1); // COMPLIANT
26+
auto l3 = reinterpret_cast<std::intptr_t>(l1); // COMPLIANT
27+
}
28+
29+
void test_compliant_const_pointer_cast() {
30+
const int *l1 = nullptr;
31+
auto l2 = reinterpret_cast<std::uintptr_t>(l1); // COMPLIANT
32+
auto l3 = reinterpret_cast<std::intptr_t>(l1); // COMPLIANT
33+
}
34+
35+
void test_non_compliant_unsigned_long_cast() {
36+
S *l1 = nullptr;
37+
auto l2 = reinterpret_cast<unsigned long>(l1); // NON_COMPLIANT
38+
}
39+
40+
void test_non_compliant_unsigned_int_cast() {
41+
S *l1 = nullptr;
42+
auto l2 = reinterpret_cast<unsigned int>(l1); // NON_COMPLIANT
43+
}
44+
45+
void test_non_compliant_long_cast() {
46+
C *l1 = nullptr;
47+
auto l2 = reinterpret_cast<long>(l1); // NON_COMPLIANT
48+
}
49+
50+
void test_non_compliant_size_t_cast() {
51+
void *l1 = nullptr;
52+
auto l2 = reinterpret_cast<std::size_t>(l1); // NON_COMPLIANT
53+
}
54+
55+
void test_non_compliant_typedef_cast() {
56+
S *l1 = nullptr;
57+
auto l2 = reinterpret_cast<hashPtr_t>(l1); // NON_COMPLIANT
58+
}
59+
60+
void test_non_compliant_using_alias_cast() {
61+
C *l1 = nullptr;
62+
auto l2 = reinterpret_cast<MyIntPtr>(l1); // NON_COMPLIANT
63+
}
64+
65+
template <typename T> void test_non_compliant_template_cast() {
66+
S *l1 = nullptr;
67+
auto l2 = reinterpret_cast<T>(l1); // NON_COMPLIANT
68+
}
69+
70+
void test_non_compliant_uint64_t_cast() {
71+
S *l1 = nullptr;
72+
auto l2 = reinterpret_cast<std::uint64_t>(l1); // NON_COMPLIANT
73+
}
74+
75+
void test_non_compliant_int64_t_cast() {
76+
void *l1 = nullptr;
77+
auto l2 = reinterpret_cast<std::int64_t>(l1); // NON_COMPLIANT
78+
}
79+
80+
void test_instantiate_template() {
81+
test_non_compliant_template_cast<std::uintptr_t>();
82+
}

0 commit comments

Comments
 (0)