Skip to content

Commit 3e54854

Browse files
committed
Address feedback
1 parent 34ecd57 commit 3e54854

4 files changed

Lines changed: 155 additions & 34 deletions

File tree

cpp/common/src/codingstandards/cpp/lifetimes/CppObjects.qll

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import cpp
22
import codingstandards.cpp.lifetimes.StorageDuration
33
import semmle.code.cpp.valuenumbering.HashCons
44
import codingstandards.cpp.Clvalues
5+
import codingstandards.cpp.types.Pointers
56

67
/**
78
* A library for handling "Objects" in C++.
@@ -136,19 +137,39 @@ abstract class ObjectIdentityBase extends Element {
136137
}
137138

138139
/**
139-
* Finds expressions `e.x` or `e[x]` for expression `e`, recursively. Does not resolve pointers.
140+
* Finds expressions `e.x` or `e[x]` for expression `e`, recursively.
141+
*
142+
* Omits accesses to reference fields, as they are not subobjects.
140143
*
141144
* Note that this does not hold for `e->x` or `e[x]` where `e` is a pointer.
142145
*/
143-
private Expr getASubobjectAccessOf(Expr e) {
144-
result = e
145-
or
146-
result.(DotFieldAccess).getQualifier() = getASubobjectAccessOf(e)
146+
Expr getASubobjectAccessOf(Expr e) {
147+
exists(Field f |
148+
not f.getUnderlyingType() instanceof ReferenceType and
149+
f.getAnAccess().(FieldAccess) = result.getAChild*()
150+
) and
151+
(
152+
result = e
153+
or
154+
result.(DotFieldAccess).getQualifier() = getASubobjectAccessOf(e)
155+
)
147156
or
148157
result.(ArrayExpr).getArrayBase() = getASubobjectAccessOf(e) and
149158
not result.(ArrayExpr).getArrayBase().getUnspecifiedType() instanceof PointerType
150159
}
151160

161+
/**
162+
* gets an access where the pointee is the subobject
163+
*/
164+
Expr getASubobjectAccessOfPointee(Expr e) {
165+
e.getParent() instanceof AddressOfExpr and
166+
result = getASubobjectAccessOf(e.getParent())
167+
or
168+
// the accessed field is a pointer to a subobject
169+
e.getParent().(PointerFieldAccess).getTarget().getUnspecifiedType() instanceof PointerType and
170+
result = getASubobjectAccessOf(e.getParent())
171+
}
172+
152173
/**
153174
* Find the object types that are embedded within the current type.
154175
*

cpp/misra/src/rules/RULE-6-8-4/MemberFunctionsRefqualified.ql

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,54 +17,66 @@ import cpp
1717
import codingstandards.cpp.misra
1818
import codingstandards.cpp.types.Compatible
1919
import codingstandards.cpp.Operator
20+
import codingstandards.cpp.types.Pointers
21+
import codingstandards.cpp.lifetimes.CppObjects
2022

2123
class MembersReturningPointerOrRef extends MemberFunction {
22-
MembersReturningPointerOrRef() {
23-
this.getUnspecifiedType() instanceof PointerType or
24-
this.getUnspecifiedType() instanceof ReferenceType
25-
}
24+
MembersReturningPointerOrRef() { this.getType() instanceof PointerLikeType }
2625
}
2726

2827
abstract class MembersReturningObjectOrSubobject extends MembersReturningPointerOrRef {
2928
string toString() { result = "Members returning object or subobject" }
3029
}
3130

31+
/**
32+
* Members that have an explicit `this` access within their return statement.
33+
*/
3234
class MembersReturningObject extends MembersReturningObjectOrSubobject {
3335
MembersReturningObject() {
3436
exists(ReturnStmt r, ThisExpr t |
3537
r.getEnclosingFunction() = this and
3638
(
37-
r.getAChild*() = t
39+
//direct access only
40+
r.getAChild() = t
3841
or
42+
//or one level of indirection
3943
exists(PointerDereferenceExpr p |
40-
p.getAChild*() = t and
41-
r.getAChild*() = p
44+
p.getAChild() = t and
45+
r.getAChild() = p
4246
)
4347
) and
4448
t.getActualType().stripType() = this.getDeclaringType()
4549
)
4650
}
4751
}
4852

53+
/**
54+
* Members that have an explicit subobject access within their return statement.
55+
*
56+
* Specifically, this captures when the return is a reference or pointer
57+
* to a subobject.
58+
*/
4959
class MembersReturningSubObject extends MembersReturningObjectOrSubobject {
5060
MembersReturningSubObject() {
51-
exists(ReturnStmt r, FieldSubObjectDeclaration field |
61+
exists(ReturnStmt r, FieldAccess access, Expr e |
5262
r.getEnclosingFunction() = this and
63+
//direct access only
64+
r.getAChild() = e and
5365
(
54-
r.getAChild*() = field.(Field).getAnAccess()
66+
//pointer or reference to pointer subobject returned
67+
e = getASubobjectAccessOfPointee(access) and
68+
(e.getType() instanceof PointerType or e.getType() instanceof ReferenceType)
5569
or
56-
exists(PointerDereferenceExpr p |
57-
p.getAChild*() = field.(Field).getAnAccess() and
58-
r.getAChild*() = p
59-
)
60-
) and
61-
field.(Field).getDeclaringType() = this.getDeclaringType()
70+
//reference to subobject returned
71+
(this.getType() instanceof ReferenceType or e.getType() instanceof ReferenceType) and
72+
not access.getTarget().getType() instanceof PointerType
73+
)
6274
)
6375
}
6476
}
6577

6678
predicate relevantTypes(Type a, Type b) {
67-
exists(MembersReturningObject f, MemberFunction overload |
79+
exists(MembersReturningObjectOrSubobject f, MemberFunction overload |
6880
f.getAnOverload() = overload and
6981
exists(int i |
7082
f.getParameter(i).getType() = a and
@@ -77,11 +89,11 @@ class AppropriatelyQualified extends MembersReturningObjectOrSubobject {
7789
AppropriatelyQualified() {
7890
//non-const-lvalue-ref-qualified
7991
this.isLValueRefQualified() and
80-
not this.hasSpecifier("const")
92+
this.getType().(PointerLikeType).pointsToNonConst()
8193
or
8294
//const-lvalue-ref-qualified
8395
this.isLValueRefQualified() and
84-
this.hasSpecifier("const") and
96+
this.getType().(PointerLikeType).pointsToConst() and
8597
//and overload exists that is rvalue-ref-qualified
8698
exists(MemberFunction overload |
8799
this.getAnOverload() = overload and
@@ -95,16 +107,6 @@ class AppropriatelyQualified extends MembersReturningObjectOrSubobject {
95107
}
96108
}
97109

98-
/**
99-
* Fields that are not reference type can be subobjects
100-
*/
101-
class FieldSubObjectDeclaration extends Declaration {
102-
FieldSubObjectDeclaration() {
103-
not this.getADeclarationEntry().getType() instanceof ReferenceType and
104-
this instanceof Field
105-
}
106-
}
107-
108110
class DefaultedAssignmentOperator extends AssignmentOperator {
109111
DefaultedAssignmentOperator() { this.isDefaulted() }
110112
}

cpp/misra/test/rules/RULE-6-8-4/MemberFunctionsRefqualified.expected

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,17 @@
44
| test.cpp:42:16:42:16 | Members returning object or subobject | Member function is not properly ref qualified. |
55
| test.cpp:42:16:42:16 | Members returning object or subobject | Member function is not properly ref qualified. |
66
| test.cpp:42:16:42:16 | Members returning object or subobject | Member function is not properly ref qualified. |
7+
| test.cpp:61:8:61:8 | Members returning object or subobject | Member function is not properly ref qualified. |
8+
| test.cpp:71:9:71:10 | Members returning object or subobject | Member function is not properly ref qualified. |
9+
| test.cpp:79:8:79:9 | Members returning object or subobject | Member function is not properly ref qualified. |
10+
| test.cpp:82:8:82:9 | Members returning object or subobject | Member function is not properly ref qualified. |
11+
| test.cpp:85:8:85:9 | Members returning object or subobject | Member function is not properly ref qualified. |
12+
| test.cpp:89:9:89:10 | Members returning object or subobject | Member function is not properly ref qualified. |
13+
| test.cpp:93:9:93:10 | Members returning object or subobject | Member function is not properly ref qualified. |
14+
| test.cpp:103:8:103:8 | Members returning object or subobject | Member function is not properly ref qualified. |
15+
| test.cpp:113:9:113:10 | Members returning object or subobject | Member function is not properly ref qualified. |
16+
| test.cpp:121:8:121:9 | Members returning object or subobject | Member function is not properly ref qualified. |
17+
| test.cpp:124:8:124:9 | Members returning object or subobject | Member function is not properly ref qualified. |
18+
| test.cpp:127:8:127:9 | Members returning object or subobject | Member function is not properly ref qualified. |
19+
| test.cpp:131:9:131:10 | Members returning object or subobject | Member function is not properly ref qualified. |
20+
| test.cpp:135:9:135:10 | Members returning object or subobject | Member function is not properly ref qualified. |

cpp/misra/test/rules/RULE-6-8-4/test.cpp

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,88 @@ void f(int p, float p1) {
5151
t.f(p);
5252
t.f(p1); // instantiation that causes issue due to parameter list type meaning
5353
// there is no overload
54-
}
54+
}
55+
56+
class B {
57+
int i;
58+
int *ip;
59+
int **ip2;
60+
61+
int *f() {
62+
return &i; // NON_COMPLIANT
63+
}
64+
int *f1() {
65+
return ip; // COMPLIANT -- reads pointer
66+
}
67+
int *f2() {
68+
return *ip2; // COMPLIANT -- reads pointer
69+
}
70+
71+
int **f3() {
72+
return &ip; // NON_COMPLIANT
73+
}
74+
75+
int **f4() {
76+
return ip2; // COMPLIANT -- copies pointer
77+
}
78+
79+
int &f5() {
80+
return i; // NON_COMPLIANT
81+
}
82+
int &f6() {
83+
return *ip; // COMPLIANT[FALSE_POSITIVE] -- reads pointer
84+
}
85+
int &f7() {
86+
return **ip2; // COMPLIANT[FALSE_POSITIVE]-- reads pointer
87+
}
88+
89+
int *&f8() {
90+
// return &p; // won't compile
91+
return ip; // NON_COMPLIANT
92+
}
93+
int *&f9() {
94+
return *ip2; // COMPLIANT[FALSE_POSITIVE] -- reads pointer
95+
}
96+
};
97+
98+
class D {
99+
int i;
100+
int *ip;
101+
int **ip2;
102+
103+
int *f() {
104+
return &(this->i); // NON_COMPLIANT
105+
}
106+
int *f1() {
107+
return this->ip; // COMPLIANT -- reads pointer
108+
}
109+
int *f2() {
110+
return *this->ip2; // COMPLIANT -- reads pointer
111+
}
112+
113+
int **f3() {
114+
return &this->ip; // NON_COMPLIANT
115+
}
116+
117+
int **f4() {
118+
return this->ip2; // COMPLIANT -- copies pointer
119+
}
120+
121+
int &f5() {
122+
return this->i; // NON_COMPLIANT
123+
}
124+
int &f6() {
125+
return *this->ip; // COMPLIANT[FALSE_POSITIVE] -- reads pointer
126+
}
127+
int &f7() {
128+
return **this->ip2; // COMPLIANT[FALSE_POSITIVE] -- reads pointer
129+
}
130+
131+
int *&f8() {
132+
// return &p; // won't compile
133+
return this->ip; // NON_COMPLIANT
134+
}
135+
int *&f9() {
136+
return *this->ip2; // COMPLIANT[FALSE_POSITIVE] -- reads pointer
137+
}
138+
};

0 commit comments

Comments
 (0)