|
17 | 17 |
|
18 | 18 | import cpp
|
19 | 19 | import codingstandards.cpp.misra
|
| 20 | +import codingstandards.cpp.Call |
| 21 | +import codingstandards.cpp.misra.BuiltInTypeRules::MisraCpp23BuiltInTypes |
20 | 22 |
|
21 | 23 | /**
|
22 | 24 | * A comparison expression that has the minimum qualification as being a valid termination
|
@@ -59,7 +61,7 @@ class LegacyForLoopCondition extends RelationalOperation {
|
59 | 61 | predicate exprWithVarAccessMaybeImpure(Expr expr, Variable variable) {
|
60 | 62 | exists(VariableAccess varAccess |
|
61 | 63 | expr.mayBeImpure() and
|
62 |
| - expr.getAChild*() = varAccess and |
| 64 | + expr.getAChild*() = varAccess and // TODO: the `l` in the `i += l` is not mutated! |
63 | 65 | variable = varAccess.getTarget()
|
64 | 66 | )
|
65 | 67 | }
|
@@ -267,6 +269,61 @@ private predicate variableReferenceTakenAsNonConstArgument(
|
267 | 269 | )
|
268 | 270 | }
|
269 | 271 |
|
| 272 | +predicate loopVariableAssignedToPointerOrReferenceType( |
| 273 | + ForStmt forLoop, VariableAccess loopVariableAccessInCondition |
| 274 | +) { |
| 275 | + 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 | + isAssignment(assignmentRhs, targetType, _) and |
| 283 | + ( |
| 284 | + targetType instanceof PointerType or |
| 285 | + targetType instanceof ReferenceType |
| 286 | + ) and |
| 287 | + not targetType.getBaseType().isConst() |
| 288 | + ) |
| 289 | +} |
| 290 | + |
| 291 | +/* |
| 292 | + * An adapted part of `BuiltinTypeRules::MisraCpp23BuiltInTypes::isPreConversionAssignment` |
| 293 | + * that is only relevant to an argument passed to a parameter, seen as an assignment. |
| 294 | + * |
| 295 | + * This predicate adds two constraints to the target type, as compared to the original |
| 296 | + * portion of the predicate: |
| 297 | + * |
| 298 | + * 1. This predicate adds type constraint that the target type is a `ReferenceType`. |
| 299 | + * 2. This predicate adds the constraint that the target type is not `const`. |
| 300 | + * |
| 301 | + * Also, this predicate requires that the call is the body of the given for-loop. |
| 302 | + */ |
| 303 | + |
| 304 | +predicate loopVariablePassedAsArgumentToReferenceParameter( |
| 305 | + ForStmt forLoop, Expr loopVariableAccessInCondition |
| 306 | +) { |
| 307 | + exists(ReferenceType targetType | |
| 308 | + exists(Call call, int i | |
| 309 | + call.getArgument(i) = loopVariableAccessInCondition and |
| 310 | + call.getEnclosingStmt().getParent*() = forLoop.getStmt() and |
| 311 | + not targetType.getBaseType().isConst() |
| 312 | + | |
| 313 | + /* A regular function call */ |
| 314 | + targetType = call.getTarget().getParameter(i).getType() |
| 315 | + or |
| 316 | + /* A function call where the argument is passed as varargs */ |
| 317 | + call.getTarget().getNumberOfParameters() <= i and |
| 318 | + /* The rule states that the type should match the "adjusted" type of the argument */ |
| 319 | + targetType = loopVariableAccessInCondition.getFullyConverted().getType() |
| 320 | + or |
| 321 | + /* An expression call - get the function type, then the parameter type */ |
| 322 | + targetType = getExprCallFunctionType(call).getParameterType(i) |
| 323 | + ) |
| 324 | + ) |
| 325 | +} |
| 326 | + |
270 | 327 | from ForStmt forLoop
|
271 | 328 | where
|
272 | 329 | not isExcluded(forLoop, StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) and
|
@@ -332,63 +389,13 @@ where
|
332 | 389 | * or its address to a mutable pointer.
|
333 | 390 | */
|
334 | 391 |
|
335 |
| - /* 6-1. The loop counter is taken a mutable reference or its address to a mutable pointer. */ |
336 |
| - exists(VariableAccess loopCounterAccessInCondition | |
337 |
| - loopCounterAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() |
| 392 | + exists(VariableAccess loopVariableAccessInCondition | |
| 393 | + loopVariableAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() or |
| 394 | + loopVariableAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() or |
| 395 | + loopVariableAccessInCondition = getLoopStepOfForStmt(forLoop) |
338 | 396 | |
|
339 |
| - exists(VariableAccess loopCounterAccessTakenAddressOrReference | |
340 |
| - loopCounterAccessInCondition.getTarget() = |
341 |
| - loopCounterAccessTakenAddressOrReference.getTarget() |
342 |
| - | |
343 |
| - variableAddressTakenInNonConstDeclaration(forLoop, loopCounterAccessTakenAddressOrReference) |
344 |
| - or |
345 |
| - variableAddressTakenInExpression(forLoop, loopCounterAccessTakenAddressOrReference) and |
346 |
| - not variableAddressTakenAsConstArgument(forLoop, |
347 |
| - loopCounterAccessTakenAddressOrReference.getTarget().getAnAccess(), _) |
348 |
| - or |
349 |
| - variableReferenceTakenInNonConstDeclaration(forLoop, loopCounterAccessTakenAddressOrReference) |
350 |
| - or |
351 |
| - variableReferenceTakenAsNonConstArgument(forLoop, |
352 |
| - loopCounterAccessTakenAddressOrReference.getTarget().getAnAccess(), _) |
353 |
| - ) |
354 |
| - ) |
355 |
| - or |
356 |
| - /* 6-2. The loop bound is taken a mutable reference or its address to a mutable pointer. */ |
357 |
| - exists(VariableAccess loopBoundAccessInCondition | |
358 |
| - loopBoundAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() |
359 |
| - | |
360 |
| - exists(VariableAccess loopBoundAccessTakenAddressOrReference | |
361 |
| - loopBoundAccessInCondition.getTarget() = loopBoundAccessTakenAddressOrReference.getTarget() |
362 |
| - | |
363 |
| - variableAddressTakenInNonConstDeclaration(forLoop, loopBoundAccessTakenAddressOrReference) |
364 |
| - or |
365 |
| - variableAddressTakenInExpression(forLoop, loopBoundAccessTakenAddressOrReference) and |
366 |
| - not variableAddressTakenAsConstArgument(forLoop, |
367 |
| - loopBoundAccessTakenAddressOrReference.getTarget().getAnAccess(), _) |
368 |
| - or |
369 |
| - variableReferenceTakenInNonConstDeclaration(forLoop, loopBoundAccessTakenAddressOrReference) |
370 |
| - or |
371 |
| - variableReferenceTakenAsNonConstArgument(forLoop, loopBoundAccessTakenAddressOrReference, _) |
372 |
| - ) |
373 |
| - ) |
374 |
| - or |
375 |
| - /* 6-3. The loop step is taken a mutable reference or its address to a mutable pointer. */ |
376 |
| - exists(VariableAccess loopStepAccessInCondition | |
377 |
| - loopStepAccessInCondition = getLoopStepOfForStmt(forLoop) |
378 |
| - | |
379 |
| - exists(VariableAccess loopStepAccessTakenAddressOrReference | |
380 |
| - loopStepAccessInCondition.getTarget() = loopStepAccessTakenAddressOrReference.getTarget() |
381 |
| - | |
382 |
| - variableAddressTakenInNonConstDeclaration(forLoop, loopStepAccessTakenAddressOrReference) |
383 |
| - or |
384 |
| - variableAddressTakenInExpression(forLoop, loopStepAccessTakenAddressOrReference) and |
385 |
| - not variableAddressTakenAsConstArgument(forLoop, |
386 |
| - loopStepAccessTakenAddressOrReference.getTarget().getAnAccess(), _) |
387 |
| - or |
388 |
| - variableReferenceTakenInNonConstDeclaration(forLoop, loopStepAccessTakenAddressOrReference) |
389 |
| - or |
390 |
| - variableReferenceTakenAsNonConstArgument(forLoop, |
391 |
| - loopStepAccessTakenAddressOrReference.getTarget().getAnAccess(), _) |
392 |
| - ) |
| 397 | + loopVariableAssignedToPointerOrReferenceType(forLoop, loopVariableAccessInCondition) |
| 398 | + or |
| 399 | + loopVariablePassedAsArgumentToReferenceParameter(forLoop, loopVariableAccessInCondition) |
393 | 400 | )
|
394 | 401 | select forLoop, "TODO"
|
0 commit comments