16
16
*/
17
17
18
18
import cpp
19
+ import semmle.code.cpp.dataflow.internal.AddressFlow
19
20
import codingstandards.cpp.misra
20
21
import codingstandards.cpp.Call
22
+ import codingstandards.cpp.Loops
21
23
import codingstandards.cpp.misra.BuiltInTypeRules:: MisraCpp23BuiltInTypes
22
24
23
25
/**
@@ -36,7 +38,7 @@ class LegacyForLoopCondition extends RelationalOperation {
36
38
LegacyForLoopCondition ( ) {
37
39
loopCounter = this .getAnOperand ( ) and
38
40
loopBound = this .getAnOperand ( ) and
39
- loopCounter .getTarget ( ) = forLoop . getInitialization ( ) . ( DeclStmt ) . getADeclaration ( ) and
41
+ loopCounter .getTarget ( ) = getAnIterationVariable ( forLoop ) and
40
42
loopBound != loopCounter
41
43
}
42
44
@@ -52,18 +54,22 @@ class LegacyForLoopCondition extends RelationalOperation {
52
54
}
53
55
54
56
/**
55
- * Holds if the given expression is impure and contains an access to the variable, and
56
- * thus may mutate the variable.
57
- *
58
- * Note that this relation over-approximates and might include impure expressions that
59
- * in fact do not mutate the variable.
57
+ * Holds if the given expression may mutate the variable.
60
58
*/
61
- predicate exprWithVarAccessMaybeImpure ( Expr expr , Variable variable ) {
62
- exists ( VariableAccess varAccess |
63
- expr .mayBeImpure ( ) and
64
- expr .getAChild * ( ) = varAccess and // TODO: the `l` in the `i += l` is not mutated!
65
- variable = varAccess .getTarget ( )
66
- )
59
+ predicate variableModifiedInExpression ( Expr expr , VariableAccess va ) {
60
+ /*
61
+ * 1. Direct modification (assignment, increment, etc.) or a function call.
62
+ */
63
+
64
+ expr .getAChild + ( ) = va and
65
+ va .isModified ( )
66
+ or
67
+ /*
68
+ * 2. Address taken for non-const access that can potentially lead to modification.
69
+ * This overlaps with the former example on cases where `expr` is a function call.
70
+ */
71
+
72
+ valueToUpdate ( va , _, expr )
67
73
}
68
74
69
75
/**
@@ -79,212 +85,26 @@ Expr getLoopStepOfForStmt(ForStmt forLoop) {
79
85
result = forLoop .getUpdate ( ) .( AssignSubExpr ) .getRValue ( )
80
86
}
81
87
82
- /**
83
- * Holds if the given function has as parameter a pointer to a constant
84
- * value, at a given index.
85
- */
86
- private predicate functionHasConstPointerParameter ( Function function , int index ) {
87
- function .getParameter ( index ) .getType ( ) .( PointerType ) .getBaseType ( ) .isConst ( )
88
- }
89
-
90
- /**
91
- * Holds if the variable behind a given variable access is taken its address in
92
- * a non-const variable declaration, in the body of the for-loop.
93
- *
94
- * e.g.1. The loop counter variable `i` in the body is taken its address in the
95
- * declaration of a pointer variable `m`.
96
- * ``` C++
97
- * for (int i = 0; i < k; i += l) {
98
- * int *m = &i;
99
- * }
100
- * ```
101
- * e.g.2. The loop bound variable `k` in the body is taken its address in the
102
- * declaration of a pointer variable `m`.
103
- * ``` C++
104
- * for (int i = j; i < k; i += l) {
105
- * int *m = &k;
106
- * }
107
- * ```
108
- */
109
- predicate variableAddressTakenInNonConstDeclaration (
110
- ForStmt forLoop , VariableAccess baseVariableAccess
111
- ) {
112
- exists ( AddressOfExpr addressOfExpr , DeclStmt decl |
113
- decl .getParentStmt + ( ) = forLoop and
114
- decl .getADeclarationEntry ( ) .( VariableDeclarationEntry ) .getVariable ( ) .getInitializer ( ) .getExpr ( ) =
115
- addressOfExpr and
116
- addressOfExpr .getOperand ( ) = baseVariableAccess and
117
- not decl .getADeclarationEntry ( )
118
- .( VariableDeclarationEntry )
119
- .getVariable ( )
120
- .getType ( )
121
- .( PointerType )
122
- .getBaseType ( )
123
- .isConst ( )
124
- )
125
- }
126
-
127
- /**
128
- * Holds if the variable behind a given variable access is taken its address
129
- * as an argument of a call in either the body of the for-loop or in its update
130
- * expression.
131
- *
132
- * e.g.1. The address of the loop counter variable `i` is passed as argument
133
- * to the call to `g`.
134
- * ``` C++
135
- * void g1(int *x);
136
- *
137
- * for (int i = 0; i < k; i += l) {
138
- * g1(&i);
139
- * }
140
- * ```
141
- * e.g.2. The address of the loop counter variable `k` is passed as argument
142
- * to the call to `g`.
143
- * ``` C++
144
- * void g1(int *x);
145
- *
146
- * for (int i = j; i < k; i += l) {
147
- * g1(&k);
148
- * }
149
- * ```
150
- */
151
- private predicate variableAddressTakenAsConstArgument (
152
- ForStmt forLoop , VariableAccess baseVariableAccess , Call call
153
- ) {
154
- exists ( AddressOfExpr addressOfExpr , int index |
155
- call .getParent + ( ) = forLoop .getAChild + ( ) and // TODO: Bad
156
- call .getArgument ( index ) .getAChild * ( ) = addressOfExpr and
157
- exists ( PointerType parameterType |
158
- parameterType = call .getTarget ( ) .getParameter ( index ) .getType ( ) and
159
- not parameterType .getBaseType ( ) .isConst ( )
160
- ) and
161
- addressOfExpr .getOperand ( ) = baseVariableAccess .getTarget ( ) .getAnAccess ( ) and
162
- baseVariableAccess .getParent + ( ) = forLoop
163
- )
164
- }
165
-
166
- /**
167
- * Holds if the variable behind a given variable access is taken its address
168
- * as an argument of a complex expression in either the body of the for-loop or
169
- * in its update expression.
170
- *
171
- * e.g.1. The loop counter variable `i` in the body and the loop bound variable `k`
172
- * is taken its address in a call.
173
- * ``` C++
174
- * void g1(int *x);
175
- *
176
- * for (int i = j; i < k; i += l) {
177
- * g1(&i);
178
- * }
179
- * ```
180
- * e.g.2. The loop counter variable `i` in the body and the loop bound variable `k`
181
- * is taken its address in a compound expression.
182
- * ``` C++
183
- * for (int i = 0; i < k; i += l) {
184
- * *(cond ? &i : &k) += 1;
185
- * }
186
- * ```
187
- */
188
- /* TODO: Do we need to use Expr.getUnderlyingType() to ensure that the expression is non-const? */
189
- predicate variableAddressTakenInExpression ( ForStmt forLoop , VariableAccess baseVariableAccess ) {
190
- exists ( AddressOfExpr addressOfExpr |
191
- baseVariableAccess .getParent + ( ) = forLoop .getAChild + ( ) and // TODO: Bad
192
- addressOfExpr .getParent + ( ) = forLoop .getAChild + ( ) and
193
- addressOfExpr .getOperand ( ) = baseVariableAccess .getTarget ( ) .getAnAccess ( )
194
- )
195
- }
196
-
197
- /**
198
- * Holds if the variable behind a given variable access is taken its reference
199
- * in a non-const variable declaration, in the body of the for-loop.
200
- *
201
- * e.g.1. The loop counter variable `i` in the body is taken its reference in
202
- * the declaration of a variable `m`.
203
- * ``` C++
204
- * for (int i = j; i < k; i += l) {
205
- * int &m = i;
206
- * }
207
- * ```
208
- * e.g.2. The loop bound variable `k` in the body is taken its reference in the
209
- * declaration of a variable `m`.
210
- * ``` C++
211
- * for (int i = j; i < k; i += l) {
212
- * int &m = k;
213
- * }
214
- * ```
215
- */
216
- predicate variableReferenceTakenInNonConstDeclaration (
217
- ForStmt forLoop , VariableAccess baseVariableAccess
218
- ) {
219
- exists ( DeclStmt decl , Variable definedVariable , ReferenceType definedVariableType |
220
- decl .getParentStmt + ( ) = forLoop and
221
- not decl = forLoop .getInitialization ( ) and // Exclude the for-loop counter initialization.
222
- definedVariable = decl .getADeclarationEntry ( ) .( VariableDeclarationEntry ) .getVariable ( ) and
223
- definedVariable .getInitializer ( ) .getExpr ( ) = baseVariableAccess and
224
- definedVariableType = definedVariable .getType ( ) and
225
- not definedVariableType .getBaseType ( ) .isConst ( )
226
- )
227
- }
228
-
229
- /**
230
- * Holds if the variable behind a given variable access is taken its reference
231
- * as an argument of a call in either the body of the for-loop or in its update
232
- * expression.
233
- *
234
- * e.g.1. The loop counter variable `i` in the body is passed by reference to the
235
- * call to `f1`.
236
- * ``` C++
237
- * void f1(int &x);
238
- *
239
- * for (int i = j; i < k; i += l) {
240
- * f1(i);
241
- * }
242
- * ```
243
- * e.g.2. The loop bound variable `k` in the body is passed by reference to the
244
- * call to `f1`.
245
- * ``` C++
246
- * void f1(int &x);
247
- *
248
- * for (int i = j; i < k; i += l) {
249
- * f1(k);
250
- * }
251
- * ```
252
- */
253
- private predicate variableReferenceTakenAsNonConstArgument (
254
- ForStmt forLoop , VariableAccess baseVariableAccess , Call call
255
- ) {
256
- exists ( int index |
257
- call .getParent + ( ) = forLoop .getAChild + ( ) and
258
- call .getArgument ( index ) .getAChild * ( ) = baseVariableAccess .getTarget ( ) .getAnAccess ( ) and
259
- /*
260
- * The given function has as parameter a reference of a constant
261
- * value, at a given index.
262
- */
263
-
264
- exists ( ReferenceType parameterType |
265
- parameterType = call .getTarget ( ) .getParameter ( index ) .getType ( ) and
266
- not parameterType .getBaseType ( ) .isConst ( )
267
- ) and
268
- baseVariableAccess .getParent + ( ) = forLoop
269
- )
270
- }
271
-
272
- predicate loopVariableAssignedToPointerOrReferenceType (
88
+ predicate loopVariableAssignedToNonConstPointerOrReferenceType (
273
89
ForStmt forLoop , VariableAccess loopVariableAccessInCondition
274
90
) {
275
91
exists ( Expr assignmentRhs , DerivedType targetType |
276
- assignmentRhs .getEnclosingStmt ( ) .getParent * ( ) = forLoop .getStmt ( ) and
277
- (
278
- assignmentRhs .( AddressOfExpr ) .getOperand ( ) =
279
- loopVariableAccessInCondition .getTarget ( ) .getAnAccess ( ) or
280
- assignmentRhs = loopVariableAccessInCondition .getTarget ( ) .getAnAccess ( )
281
- ) and
282
92
isAssignment ( assignmentRhs , targetType , _) and
93
+ not targetType .getBaseType ( ) .isConst ( ) and
283
94
(
284
95
targetType instanceof PointerType or
285
96
targetType instanceof ReferenceType
286
- ) and
287
- not targetType .getBaseType ( ) .isConst ( )
97
+ )
98
+ |
99
+ assignmentRhs .getEnclosingStmt ( ) .getParent * ( ) = forLoop .getStmt ( ) and
100
+ (
101
+ /* 1. The address is taken: A loop variable access */
102
+ assignmentRhs .( AddressOfExpr ) .getOperand ( ) =
103
+ loopVariableAccessInCondition .getTarget ( ) .getAnAccess ( )
104
+ or
105
+ /* 2. The address is taken: A loop variable access */
106
+ assignmentRhs = loopVariableAccessInCondition .getTarget ( ) .getAnAccess ( )
107
+ )
288
108
)
289
109
}
290
110
@@ -301,12 +121,12 @@ predicate loopVariableAssignedToPointerOrReferenceType(
301
121
* Also, this predicate requires that the call is the body of the given for-loop.
302
122
*/
303
123
304
- predicate loopVariablePassedAsArgumentToReferenceParameter (
305
- ForStmt forLoop , Expr loopVariableAccessInCondition
124
+ predicate loopVariablePassedAsArgumentToNonConstReferenceParameter (
125
+ ForStmt forLoop , VariableAccess loopVariableAccessInCondition
306
126
) {
307
127
exists ( ReferenceType targetType |
308
128
exists ( Call call , int i |
309
- call .getArgument ( i ) = loopVariableAccessInCondition and
129
+ call .getArgument ( i ) = loopVariableAccessInCondition . getTarget ( ) . getAnAccess ( ) and
310
130
call .getEnclosingStmt ( ) .getParent * ( ) = forLoop .getStmt ( ) and
311
131
not targetType .getBaseType ( ) .isConst ( )
312
132
|
@@ -343,11 +163,8 @@ where
343
163
not forLoop .getCondition ( ) instanceof LegacyForLoopCondition
344
164
or
345
165
/* 3. The loop counter is mutated somewhere other than its update expression. */
346
- exists ( Expr mutatingExpr , Variable loopCounter |
347
- mutatingExpr = forLoop .getStmt ( ) .getChildStmt ( ) .getAChild ( ) and
348
- loopCounter = forLoop .getAnIterationVariable ( )
349
- |
350
- exprWithVarAccessMaybeImpure ( mutatingExpr , loopCounter )
166
+ exists ( Variable loopCounter |
167
+ isIrregularLoopCounterModification ( forLoop , loopCounter , loopCounter .getAnAccess ( ) )
351
168
)
352
169
or
353
170
/* 4. The type size of the loop counter is not greater or equal to that of the loop counter. */
@@ -360,27 +177,45 @@ where
360
177
)
361
178
)
362
179
or
363
- /* 5. The loop bound and the loop step is a variable that is mutated in the for loop. */
364
- exists ( Expr mutatingExpr |
365
- (
366
- /* 1. The mutating expression may be in the loop body. */
180
+ /*
181
+ * 5. The loop bound and the loop step are non-const expressions, or are variables that are
182
+ * mutated in the for loop.
183
+ */
184
+
185
+ /* 5-1. The mutating expression mutates the loop bound. */
186
+ exists ( Expr loopBound |
187
+ loopBound = forLoop .getCondition ( ) .( LegacyForLoopCondition ) .getLoopBound ( )
188
+ |
189
+ exists ( Expr mutatingExpr |
190
+ /* The mutating expression may be in the loop body. */
367
191
mutatingExpr = forLoop .getStmt ( ) .getChildStmt ( ) .getAChild * ( )
368
192
or
369
- /* 2. The mutating expression may be in the loop updating expression. */
193
+ /* The mutating expression may be in the loop updating expression. */
370
194
mutatingExpr = forLoop .getUpdate ( ) .getAChild * ( )
371
- )
372
- |
373
- /* 5-1. The mutating expression mutates the loop bound. */
374
- exists ( LegacyForLoopCondition forLoopCondition , Variable loopBoundVariable |
375
- forLoopCondition = forLoop .getCondition ( ) and
376
- loopBoundVariable = forLoopCondition .getLoopBound ( ) .( VariableAccess ) .getTarget ( )
377
195
|
378
- exprWithVarAccessMaybeImpure ( mutatingExpr , loopBoundVariable )
196
+ /* 5-1-1. The loop bound is a variable that is mutated in the for loop. */
197
+ variableModifiedInExpression ( mutatingExpr ,
198
+ loopBound .( VariableAccess ) .getTarget ( ) .getAnAccess ( ) )
199
+ or
200
+ /* 5-1-2. The loop bound is not a variable access and is not a constant expression. */
201
+ not loopBound instanceof VariableAccess and not loopBound .isConstant ( )
379
202
)
380
- or
381
- /* 5-2. The mutating expression mutates the loop step. */
382
- exists ( VariableAccess loopStep | loopStep = getLoopStepOfForStmt ( forLoop ) |
383
- exprWithVarAccessMaybeImpure ( mutatingExpr , loopStep .getTarget ( ) )
203
+ )
204
+ or
205
+ /* 5-2. The mutating expression mutates the loop step. */
206
+ exists ( Expr loopStep | loopStep = getLoopStepOfForStmt ( forLoop ) |
207
+ exists ( Expr mutatingExpr |
208
+ /* The mutating expression may be in the loop body. */
209
+ mutatingExpr = forLoop .getStmt ( ) .getChildStmt ( ) .getAChild * ( )
210
+ or
211
+ /* The mutating expression may be in the loop updating expression. */
212
+ mutatingExpr = forLoop .getUpdate ( ) .getAChild * ( )
213
+ |
214
+ /* 5-1-2. The loop step is a variable that is mutated in the for loop. */
215
+ variableModifiedInExpression ( mutatingExpr , loopStep .( VariableAccess ) .getTarget ( ) .getAnAccess ( ) )
216
+ or
217
+ /* 5-1-2. The loop bound is not a variable access and is not a constant expression. */
218
+ not loopStep instanceof VariableAccess and not loopStep .isConstant ( )
384
219
)
385
220
)
386
221
or
@@ -390,12 +225,17 @@ where
390
225
*/
391
226
392
227
exists ( VariableAccess loopVariableAccessInCondition |
393
- loopVariableAccessInCondition = forLoop .getCondition ( ) .( LegacyForLoopCondition ) .getLoopCounter ( ) or
394
- loopVariableAccessInCondition = forLoop .getCondition ( ) .( LegacyForLoopCondition ) .getLoopBound ( ) or
395
- loopVariableAccessInCondition = getLoopStepOfForStmt ( forLoop )
396
- |
397
- loopVariableAssignedToPointerOrReferenceType ( forLoop , loopVariableAccessInCondition )
398
- or
399
- loopVariablePassedAsArgumentToReferenceParameter ( forLoop , loopVariableAccessInCondition )
228
+ (
229
+ loopVariableAccessInCondition =
230
+ forLoop .getCondition ( ) .( LegacyForLoopCondition ) .getLoopCounter ( ) or
231
+ loopVariableAccessInCondition = forLoop .getCondition ( ) .( LegacyForLoopCondition ) .getLoopBound ( ) or
232
+ loopVariableAccessInCondition = getLoopStepOfForStmt ( forLoop )
233
+ ) and
234
+ (
235
+ loopVariableAssignedToNonConstPointerOrReferenceType ( forLoop , loopVariableAccessInCondition )
236
+ or
237
+ loopVariablePassedAsArgumentToNonConstReferenceParameter ( forLoop ,
238
+ loopVariableAccessInCondition )
239
+ )
400
240
)
401
241
select forLoop , "TODO"
0 commit comments