|
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