1616 */
1717
1818import cpp
19+ import semmle.code.cpp.dataflow.internal.AddressFlow
1920import codingstandards.cpp.misra
2021import codingstandards.cpp.Call
22+ import codingstandards.cpp.Loops
2123import codingstandards.cpp.misra.BuiltInTypeRules:: MisraCpp23BuiltInTypes
2224
2325/**
@@ -36,7 +38,7 @@ class LegacyForLoopCondition extends RelationalOperation {
3638 LegacyForLoopCondition ( ) {
3739 loopCounter = this .getAnOperand ( ) and
3840 loopBound = this .getAnOperand ( ) and
39- loopCounter .getTarget ( ) = forLoop . getInitialization ( ) . ( DeclStmt ) . getADeclaration ( ) and
41+ loopCounter .getTarget ( ) = getAnIterationVariable ( forLoop ) and
4042 loopBound != loopCounter
4143 }
4244
@@ -52,18 +54,22 @@ class LegacyForLoopCondition extends RelationalOperation {
5254}
5355
5456/**
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.
6058 */
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 )
6773}
6874
6975/**
@@ -79,212 +85,26 @@ Expr getLoopStepOfForStmt(ForStmt forLoop) {
7985 result = forLoop .getUpdate ( ) .( AssignSubExpr ) .getRValue ( )
8086}
8187
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 (
27389 ForStmt forLoop , VariableAccess loopVariableAccessInCondition
27490) {
27591 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
28292 isAssignment ( assignmentRhs , targetType , _) and
93+ not targetType .getBaseType ( ) .isConst ( ) and
28394 (
28495 targetType instanceof PointerType or
28596 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+ )
288108 )
289109}
290110
@@ -301,12 +121,12 @@ predicate loopVariableAssignedToPointerOrReferenceType(
301121 * Also, this predicate requires that the call is the body of the given for-loop.
302122 */
303123
304- predicate loopVariablePassedAsArgumentToReferenceParameter (
305- ForStmt forLoop , Expr loopVariableAccessInCondition
124+ predicate loopVariablePassedAsArgumentToNonConstReferenceParameter (
125+ ForStmt forLoop , VariableAccess loopVariableAccessInCondition
306126) {
307127 exists ( ReferenceType targetType |
308128 exists ( Call call , int i |
309- call .getArgument ( i ) = loopVariableAccessInCondition and
129+ call .getArgument ( i ) = loopVariableAccessInCondition . getTarget ( ) . getAnAccess ( ) and
310130 call .getEnclosingStmt ( ) .getParent * ( ) = forLoop .getStmt ( ) and
311131 not targetType .getBaseType ( ) .isConst ( )
312132 |
@@ -343,11 +163,8 @@ where
343163 not forLoop .getCondition ( ) instanceof LegacyForLoopCondition
344164 or
345165 /* 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 ( ) )
351168 )
352169 or
353170 /* 4. The type size of the loop counter is not greater or equal to that of the loop counter. */
@@ -360,27 +177,45 @@ where
360177 )
361178 )
362179 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. */
367191 mutatingExpr = forLoop .getStmt ( ) .getChildStmt ( ) .getAChild * ( )
368192 or
369- /* 2. The mutating expression may be in the loop updating expression. */
193+ /* The mutating expression may be in the loop updating expression. */
370194 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 ( )
377195 |
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 ( )
379202 )
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 ( )
384219 )
385220 )
386221 or
@@ -390,12 +225,17 @@ where
390225 */
391226
392227 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+ )
400240 )
401241select forLoop , "TODO"
0 commit comments