|
| 1 | +/** |
| 2 | + * @id c/misra/unsequenced-side-effects |
| 3 | + * @name RULE-13-2: The value of an expression and its persistent side effects depend on its evaluation order |
| 4 | + * @description The value of an expression and its persistent side effects are depending on the |
| 5 | + * evaluation order resulting in unpredictable behavior. |
| 6 | + * @kind problem |
| 7 | + * @precision very-high |
| 8 | + * @problem.severity error |
| 9 | + * @tags external/misra/id/rule-13-2 |
| 10 | + * correctness |
| 11 | + * external/misra/obligation/required |
| 12 | + */ |
| 13 | + |
| 14 | +import cpp |
| 15 | +import codingstandards.c.misra |
| 16 | +import codingstandards.c.Expr |
| 17 | +import codingstandards.c.SideEffects |
| 18 | +import codingstandards.c.Ordering |
| 19 | + |
| 20 | +predicate isCandidatePair(Expr parentExpr, Expr e1, Expr e2) { |
| 21 | + parentExpr.getAChild+() = e1 and |
| 22 | + parentExpr.getAChild+() = e2 |
| 23 | +} |
| 24 | + |
| 25 | +class ConstituentExprOrdering extends Ordering::Configuration { |
| 26 | + ConstituentExprOrdering() { this = "ConstituentExprOrdering" } |
| 27 | + |
| 28 | + override predicate isCandidate(Expr e1, Expr e2) { |
| 29 | + // Two different expressions part of the same full expression. |
| 30 | + // Compute differerence using successor relation to break the symmetry of the candidate relation. |
| 31 | + isCandidatePair(_, e1, e2) |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +from |
| 36 | + ConstituentExprOrdering orderingConfig, FullExpr fullExpr, VariableEffect variableEffect1, |
| 37 | + VariableEffect variableEffect2 |
| 38 | +where |
| 39 | + not isExcluded(fullExpr, SideEffects3Package::unsequencedSideEffectsQuery()) and |
| 40 | + // If the effect is local we can directly check if it is unsequenced. |
| 41 | + // If the effect is not local (happens in a different function) we use the access as a proxy. |
| 42 | + orderingConfig.isUnsequenced(variableEffect1, variableEffect2) and |
| 43 | + fullExpr.getAChild+() = variableEffect1 and |
| 44 | + fullExpr.getAChild+() = variableEffect2 and |
| 45 | + // Both are evaluated |
| 46 | + not exists(ConditionalExpr ce | |
| 47 | + ce.getThen().getAChild*() = variableEffect1 and ce.getElse().getAChild*() = variableEffect2 |
| 48 | + ) and |
| 49 | + // Break the symmetry of the ordering relation by requiring that the first expression is located before the second. |
| 50 | + // This builds upon the assumption that the expressions are part of the same full expression as specified in the ordering configuration. |
| 51 | + exists(int offset1, int offset2 | |
| 52 | + variableEffect1.getLocation().charLoc(_, offset1, _) and |
| 53 | + variableEffect2.getLocation().charLoc(_, offset2, _) and |
| 54 | + offset1 < offset2 |
| 55 | + ) |
| 56 | +select fullExpr, "The expression contains unsequenced $@ to $@ and $@ to $@.", variableEffect1, |
| 57 | + "side effect", variableEffect1.getAnAccess(), variableEffect1.getTarget().getName(), |
| 58 | + variableEffect2, "side effect", variableEffect2.getAnAccess(), |
| 59 | + variableEffect2.getTarget().getName() |
0 commit comments