Skip to content

Commit 6bce7f8

Browse files
committed
Rule 8.2.8: Handle results in templates per rule
1 parent 1d0736e commit 6bce7f8

File tree

3 files changed

+82
-21
lines changed

3 files changed

+82
-21
lines changed

cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,55 @@ import cpp
1717
import codingstandards.cpp.misra
1818
import codingstandards.cpp.types.Type
1919

20-
from ReinterpretCast cast, PointerType sourceType, Type targetType
20+
class InvalidReinterpretCast extends ReinterpretCast {
21+
InvalidReinterpretCast() {
22+
this.getExpr().getType().stripTopLevelSpecifiers() instanceof PointerType and
23+
this.getType().getUnspecifiedType() instanceof IntegralType and
24+
not stripSpecifiers(this.getType()).(UserType).hasGlobalOrStdName(["uintptr_t", "intptr_t"])
25+
}
26+
}
27+
28+
from
29+
InvalidReinterpretCast cast, string message, Element optionalTemplateUseSite,
30+
string optionalTemplateUseSiteString
2131
where
2232
not isExcluded(cast, Conversions2Package::pointerToIntegralCastQuery()) and
23-
sourceType = cast.getExpr().getType().getUnspecifiedType() and
24-
targetType = cast.getType() and
25-
targetType.getUnspecifiedType() instanceof IntegralType and
26-
not stripSpecifiers(targetType).(UserType).hasGlobalOrStdName(["uintptr_t", "intptr_t"])
27-
select cast,
28-
"Cast of object pointer type to integral type '" + targetType +
29-
"' instead of 'std::uintptr_t' or 'std::intptr_t'."
33+
// Where a result occurs in both the instantiated and uninstantiated template,
34+
// prefer the uninstantiated version.
35+
not exists(InvalidReinterpretCast otherCast |
36+
otherCast.getLocation() = cast.getLocation() and
37+
not otherCast = cast and
38+
otherCast.isFromUninstantiatedTemplate(_)
39+
) and
40+
if not cast.isFromTemplateInstantiation(_)
41+
then
42+
// Either not in a template, or appears in the uninstantiated template and is
43+
// therefore not argument dependent.
44+
message =
45+
"Cast of object pointer type to integral type '" + cast.getType() +
46+
"' instead of 'std::uintptr_t' or 'std::intptr_t'." and
47+
optionalTemplateUseSite = cast and
48+
optionalTemplateUseSiteString = ""
49+
else
50+
// This is from a template instantiation and is dependent on a template argument,
51+
// so attempt to identify the locations which instantiate the template.
52+
exists(Element instantiation |
53+
cast.isFromTemplateInstantiation(instantiation) and
54+
message = "Cast of object pointer type to integral type inside $@."
55+
|
56+
optionalTemplateUseSite = instantiation.(ClassTemplateInstantiation).getATypeNameUse() and
57+
optionalTemplateUseSiteString =
58+
"instantiation of class " + instantiation.(ClassTemplateInstantiation).getName()
59+
or
60+
optionalTemplateUseSite =
61+
instantiation.(FunctionTemplateInstantiation).getACallToThisFunction() and
62+
optionalTemplateUseSiteString =
63+
"call to instantiated template f of " +
64+
instantiation.(FunctionTemplateInstantiation).getName()
65+
or
66+
optionalTemplateUseSite = instantiation.(VariableTemplateInstantiation).getAnAccess() and
67+
optionalTemplateUseSiteString =
68+
"reference to instantiated template variable " +
69+
instantiation.(VariableTemplateInstantiation).getName()
70+
)
71+
select cast, message, optionalTemplateUseSite, optionalTemplateUseSiteString
Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
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'. |
1+
| test.cpp:35:13:35:47 | reinterpret_cast<unsigned long>... | Cast of object pointer type to integral type 'unsigned long' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:35:13:35:47 | reinterpret_cast<unsigned long>... | |
2+
| test.cpp:40:13:40:46 | reinterpret_cast<unsigned int>... | Cast of object pointer type to integral type 'unsigned int' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:40:13:40:46 | reinterpret_cast<unsigned int>... | |
3+
| test.cpp:45:13:45:38 | reinterpret_cast<long>... | Cast of object pointer type to integral type 'long' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:45:13:45:38 | reinterpret_cast<long>... | |
4+
| test.cpp:50:13:50:45 | reinterpret_cast<size_t>... | Cast of object pointer type to integral type 'size_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:50:13:50:45 | reinterpret_cast<size_t>... | |
5+
| test.cpp:55:13:55:43 | reinterpret_cast<hashPtr_t>... | Cast of object pointer type to integral type 'hashPtr_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:55:13:55:43 | reinterpret_cast<hashPtr_t>... | |
6+
| test.cpp:60:13:60:42 | reinterpret_cast<MyIntPtr>... | Cast of object pointer type to integral type 'MyIntPtr' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:60:13:60:42 | reinterpret_cast<MyIntPtr>... | |
7+
| test.cpp:65:13:65:35 | reinterpret_cast<unsigned long>... | Cast of object pointer type to integral type inside $@. | test.cpp:94:3:94:50 | call to test_non_compliant_template_cast | call to instantiated template f of test_non_compliant_template_cast |
8+
| test.cpp:67:13:67:47 | reinterpret_cast<uint64_t>... | Cast of object pointer type to integral type 'uint64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:67:13:67:47 | reinterpret_cast<uint64_t>... | |
9+
| 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'. | test.cpp:72:13:72:47 | reinterpret_cast<uint64_t>... | |
10+
| 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'. | test.cpp:77:13:77:46 | reinterpret_cast<int64_t>... | |
11+
| test.cpp:84:15:84:37 | reinterpret_cast<unsigned long>... | Cast of object pointer type to integral type inside $@. | test.cpp:95:48:95:48 | definition of x | instantiation of class TestNonCompliantTemplateCast<unsigned long> |
12+
| test.cpp:86:15:86:49 | reinterpret_cast<uint64_t>... | Cast of object pointer type to integral type 'uint64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:86:15:86:49 | reinterpret_cast<uint64_t>... | |
13+
| test.cpp:91:23:91:45 | reinterpret_cast<unsigned long>... | Cast of object pointer type to integral type inside $@. | test.cpp:96:3:96:35 | variable_template | reference to instantiated template variable variable_template |

cpp/misra/test/rules/RULE-8-2-8/test.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33
struct S {};
44
class C {};
55

6-
void *g1 = nullptr;
7-
S *g2 = nullptr;
8-
const int *g3 = nullptr;
6+
S *g1 = nullptr;
97

108
using hashPtr_t = std::uintptr_t;
119
using MyIntPtr = std::intptr_t;
@@ -64,7 +62,9 @@ void test_non_compliant_using_alias_cast() {
6462

6563
template <typename T> void test_non_compliant_template_cast() {
6664
S *l1 = nullptr;
67-
auto l2 = reinterpret_cast<T>(l1); // NON_COMPLIANT
65+
auto l2 = reinterpret_cast<T>(l1); // NON_COMPLIANT
66+
auto l3 = reinterpret_cast<std::uintptr_t>(l1); // COMPLIANT
67+
auto l4 = reinterpret_cast<std::uint64_t>(l1); // NON_COMPLIANT
6868
}
6969

7070
void test_non_compliant_uint64_t_cast() {
@@ -77,6 +77,21 @@ void test_non_compliant_int64_t_cast() {
7777
auto l2 = reinterpret_cast<std::int64_t>(l1); // NON_COMPLIANT
7878
}
7979

80+
template <typename T> class TestNonCompliantTemplateCast {
81+
public:
82+
TestNonCompliantTemplateCast() {
83+
S *l1 = nullptr;
84+
auto l2 = reinterpret_cast<T>(l1); // NON_COMPLIANT
85+
auto l3 = reinterpret_cast<std::uintptr_t>(l1); // COMPLIANT
86+
auto l4 = reinterpret_cast<std::uint64_t>(l1); // NON_COMPLIANT
87+
}
88+
};
89+
90+
template <class T>
91+
T variable_template = reinterpret_cast<T>(g1); // NON_COMPLIANT
92+
8093
void test_instantiate_template() {
8194
test_non_compliant_template_cast<std::uintptr_t>();
95+
TestNonCompliantTemplateCast<std::uintptr_t> x{};
96+
variable_template<std::uintptr_t>;
8297
}

0 commit comments

Comments
 (0)