Skip to content

Commit 4489686

Browse files
authored
Merge pull request #1101 from knewbury01/knewbury01/cpp-misra2023-declarations5
Declarations5 cpp misra 2023
2 parents 7e0497a + 706029d commit 4489686

13 files changed

Lines changed: 461 additions & 9 deletions

File tree

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
2+
import cpp
3+
import RuleMetadata
4+
import codingstandards.cpp.exclusions.RuleMetadata
5+
6+
newtype Declarations5Query =
7+
TMemberFunctionsRefqualifiedQuery() or
8+
TTypeAliasesDeclarationQuery()
9+
10+
predicate isDeclarations5QueryMetadata(Query query, string queryId, string ruleId, string category) {
11+
query =
12+
// `Query` instance for the `memberFunctionsRefqualified` query
13+
Declarations5Package::memberFunctionsRefqualifiedQuery() and
14+
queryId =
15+
// `@id` for the `memberFunctionsRefqualified` query
16+
"cpp/misra/member-functions-refqualified" and
17+
ruleId = "RULE-6-8-4" and
18+
category = "advisory"
19+
or
20+
query =
21+
// `Query` instance for the `typeAliasesDeclaration` query
22+
Declarations5Package::typeAliasesDeclarationQuery() and
23+
queryId =
24+
// `@id` for the `typeAliasesDeclaration` query
25+
"cpp/misra/type-aliases-declaration" and
26+
ruleId = "RULE-6-9-1" and
27+
category = "required"
28+
}
29+
30+
module Declarations5Package {
31+
Query memberFunctionsRefqualifiedQuery() {
32+
//autogenerate `Query` type
33+
result =
34+
// `Query` type for `memberFunctionsRefqualified` query
35+
TQueryCPP(TDeclarations5PackageQuery(TMemberFunctionsRefqualifiedQuery()))
36+
}
37+
38+
Query typeAliasesDeclarationQuery() {
39+
//autogenerate `Query` type
40+
result =
41+
// `Query` type for `typeAliasesDeclaration` query
42+
TQueryCPP(TDeclarations5PackageQuery(TTypeAliasesDeclarationQuery()))
43+
}
44+
}

cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import Declarations1
4040
import Declarations2
4141
import Declarations3
4242
import Declarations4
43+
import Declarations5
4344
import Declarations6
4445
import Declarations7
4546
import ExceptionSafety
@@ -149,6 +150,7 @@ newtype TCPPQuery =
149150
TDeclarations2PackageQuery(Declarations2Query q) or
150151
TDeclarations3PackageQuery(Declarations3Query q) or
151152
TDeclarations4PackageQuery(Declarations4Query q) or
153+
TDeclarations5PackageQuery(Declarations5Query q) or
152154
TDeclarations6PackageQuery(Declarations6Query q) or
153155
TDeclarations7PackageQuery(Declarations7Query q) or
154156
TExceptionSafetyPackageQuery(ExceptionSafetyQuery q) or
@@ -258,6 +260,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
258260
isDeclarations2QueryMetadata(query, queryId, ruleId, category) or
259261
isDeclarations3QueryMetadata(query, queryId, ruleId, category) or
260262
isDeclarations4QueryMetadata(query, queryId, ruleId, category) or
263+
isDeclarations5QueryMetadata(query, queryId, ruleId, category) or
261264
isDeclarations6QueryMetadata(query, queryId, ruleId, category) or
262265
isDeclarations7QueryMetadata(query, queryId, ruleId, category) or
263266
isExceptionSafetyQueryMetadata(query, queryId, ruleId, category) or

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

Lines changed: 26 additions & 3 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,41 @@ 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) {
146+
Expr getASubobjectAccessOf(Expr e) {
144147
result = e
145148
or
146-
result.(DotFieldAccess).getQualifier() = getASubobjectAccessOf(e)
149+
result.(DotFieldAccess).getQualifier() = getASubobjectAccessOf(e) and
150+
not result.(DotFieldAccess).getTarget().getUnderlyingType() instanceof ReferenceType
147151
or
148152
result.(ArrayExpr).getArrayBase() = getASubobjectAccessOf(e) and
149153
not result.(ArrayExpr).getArrayBase().getUnspecifiedType() instanceof PointerType
150154
}
151155

156+
/**
157+
* Finds subobjects of the pointee for expression `e`,
158+
* where `e` has the type pointer type.
159+
*
160+
* For `e` this will be subobject accesses of `*e`.
161+
* Or for `e->x` the subobject access is `x`.
162+
*
163+
* This predicate is not used/tested extensively so
164+
* verify it before use.
165+
*/
166+
Expr getASubobjectAccessOfPointee(Expr e) {
167+
e.getParent() instanceof PointerDereferenceExpr and
168+
result = getASubobjectAccessOf(e.getParent())
169+
or
170+
// for e1->e2 : getASubobjectAccessOfPointee(e1) = e2 and or subobjects of e2
171+
result = getASubobjectAccessOf(e.getParent().(PointerFieldAccess)) and
172+
not result.(PointerFieldAccess).getTarget().getUnderlyingType() instanceof ReferenceType
173+
}
174+
152175
/**
153176
* Find the object types that are embedded within the current type.
154177
*

cpp/common/src/codingstandards/cpp/types/Compatible.qll

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -486,45 +486,72 @@ signature predicate interestedInFunctionDeclarations(
486486
);
487487

488488
module FunctionDeclarationTypeEquivalence<
489-
TypeEquivalenceSig Config, interestedInFunctionDeclarations/2 interestedInFunctions>
489+
TypeEquivalenceSig Config, interestedInFunctionDeclarations/2 interestedInFunDecls>
490490
{
491491
private predicate interestedInReturnTypes(Type a, Type b) {
492492
exists(FunctionDeclarationEntry aFun, FunctionDeclarationEntry bFun |
493-
interestedInFunctions(pragma[only_bind_into](aFun), pragma[only_bind_into](bFun)) and
493+
interestedInFunDecls(pragma[only_bind_into](aFun), pragma[only_bind_into](bFun)) and
494494
a = aFun.getType() and
495495
b = bFun.getType()
496496
)
497497
}
498498

499499
private predicate interestedInParameterTypes(Type a, Type b) {
500500
exists(FunctionDeclarationEntry aFun, FunctionDeclarationEntry bFun, int i |
501-
interestedInFunctions(pragma[only_bind_into](aFun), pragma[only_bind_into](bFun)) and
501+
interestedInFunDecls(pragma[only_bind_into](aFun), pragma[only_bind_into](bFun)) and
502502
a = aFun.getParameterDeclarationEntry(i).getType() and
503503
b = bFun.getParameterDeclarationEntry(i).getType()
504504
)
505505
}
506506

507507
predicate equalReturnTypes(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) {
508-
interestedInFunctions(f1, f2) and
508+
interestedInFunDecls(f1, f2) and
509509
TypeEquivalence<Config, interestedInReturnTypes/2>::equalTypes(f1.getType(), f2.getType())
510510
}
511511

512512
predicate equalParameterTypes(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) {
513-
interestedInFunctions(f1, f2) and
513+
interestedInFunDecls(f1, f2) and
514514
f1.getDeclaration() = f2.getDeclaration() and
515515
forall(int i | exists([f1, f2].getParameterDeclarationEntry(i)) |
516516
equalParameterTypesAt(f1, f2, pragma[only_bind_into](i))
517517
)
518518
}
519519

520520
predicate equalParameterTypesAt(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, int i) {
521-
interestedInFunctions(f1, f2) and
521+
interestedInFunDecls(f1, f2) and
522522
f1.getDeclaration() = f2.getDeclaration() and
523523
TypeEquivalence<Config, interestedInParameterTypes/2>::equalTypes(f1.getParameterDeclarationEntry(pragma[only_bind_into](i))
524524
.getType(), f2.getParameterDeclarationEntry(pragma[only_bind_into](i)).getType())
525525
}
526526
}
527527

528+
signature predicate interestedInFunctionsByFunction(Function f1, Function f2);
529+
530+
module FunctionEquivalence<
531+
TypeEquivalenceSig Config, interestedInFunctionsByFunction/2 interestedInFuncs>
532+
{
533+
private predicate interestedInParameterTypes(Type a, Type b) {
534+
exists(Function aFun, Function bFun, int i |
535+
interestedInFuncs(pragma[only_bind_into](aFun), pragma[only_bind_into](bFun)) and
536+
a = aFun.getParameter(i).getType() and
537+
b = bFun.getParameter(i).getType()
538+
)
539+
}
540+
541+
predicate equalParameterTypes(Function f1, Function f2) {
542+
interestedInFuncs(f1, f2) and
543+
forall(int i | exists([f1, f2].getParameter(i)) |
544+
equalParameterTypesAt(f1, f2, pragma[only_bind_into](i))
545+
)
546+
}
547+
548+
predicate equalParameterTypesAt(Function f1, Function f2, int i) {
549+
interestedInFuncs(f1, f2) and
550+
TypeEquivalence<Config, interestedInParameterTypes/2>::equalTypes(f1.getParameter(pragma[only_bind_into](i))
551+
.getType(), f2.getParameter(pragma[only_bind_into](i)).getType())
552+
}
553+
}
554+
528555
private class LeafType extends Type {
529556
LeafType() {
530557
not this instanceof DerivedType and
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
* @id cpp/misra/member-functions-refqualified
3+
* @name RULE-6-8-4: Member functions returning references to their object should be refqualified appropriately
4+
* @description Member functions that return references to temporary objects (or subobjects) can
5+
* lead to dangling pointers.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-6-8-4
10+
* correctness
11+
* scope/single-translation-unit
12+
* external/misra/enforcement/decidable
13+
* external/misra/obligation/advisory
14+
*/
15+
16+
import cpp
17+
import codingstandards.cpp.misra
18+
import codingstandards.cpp.types.Compatible
19+
import codingstandards.cpp.Operator
20+
import codingstandards.cpp.types.Pointers
21+
import codingstandards.cpp.lifetimes.CppObjects
22+
23+
class MembersReturningPointerOrRef extends MemberFunction {
24+
MembersReturningPointerOrRef() { this.getType() instanceof PointerLikeType }
25+
}
26+
27+
abstract class MembersReturningObjectOrSubobject extends MembersReturningPointerOrRef {
28+
string toString() { result = "Members returning object or subobject" }
29+
}
30+
31+
/**
32+
* Members that have an explicit `this` access within their return statement.
33+
*/
34+
class MembersReturningObject extends MembersReturningObjectOrSubobject {
35+
MembersReturningObject() {
36+
exists(ReturnStmt r, ThisExpr t |
37+
r.getEnclosingFunction() = this and
38+
//return `this`
39+
r.getAChild() = t and
40+
t.getActualType().stripType() = this.getDeclaringType()
41+
)
42+
}
43+
}
44+
45+
/**
46+
* Members that have an explicit subobject access within their return statement.
47+
*
48+
* Specifically, this captures when the return is a reference or pointer
49+
* to a subobject.
50+
*/
51+
class MembersReturningSubObject extends MembersReturningObjectOrSubobject {
52+
MembersReturningSubObject() {
53+
exists(ReturnStmt r, FieldAccess access, Expr e |
54+
r.getEnclosingFunction() = this and
55+
(not exists(access.getQualifier()) or access.getQualifier() instanceof ThisExpr) and
56+
(
57+
//subobject returned by address
58+
r.getAChild() = access.getParent() and
59+
e = getASubobjectAccessOf(access) and
60+
access.getParent() instanceof AddressOfExpr
61+
or
62+
//reference to subobject returned
63+
r.getAChild() = e and
64+
e = getASubobjectAccessOf(access) and
65+
this.getType() instanceof ReferenceType
66+
)
67+
)
68+
}
69+
}
70+
71+
predicate relevantFunctions(Function a, Function b) {
72+
a instanceof MembersReturningObjectOrSubobject and
73+
a.getAnOverload() = b
74+
}
75+
76+
class AppropriatelyQualified extends MemberFunction {
77+
AppropriatelyQualified() {
78+
//non-const-lvalue-ref-qualified
79+
this.isLValueRefQualified() and
80+
this.getType().(PointerLikeType).pointsToNonConst()
81+
or
82+
//const-lvalue-ref-qualified
83+
this.isLValueRefQualified() and
84+
this.getType().(PointerLikeType).pointsToConst() and
85+
//and overload exists that is rvalue-ref-qualified
86+
exists(MemberFunction overload |
87+
this.getAnOverload() = overload and
88+
overload.isRValueRefQualified() and
89+
//and has same param list
90+
FunctionEquivalence<TypesCompatibleConfig, relevantFunctions/2>::equalParameterTypes(this,
91+
overload)
92+
)
93+
}
94+
}
95+
96+
class DefaultedAssignmentOperator extends AssignmentOperator {
97+
DefaultedAssignmentOperator() { this.isDefaulted() }
98+
}
99+
100+
from MembersReturningObjectOrSubobject f
101+
where
102+
not isExcluded(f, Declarations5Package::memberFunctionsRefqualifiedQuery()) and
103+
not f instanceof AppropriatelyQualified and
104+
not f instanceof DefaultedAssignmentOperator
105+
select f, "Member function is not properly ref qualified."
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* @id cpp/misra/type-aliases-declaration
3+
* @name RULE-6-9-1: The same type aliases shall be used in all declarations of the same entity
4+
* @description Using different type aliases on redeclarations can make code hard to understand and
5+
* maintain.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity warning
9+
* @tags external/misra/id/rule-6-9-1
10+
* maintainability
11+
* readability
12+
* scope/single-translation-unit
13+
* external/misra/enforcement/decidable
14+
* external/misra/obligation/required
15+
*/
16+
17+
import cpp
18+
import codingstandards.cpp.misra
19+
20+
from DeclarationEntry decl1, DeclarationEntry decl2, TypedefType t
21+
where
22+
not isExcluded(decl1, Declarations5Package::typeAliasesDeclarationQuery()) and
23+
not isExcluded(decl2, Declarations5Package::typeAliasesDeclarationQuery()) and
24+
not decl1 = decl2 and
25+
decl1.getDeclaration() = decl2.getDeclaration() and
26+
t.getATypeNameUse() = decl1 and
27+
not t.getATypeNameUse() = decl2 and
28+
//exception cases - we dont want to disallow struct typedef name use
29+
not t.getBaseType() instanceof Struct and
30+
not t.getBaseType() instanceof Enum
31+
select decl1,
32+
"Declaration entry has a different type alias than $@ where the type alias used is '$@'.", decl2,
33+
decl2.getName(), t, t.getName()
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
| test.cpp:12:14:12:20 | Members returning object or subobject | Member function is not properly ref qualified. |
2+
| test.cpp:24:12:24:23 | Members returning object or subobject | Member function is not properly ref qualified. |
3+
| test.cpp:42:16:42:16 | Members returning object or subobject | Member function is not properly ref qualified. |
4+
| test.cpp:42:16:42:16 | Members returning object or subobject | Member function is not properly ref qualified. |
5+
| test.cpp:42:16:42:16 | Members returning object or subobject | Member function is not properly ref qualified. |
6+
| test.cpp:61:8:61:8 | Members returning object or subobject | Member function is not properly ref qualified. |
7+
| test.cpp:71:9:71:10 | Members returning object or subobject | Member function is not properly ref qualified. |
8+
| test.cpp:79:8:79:9 | Members returning object or subobject | Member function is not properly ref qualified. |
9+
| test.cpp:89:9:89:10 | Members returning object or subobject | Member function is not properly ref qualified. |
10+
| test.cpp:103:8:103:8 | Members returning object or subobject | Member function is not properly ref qualified. |
11+
| test.cpp:113:9:113:10 | Members returning object or subobject | Member function is not properly ref qualified. |
12+
| test.cpp:121:8:121:9 | Members returning object or subobject | Member function is not properly ref qualified. |
13+
| test.cpp:131:9:131:10 | Members returning object or subobject | Member function is not properly ref qualified. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-6-8-4/MemberFunctionsRefqualified.ql

0 commit comments

Comments
 (0)