Skip to content

Commit 72383c2

Browse files
Initial implementation of 15-1-4
1 parent 8071ddb commit 72383c2

File tree

8 files changed

+544
-1
lines changed

8 files changed

+544
-1
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
2+
import cpp
3+
import RuleMetadata
4+
import codingstandards.cpp.exclusions.RuleMetadata
5+
6+
newtype Classes4Query = TNonStaticMemberNotInitBeforeUseQuery()
7+
8+
predicate isClasses4QueryMetadata(Query query, string queryId, string ruleId, string category) {
9+
query =
10+
// `Query` instance for the `nonStaticMemberNotInitBeforeUse` query
11+
Classes4Package::nonStaticMemberNotInitBeforeUseQuery() and
12+
queryId =
13+
// `@id` for the `nonStaticMemberNotInitBeforeUse` query
14+
"cpp/misra/non-static-member-not-init-before-use" and
15+
ruleId = "RULE-15-1-4" and
16+
category = "advisory"
17+
}
18+
19+
module Classes4Package {
20+
Query nonStaticMemberNotInitBeforeUseQuery() {
21+
//autogenerate `Query` type
22+
result =
23+
// `Query` type for `nonStaticMemberNotInitBeforeUse` query
24+
TQueryCPP(TClasses4PackageQuery(TNonStaticMemberNotInitBeforeUseQuery()))
25+
}
26+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import BannedSyntax
1111
import BannedTypes
1212
import Classes
1313
import Classes2
14+
import Classes4
1415
import Comments
1516
import Concurrency
1617
import Conditionals
@@ -100,6 +101,7 @@ newtype TCPPQuery =
100101
TBannedTypesPackageQuery(BannedTypesQuery q) or
101102
TClassesPackageQuery(ClassesQuery q) or
102103
TClasses2PackageQuery(Classes2Query q) or
104+
TClasses4PackageQuery(Classes4Query q) or
103105
TCommentsPackageQuery(CommentsQuery q) or
104106
TConcurrencyPackageQuery(ConcurrencyQuery q) or
105107
TConditionalsPackageQuery(ConditionalsQuery q) or
@@ -189,6 +191,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
189191
isBannedTypesQueryMetadata(query, queryId, ruleId, category) or
190192
isClassesQueryMetadata(query, queryId, ruleId, category) or
191193
isClasses2QueryMetadata(query, queryId, ruleId, category) or
194+
isClasses4QueryMetadata(query, queryId, ruleId, category) or
192195
isCommentsQueryMetadata(query, queryId, ruleId, category) or
193196
isConcurrencyQueryMetadata(query, queryId, ruleId, category) or
194197
isConditionalsQueryMetadata(query, queryId, ruleId, category) or
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
/**
2+
* @id cpp/misra/non-static-member-not-init-before-use
3+
* @name RULE-15-1-4: All direct, non-static data members of a class should be initialized before the class object is accessible
4+
* @description Explicit initialization of all non-static data members reduces the risk of an
5+
* invalid state existing after successful construction.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity warning
9+
* @tags external/misra/id/rule-15-1-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.TrivialType
19+
20+
/**
21+
* A type needs initialization if it is:
22+
* - a scalar type
23+
* - an array of types that need initialization
24+
* - an aggregate class with a field that needs initialization
25+
*/
26+
private predicate needsInitialization(Type t) {
27+
isScalarType(t)
28+
or
29+
needsInitialization(t.getUnspecifiedType().(ArrayType).getBaseType())
30+
or
31+
t instanceof RelevantAggregate
32+
}
33+
34+
/**
35+
* An aggregate must be validated at construction time if it has a field that needs initialization.
36+
*/
37+
class RelevantAggregate extends Class {
38+
CheckedField f;
39+
40+
RelevantAggregate() {
41+
isAggregateClass(this) and
42+
f = getAField()
43+
}
44+
45+
CheckedField getField() { result = f }
46+
}
47+
48+
/**
49+
* A field must be checked for initialization if its type needs initialization, is not static, and
50+
* it does not have a default member initializer.
51+
*/
52+
class CheckedField extends Field {
53+
CheckedField() {
54+
this instanceof Field and
55+
needsInitialization(this.getUnspecifiedType()) and
56+
not exists(this.getInitializer())
57+
}
58+
}
59+
60+
/**
61+
* Holds if `f` is initialized in constructor `ctor` via the member initialization list
62+
* or has a default member initializer (NSDMI).
63+
*/
64+
predicate ctorInitializesCheckedField(Constructor ctor, CheckedField f) {
65+
// Field appears in the member initialization list
66+
exists(ConstructorFieldInit init |
67+
init = ctor.getAnInitializer() and
68+
init.getTarget() = f and
69+
not init.isCompilerGenerated()
70+
)
71+
}
72+
73+
/**
74+
* Represents an AST element that does not initialize a non-static data member that requires initialization.
75+
*
76+
* This may be a constructor definition, or an aggregate creation, etc.
77+
*/
78+
abstract class IncompleteInitialization extends Element {
79+
abstract CheckedField getField();
80+
81+
abstract string getKindStr();
82+
}
83+
84+
/**
85+
* A constructor that does not initialize a field that requires initialization.
86+
*
87+
* Non-aggregate class constructors must either:
88+
* - belong to an aggregate class, or
89+
* - delegate to another constructor in the same class, or
90+
* - initialize all fields that require initialization, or
91+
* - be a defaulted move/copy constructor (which we assume satisfies the above)
92+
*
93+
* Constructors that don't meet these criteria are non-compliant.
94+
*/
95+
class IncompleteConstructor extends Constructor, IncompleteInitialization {
96+
CheckedField checkedField;
97+
98+
IncompleteConstructor() {
99+
checkedField = this.getDeclaringType().getAField() and
100+
not ctorInitializesCheckedField(this, checkedField) and
101+
// aggregate classes are allowed and do not initialize members
102+
not isAggregateClass(getDeclaringType()) and
103+
this.getDeclaringType().hasDefinition() and
104+
not this.isDeleted() and
105+
// Delegating constructors do not need to initialize members
106+
not any(ConstructorDelegationInit init) = this.getAnInitializer() and
107+
// exclude defaulted move and copy constructors.
108+
not (
109+
(
110+
this.isDefaulted() or
111+
this.isCompilerGenerated()
112+
) and
113+
(
114+
this instanceof MoveConstructor or
115+
this instanceof CopyConstructor
116+
)
117+
)
118+
}
119+
120+
override CheckedField getField() { result = checkedField }
121+
122+
override string getKindStr() { result = "Constructor" }
123+
}
124+
125+
/**
126+
* A using declaration that introduces a base class constructor and skips initialization of a field.
127+
*
128+
* A declaration `using BaseClass::BaseClass;` in a derived class allows the derived class to
129+
* inherit the base class constructors. These will not initialize any fields declared in the derived
130+
* class, so if any checked field exists, the using declaration is non-compliant.
131+
*/
132+
class UsingBaseConstructor extends UsingDeclarationEntry, IncompleteInitialization {
133+
Class baseClass;
134+
Class containerClass;
135+
CheckedField checkedField;
136+
137+
UsingBaseConstructor() {
138+
getEnclosingElement() = containerClass and
139+
baseClass = getDeclaration() and
140+
checkedField = containerClass.getAField()
141+
}
142+
143+
override CheckedField getField() { result = checkedField }
144+
145+
override string getKindStr() { result = "Using declaration with base constructor" }
146+
}
147+
148+
/**
149+
* Handles the scenarios where an aggregate may be initialized by value based on a type.
150+
*
151+
* For instance, `const Agg`, `Agg[]`, and `Agg[][]` will be initialized by value, but `Agg*` and
152+
* `Agg&` will not. This is important to verify that aggregates are properly initialized
153+
*/
154+
predicate typeContainsAggregate(Type t, RelevantAggregate aggregate) {
155+
t.getUnderlyingType() = aggregate
156+
or
157+
not t.getUnderlyingType() instanceof RelevantAggregate and
158+
typeContainsAggregate(t.getUnderlyingType().(ArrayType).getBaseType(), aggregate)
159+
}
160+
161+
/**
162+
* A declaration of an aggregate that does not initialize necessary fields.
163+
*
164+
* By rule, aggregates are checked at construction time, rather than non-aggregates which are
165+
* checked at constructor definition.
166+
*
167+
* A declaration of `aggregate agg;` does not zero-initialize members, and may be non-compliant,
168+
* while `aggregate agg{};` does zero-initialize members and is compliant.
169+
*
170+
* Note that `aggregate agg;` as a member of an aggregate class is compliant, and as a member of a
171+
* non-aggregate class will be checked at the outer class constructor definition.
172+
*/
173+
class IncompleteAggregateInit extends Variable, IncompleteInitialization {
174+
RelevantAggregate aggregate;
175+
176+
IncompleteAggregateInit() {
177+
typeContainsAggregate(getType(), aggregate) and
178+
// agg{} is allowed, and agg; is not.
179+
not this.hasInitializer() and
180+
// Aggregate members may be initialized by constructor or belong to another aggregate.
181+
not this instanceof MemberVariable
182+
}
183+
184+
override CheckedField getField() { result = aggregate.getField() }
185+
186+
override string getKindStr() { result = "Aggregate variable" }
187+
}
188+
189+
/**
190+
* An aggregate created by a new or new[] expression that does not initialize necessary fields.
191+
*
192+
* For examyple, `new Aggregate;` does not zero-initialize members and may be non-compliant, while
193+
* `new Aggregate{};` does zero-initialize members and is compliant.
194+
*/
195+
class IncompleteAggregateNew extends NewOrNewArrayExpr, IncompleteInitialization {
196+
RelevantAggregate aggregate;
197+
198+
IncompleteAggregateNew() {
199+
typeContainsAggregate(this.getAllocatedType().getUnspecifiedType(), aggregate) and
200+
not exists(getAChild())
201+
}
202+
203+
override CheckedField getField() { result = aggregate.getField() }
204+
205+
override string getKindStr() { result = "Aggregate new expression" }
206+
}
207+
208+
from IncompleteInitialization init, CheckedField f
209+
where
210+
not isExcluded(init, Classes4Package::nonStaticMemberNotInitBeforeUseQuery()) and
211+
f = init.getField()
212+
select init, init.getKindStr() + " does not initialize non-static data member $@", f, f.getName()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
| test.cpp:35:3:35:14 | MemberUninit | Constructor does not initialize non-static data member $@ | test.cpp:36:16:36:17 | m1 | m1 |
2+
| test.cpp:45:3:45:19 | MemberUninitArray | Constructor does not initialize non-static data member $@ | test.cpp:46:16:46:17 | m1 | m1 |
3+
| test.cpp:50:3:50:21 | MemberUninitPointer | Constructor does not initialize non-static data member $@ | test.cpp:51:17:51:18 | m1 | m1 |
4+
| test.cpp:55:3:55:21 | MemberUninitAndInit | Constructor does not initialize non-static data member $@ | test.cpp:56:16:56:17 | m1 | m1 |
5+
| test.cpp:62:3:62:15 | MultipleCtors | Constructor does not initialize non-static data member $@ | test.cpp:65:16:65:17 | m1 | m1 |
6+
| test.cpp:74:3:74:21 | DefaultedCtorUninit | Constructor does not initialize non-static data member $@ | test.cpp:75:16:75:17 | m2 | m2 |
7+
| test.cpp:85:3:85:16 | CopyMoveUninit | Constructor does not initialize non-static data member $@ | test.cpp:87:16:87:17 | m1 | m1 |
8+
| test.cpp:86:3:86:16 | CopyMoveUninit | Constructor does not initialize non-static data member $@ | test.cpp:87:16:87:17 | m1 | m1 |
9+
| test.cpp:104:3:104:37 | DelegatingCtorSameClassNonCompliant | Constructor does not initialize non-static data member $@ | test.cpp:109:16:109:17 | m1 | m1 |
10+
| test.cpp:120:3:120:32 | DelegatingCtorBaseNonCompliant | Constructor does not initialize non-static data member $@ | test.cpp:121:16:121:17 | m1 | m1 |
11+
| test.cpp:147:3:147:62 | using DelegateToNonCompliantBase | Using declaration with base constructor does not initialize non-static data member $@ | test.cpp:148:16:148:17 | m1 | m1 |
12+
| test.cpp:202:24:202:25 | l4 | Aggregate variable does not initialize non-static data member $@ | test.cpp:177:16:177:17 | m1 | m1 |
13+
| test.cpp:207:24:207:25 | l9 | Aggregate variable does not initialize non-static data member $@ | test.cpp:177:16:177:17 | m1 | m1 |
14+
| test.cpp:210:3:210:26 | new | Aggregate new expression does not initialize non-static data member $@ | test.cpp:177:16:177:17 | m1 | m1 |
15+
| test.cpp:213:3:213:29 | new[] | Aggregate new expression does not initialize non-static data member $@ | test.cpp:177:16:177:17 | m1 | m1 |
16+
| test.cpp:217:36:217:38 | l12 | Aggregate variable does not initialize non-static data member $@ | test.cpp:186:24:186:25 | m1 | m1 |
17+
| test.cpp:220:36:220:38 | l15 | Aggregate variable does not initialize non-static data member $@ | test.cpp:186:24:186:25 | m1 | m1 |
18+
| test.cpp:222:3:222:38 | new | Aggregate new expression does not initialize non-static data member $@ | test.cpp:186:24:186:25 | m1 | m1 |
19+
| test.cpp:241:3:241:32 | HasAggregateMemberNonCompliant | Constructor does not initialize non-static data member $@ | test.cpp:242:24:242:25 | m1 | m1 |
20+
| test.cpp:241:3:241:32 | HasAggregateMemberNonCompliant | Constructor does not initialize non-static data member $@ | test.cpp:243:36:243:37 | m2 | m2 |
21+
| test.cpp:253:3:253:43 | HasUninitArrayAggregateMemberNonCompliant | Constructor does not initialize non-static data member $@ | test.cpp:254:24:254:25 | m1 | m1 |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-15-1-4/NonStaticMemberNotInitBeforeUse.ql

0 commit comments

Comments
 (0)