Skip to content

Commit afa6c7f

Browse files
committed
PointerToAVirtualBaseClass: Handle reference types and type defs
1 parent 2510f2f commit afa6c7f

File tree

4 files changed

+76
-5
lines changed

4 files changed

+76
-5
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- `M5-2-2` - `PointerToAVirtualBaseClassCastToAPointer.ql`:
2+
- Report casts where the from or to types are typedefs to virtual base classes or derived classes.
3+
- Report casts to a reference type which is a derived type.

cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,19 @@ query predicate problems(Cast cast, string message) {
1616
exists(VirtualBaseClass castFrom, Class castTo |
1717
not isExcluded(cast, getQuery()) and
1818
not cast instanceof DynamicCast and
19-
castFrom = cast.getExpr().getType().(PointerType).getBaseType() and
20-
cast.getType().(PointerType).getBaseType() = castTo and
2119
castTo = castFrom.getADerivedClass+() and
2220
message =
2321
"A pointer to virtual base class " + castFrom.getName() +
2422
" is not cast to a pointer of derived class " + castTo.getName() + " using a dynamic_cast."
23+
|
24+
// Pointer cast
25+
castFrom = cast.getExpr().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and
26+
cast.getType().stripTopLevelSpecifiers().(PointerType).getBaseType() = castTo
27+
or
28+
// Reference type cast
29+
castFrom = cast.getExpr().getType().stripTopLevelSpecifiers() and
30+
// Not actually represented as a reference type in our model - instead as the
31+
// type itself
32+
cast.getType().stripTopLevelSpecifiers() = castTo
2533
)
2634
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| test.cpp:36:12:36:37 | reinterpret_cast<C2 *>... | A pointer to virtual base class C1 is not cast to a pointer of derived class C2 using a dynamic_cast. |
2+
| test.cpp:42:12:42:38 | reinterpret_cast<C2>... | A pointer to virtual base class C1 is not cast to a pointer of derived class C2 using a dynamic_cast. |
3+
| test.cpp:48:17:48:48 | reinterpret_cast<Derived>... | A pointer to virtual base class C1 is not cast to a pointer of derived class C2 using a dynamic_cast. |

cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/test.cpp

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,74 @@ class C1 {
22
public:
33
virtual ~C1() {}
44
};
5+
56
class C2 : public virtual C1 {
67
public:
78
C2() {}
89
~C2() {}
910
};
1011

11-
void f1() {
12+
typedef C1 Base;
13+
typedef C2 Derived;
14+
15+
void test_dynamic_cast_pointer_compliant() {
1216
C2 l1;
1317
C1 *p1 = &l1;
18+
C2 *p2 = dynamic_cast<C2 *>(p1); // COMPLIANT
19+
}
1420

15-
// C2 *p2 = static_cast<C2 *>(p1); // NON_COMPLIANT, prohibited by compiler
16-
C2 *p3 = dynamic_cast<C2 *>(p1); // COMPLIANT
21+
void test_dynamic_cast_reference_compliant() {
22+
C2 l1;
23+
C1 *p1 = &l1;
1724
C2 &l2 = dynamic_cast<C2 &>(*p1); // COMPLIANT
1825
}
26+
27+
void test_dynamic_cast_reference_compliant_typedefs() {
28+
Derived l1;
29+
Base *p1 = &l1;
30+
Derived &l2 = dynamic_cast<Derived &>(*p1); // COMPLIANT
31+
}
32+
33+
void test_reinterpret_cast_pointer_non_compliant() {
34+
C2 l1;
35+
C1 *p1 = &l1;
36+
C2 *p2 = reinterpret_cast<C2 *>(p1); // NON_COMPLIANT
37+
}
38+
39+
void test_reinterpret_cast_reference_non_compliant() {
40+
C2 l1;
41+
C1 *p1 = &l1;
42+
C2 &l2 = reinterpret_cast<C2 &>(*p1); // NON_COMPLIANT
43+
}
44+
45+
void test_reinterpret_cast_typedefs_non_compliant() {
46+
Derived l1;
47+
Base *p1 = &l1;
48+
Derived &l2 = reinterpret_cast<Derived &>(*p1); // NON_COMPLIANT
49+
}
50+
51+
void test_c_style_cast_pointer_non_compliant() {
52+
C2 l1;
53+
C1 *p1 = &l1;
54+
// C2 *p2 = (C2 *)p1; // NON_COMPLIANT - prohibited by the compiler
55+
}
56+
57+
void test_c_style_cast_reference_non_compliant() {
58+
C2 l1;
59+
C1 *p1 = &l1;
60+
// C2 &l2 = (C2 &)*p1; // NON_COMPLIANT - prohibited by the compiler
61+
}
62+
63+
void test_static_cast_pointer_non_compliant() {
64+
C2 l1;
65+
C1 *p1 = &l1;
66+
// C2 *p2 = static_cast<C2 *>(p1); // NON_COMPLIANT - prohibited by the
67+
// compiler
68+
}
69+
70+
void test_static_cast_reference_non_compliant() {
71+
C2 l1;
72+
C1 *p1 = &l1;
73+
// C2 &l2 = static_cast<C2 &>(*p1); // NON_COMPLIANT - prohibited by the
74+
// compiler
75+
}

0 commit comments

Comments
 (0)