Skip to content

Commit 11ca8b3

Browse files
committed
RULE-8-2-6 - IntToPointerCastProhibited
Detects casts from integral, enumerated, or void pointer types to object pointer types that may lead to unspecified behavior. [a]
1 parent 6b24e50 commit 11ca8b3

File tree

4 files changed

+145
-0
lines changed

4 files changed

+145
-0
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* @id cpp/misra/int-to-pointer-cast-prohibited
3+
* @name RULE-8-2-6: An object with integral, enumerated, or pointer to void type shall not be cast to a pointer type
4+
* @description Casting from an integral type, enumerated type, or pointer to void type to a pointer
5+
* type leads to unspecified behavior and is error prone.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-8-2-6
10+
* scope/single-translation-unit
11+
* external/misra/enforcement/decidable
12+
* external/misra/obligation/required
13+
*/
14+
15+
import cpp
16+
import codingstandards.cpp.misra
17+
18+
from Cast cast, Type sourceType, Type targetType
19+
where
20+
not isExcluded(cast, Conversions2Package::intToPointerCastProhibitedQuery()) and
21+
sourceType = cast.getExpr().getType().stripTopLevelSpecifiers() and
22+
targetType = cast.getType().stripTopLevelSpecifiers() and
23+
targetType instanceof PointerType and
24+
not targetType instanceof FunctionPointerType and
25+
not (
26+
// Exception: casts between void pointers are allowed
27+
targetType.(PointerType).getBaseType().stripTopLevelSpecifiers() instanceof VoidType and
28+
sourceType instanceof PointerType and
29+
sourceType.(PointerType).getBaseType().stripTopLevelSpecifiers() instanceof VoidType
30+
) and
31+
(
32+
// Integral types
33+
sourceType instanceof IntegralType
34+
or
35+
// Enumerated types
36+
sourceType instanceof Enum
37+
or
38+
// Pointer to void type
39+
sourceType instanceof PointerType and
40+
sourceType.(PointerType).getBaseType().stripTopLevelSpecifiers() instanceof VoidType
41+
)
42+
select cast,
43+
"Cast from '" + sourceType.toString() + "' to '" + targetType.toString() + "' is prohibited."
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
| test.cpp:15:20:15:53 | reinterpret_cast<TestStruct *>... | Cast from 'signed int' to 'TestStruct *' is prohibited. |
2+
| test.cpp:16:20:16:53 | reinterpret_cast<TestStruct *>... | Cast from 'signed long' to 'TestStruct *' is prohibited. |
3+
| test.cpp:17:22:17:57 | reinterpret_cast<int32_t *>... | Cast from 'signed long' to 'int32_t *' is prohibited. |
4+
| test.cpp:24:20:24:53 | reinterpret_cast<TestStruct *>... | Cast from 'TestEnum' to 'TestStruct *' is prohibited. |
5+
| test.cpp:25:22:25:57 | reinterpret_cast<int32_t *>... | Cast from 'TestEnum' to 'int32_t *' is prohibited. |
6+
| test.cpp:32:20:32:48 | static_cast<TestStruct *>... | Cast from 'void *' to 'TestStruct *' is prohibited. |
7+
| test.cpp:33:20:33:53 | reinterpret_cast<TestStruct *>... | Cast from 'void *' to 'TestStruct *' is prohibited. |
8+
| test.cpp:34:22:34:52 | static_cast<int32_t *>... | Cast from 'void *' to 'int32_t *' is prohibited. |
9+
| test.cpp:35:22:35:57 | reinterpret_cast<int32_t *>... | Cast from 'void *' to 'int32_t *' is prohibited. |
10+
| test.cpp:43:14:43:41 | reinterpret_cast<void *>... | Cast from 'signed int' to 'void *' is prohibited. |
11+
| test.cpp:44:14:44:41 | reinterpret_cast<void *>... | Cast from 'signed long' to 'void *' is prohibited. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-8-2-6/IntToPointerCastProhibited.ql
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#include <cstdint>
2+
3+
struct TestStruct {
4+
std::int32_t m1;
5+
std::int32_t m2;
6+
};
7+
8+
enum TestEnum { VALUE1, VALUE2 };
9+
10+
void test_integral_to_pointer_cast() {
11+
std::int32_t l1 = 42;
12+
std::int64_t l2 = 0x1000;
13+
14+
// Casting integral types to pointer types
15+
TestStruct *l4 = reinterpret_cast<TestStruct *>(l1); // NON_COMPLIANT
16+
TestStruct *l5 = reinterpret_cast<TestStruct *>(l2); // NON_COMPLIANT
17+
std::int32_t *l7 = reinterpret_cast<std::int32_t *>(l2); // NON_COMPLIANT
18+
}
19+
20+
void test_enumerated_to_pointer_cast() {
21+
TestEnum l1 = VALUE1;
22+
23+
// Casting enumerated types to pointer types
24+
TestStruct *l3 = reinterpret_cast<TestStruct *>(l1); // NON_COMPLIANT
25+
std::int32_t *l5 = reinterpret_cast<std::int32_t *>(l1); // NON_COMPLIANT
26+
}
27+
28+
void test_void_pointer_to_object_pointer_cast() {
29+
void *l1 = nullptr;
30+
31+
// Casting void pointer to object pointer types
32+
TestStruct *l2 = static_cast<TestStruct *>(l1); // NON_COMPLIANT
33+
TestStruct *l3 = reinterpret_cast<TestStruct *>(l1); // NON_COMPLIANT
34+
std::int32_t *l4 = static_cast<std::int32_t *>(l1); // NON_COMPLIANT
35+
std::int32_t *l5 = reinterpret_cast<std::int32_t *>(l1); // NON_COMPLIANT
36+
}
37+
38+
void test_integral_to_void_pointer_cast() {
39+
std::int32_t l1 = 42;
40+
std::int64_t l2 = 0x1000;
41+
42+
// Casting integral types to void pointer
43+
void *l3 = reinterpret_cast<void *>(l1); // NON_COMPLIANT
44+
void *l4 = reinterpret_cast<void *>(l2); // NON_COMPLIANT
45+
}
46+
47+
void test_compliant_void_pointer_casts() {
48+
void *l1 = nullptr;
49+
const void *l2 = nullptr;
50+
51+
// Casts between void pointers are allowed
52+
const void *l3 = const_cast<const void *>(l1); // COMPLIANT
53+
void *l4 = const_cast<void *>(l2); // COMPLIANT
54+
volatile void *l5 = static_cast<volatile void *>(l1); // COMPLIANT
55+
}
56+
57+
void f1() {}
58+
void f2(int) {}
59+
60+
void test_compliant_function_pointer_exceptions() {
61+
std::int64_t l1 = 0x1000;
62+
63+
// Function pointer casts are exceptions to this rule
64+
void (*l2)() = reinterpret_cast<void (*)()>(l1); // COMPLIANT
65+
void (*l3)(int) = reinterpret_cast<void (*)(int)>(l1); // COMPLIANT
66+
}
67+
68+
struct TestClass {
69+
void memberFunc();
70+
std::int32_t m1;
71+
};
72+
73+
void test_compliant_member_function_pointer_exceptions() {
74+
void *l1 = nullptr;
75+
76+
// Member function pointer casts are technically exceptions to this rule, but
77+
// are prohibited by the compiler.
78+
// void (TestClass::*l2)() =
79+
// reinterpret_cast<void (TestClass::*)()>(l1); // COMPLIANT
80+
}
81+
82+
void test_compliant_regular_pointer_operations() {
83+
TestStruct l1;
84+
TestStruct *l2 = &l1;
85+
std::int32_t *l3 = &l1.m1;
86+
87+
// Regular pointer operations that don't involve forbidden casts
88+
TestStruct *l4 = l2; // COMPLIANT
89+
std::int32_t *l5 = l3; // COMPLIANT
90+
}

0 commit comments

Comments
 (0)