|
18 | 18 | import cpp
|
19 | 19 | import codingstandards.cpp.misra
|
20 | 20 |
|
21 |
| -from |
| 21 | +/** |
| 22 | + * A comparison expression that has the minimum qualification as being a valid termination |
| 23 | + * condition of a legacy for-loop. It is characterized by a value read from a variable being |
| 24 | + * compared to a value, which is supposed to be the loop bound. |
| 25 | + */ |
| 26 | +class LegacyForLoopCondition extends RelationalOperation { |
| 27 | + ForStmt forLoop; |
| 28 | + VariableAccess loopCounter; |
| 29 | + Expr loopBound; |
| 30 | + |
| 31 | + LegacyForLoopCondition() { |
| 32 | + loopCounter = this.getAnOperand() and |
| 33 | + loopBound = this.getAnOperand() and |
| 34 | + loopCounter.getTarget() = forLoop.getInitialization().(DeclStmt).getADeclaration() and |
| 35 | + loopBound != loopCounter |
| 36 | + } |
| 37 | + |
| 38 | + VariableAccess getLoopCounter() { result = loopCounter } |
| 39 | + |
| 40 | + Expr getLoopBound() { result = loopBound } |
| 41 | +} |
| 42 | + |
| 43 | +/** |
| 44 | + * Holds if the given expression is impure and contains an access to the variable, and |
| 45 | + * thus may mutate the variable. |
| 46 | + * |
| 47 | + * Note that this relation over-approximates and might include impure expressions that |
| 48 | + * in fact do not mutate the variable. |
| 49 | + */ |
| 50 | +predicate exprWithVarAccessMaybeImpure(Expr expr, Variable variable) { |
| 51 | + exists(VariableAccess varAccess | |
| 52 | + expr.mayBeImpure() and |
| 53 | + expr.getAChild*() = varAccess and |
| 54 | + variable = varAccess.getTarget() |
| 55 | + ) |
| 56 | +} |
| 57 | + |
| 58 | +/** |
| 59 | + * Gets the loop step of a legacy for loop. |
| 60 | + * |
| 61 | + * This predicate assumes the update expression of the given for loop is an add-and-assign |
| 62 | + * (`+=`) or sub-and-assign (`-=`) expression, so the update expression that is an increment |
| 63 | + * (`++`) or a decrement (`--`) operation should be handled using different means than this |
| 64 | + * predicate. |
| 65 | + */ |
| 66 | +Expr getLoopStepOfForStmt(ForStmt forLoop) { |
| 67 | + result = forLoop.getUpdate().(AssignAddExpr).getRValue() or |
| 68 | + result = forLoop.getUpdate().(AssignSubExpr).getRValue() |
| 69 | +} |
| 70 | + |
| 71 | +/** |
| 72 | + * Holds if the given function has as parameter at a given index a pointer to a |
| 73 | + * constant value or a reference of a constant value. |
| 74 | + */ |
| 75 | +predicate functionHasConstPointerOrReferenceParameter(Function function, int index) { |
| 76 | + function.getParameter(index).getType().(PointerType).getBaseType().isConst() or |
| 77 | + function.getParameter(index).getType().(ReferenceType).getBaseType().isConst() |
| 78 | +} |
| 79 | + |
| 80 | +/** |
| 81 | + * Holds if the the variable behind a given variable access is taken its address |
| 82 | + * in a declaration in either the body of the for-loop or in its update expression. |
| 83 | + * |
| 84 | + * e.g.1. The loop counter variable `i` in the body is taken its address in the |
| 85 | + * declaration of a pointer variable `m`. |
| 86 | + * ``` C++ |
| 87 | + * for (int i = 0; i < k; i += l) { |
| 88 | + * int *m = &i; |
| 89 | + * } |
| 90 | + * ``` |
| 91 | + * e.g.2. The loop bound variable `k` in the body is taken its address in the |
| 92 | + * declaration of a pointer variable `m`. |
| 93 | + * ``` C++ |
| 94 | + * for (int i = j; i < k; i += l) { |
| 95 | + * int *m = &k; |
| 96 | + * } |
| 97 | + * ``` |
| 98 | + */ |
| 99 | +predicate variableAddressTakenInDeclaration(ForStmt forLoop, VariableAccess baseVariableAccess) { |
| 100 | + exists(AddressOfExpr addressOfExpr, DeclStmt decl | |
| 101 | + decl.getParentStmt+() = forLoop and |
| 102 | + decl.getADeclarationEntry().(VariableDeclarationEntry).getVariable().getInitializer().getExpr() = |
| 103 | + addressOfExpr and |
| 104 | + baseVariableAccess.getTarget() = |
| 105 | + forLoop.getCondition().(LegacyForLoopCondition).getLoopBound().(VariableAccess).getTarget() |
| 106 | + ) |
| 107 | +} |
| 108 | + |
| 109 | +/** |
| 110 | + * Holds if the the variable behind a given variable access is taken its address |
| 111 | + * as an argument of a call in either the body of the for-loop or in its update |
| 112 | + * expression. |
| 113 | + * |
| 114 | + * e.g.1. The loop counter variable `i` in the body is taken its address in the |
| 115 | + * declaration of a pointer variable `m`. |
| 116 | + * ``` C++ |
| 117 | + * for (int i = 0; i < k; i += l) { |
| 118 | + * g(&i); |
| 119 | + * } |
| 120 | + * ``` |
| 121 | + * e.g.2. The loop bound variable `k` in the body is taken its address in the |
| 122 | + * declaration of a pointer variable `m`. |
| 123 | + * ``` C++ |
| 124 | + * for (int i = j; i < k; i += l) { |
| 125 | + * g(&k); |
| 126 | + * } |
| 127 | + * ``` |
| 128 | + */ |
| 129 | +predicate variableAddressTakenAsConstArgument( |
| 130 | + ForStmt forLoop, VariableAccess baseVariableAccess, Call call |
| 131 | +) { |
| 132 | + exists(AddressOfExpr addressOfExpr, int index | |
| 133 | + call.getParent+() = forLoop.getAChild+() and |
| 134 | + call.getArgument(index).getAChild*() = addressOfExpr and |
| 135 | + functionHasConstPointerOrReferenceParameter(call.getTarget(), index) and |
| 136 | + addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess() |
| 137 | + ) |
| 138 | +} |
| 139 | + |
| 140 | +/** |
| 141 | + * Holds if the the variable behind a given variable access is taken its address |
| 142 | + * as an argument of a complex expression in either the body of the for-loop or |
| 143 | + * in its update expression. |
| 144 | + * |
| 145 | + * e.g. The loop counter variable `i` in the body and the loop bound variable `k` |
| 146 | + * is taken its address in a compound expression. |
| 147 | + * ``` C++ |
| 148 | + * for (int i = 0; i < k; i += l) { |
| 149 | + * *(cond ? &i : &k) += 1; |
| 150 | + * } |
| 151 | + * ``` |
| 152 | + */ |
| 153 | +predicate variableAddressTakenInExpression(ForStmt forLoop, VariableAccess baseVariableAccess) { |
| 154 | + exists(AddressOfExpr addressOfExpr | |
| 155 | + baseVariableAccess.getParent+() = forLoop.getAChild+() and |
| 156 | + addressOfExpr.getParent+() = forLoop.getAChild+() and |
| 157 | + addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess() |
| 158 | + ) and |
| 159 | + not exists(Call call | variableAddressTakenAsConstArgument(forLoop, baseVariableAccess, call)) |
| 160 | +} |
| 161 | + |
| 162 | +from ForStmt forLoop |
22 | 163 | where
|
23 |
| - not isExcluded(x, StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) and |
24 |
| -select |
| 164 | + not isExcluded(forLoop, StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) and |
| 165 | + /* 1. There is a counter variable that is not of an integer type. */ |
| 166 | + exists(Type type | type = forLoop.getAnIterationVariable().getType() | |
| 167 | + not ( |
| 168 | + type instanceof IntegralType or |
| 169 | + type instanceof FixedWidthIntegralType |
| 170 | + ) |
| 171 | + ) |
| 172 | + or |
| 173 | + /* |
| 174 | + * 2. The loop condition checks termination without comparing the counter variable and the |
| 175 | + * loop bound using a relational operator. |
| 176 | + */ |
| 177 | + |
| 178 | + not forLoop.getCondition() instanceof LegacyForLoopCondition |
| 179 | + or |
| 180 | + /* 3. The loop counter is mutated somewhere other than its update expression. */ |
| 181 | + exists(Expr mutatingExpr, Variable loopCounter | |
| 182 | + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild() and |
| 183 | + loopCounter = forLoop.getAnIterationVariable() |
| 184 | + | |
| 185 | + exprWithVarAccessMaybeImpure(mutatingExpr, loopCounter) |
| 186 | + ) |
| 187 | + or |
| 188 | + /* 4. The type size of the loop counter is not greater or equal to that of the loop counter. */ |
| 189 | + exists(LegacyForLoopCondition forLoopCondition | forLoopCondition = forLoop.getCondition() | |
| 190 | + exists(Type loopCounterType, Type loopBoundType | |
| 191 | + loopCounterType = forLoopCondition.getLoopCounter().getType() and |
| 192 | + loopBoundType = forLoopCondition.getLoopBound().getType() |
| 193 | + | |
| 194 | + loopCounterType.getSize() < loopBoundType.getSize() |
| 195 | + ) |
| 196 | + ) |
| 197 | + or |
| 198 | + /* 5. The loop bound and the loop step is a variable that is mutated in the for loop. */ |
| 199 | + exists(Expr mutatingExpr | |
| 200 | + ( |
| 201 | + /* 1. The mutating expression may be in the loop body. */ |
| 202 | + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() |
| 203 | + or |
| 204 | + /* 2. The mutating expression may be in the loop updating expression. */ |
| 205 | + mutatingExpr = forLoop.getUpdate().getAChild*() |
| 206 | + ) |
| 207 | + | |
| 208 | + /* 5-1. The mutating expression mutates the loop bound. */ |
| 209 | + exists(LegacyForLoopCondition forLoopCondition, Variable loopBoundVariable | |
| 210 | + forLoopCondition = forLoop.getCondition() and |
| 211 | + loopBoundVariable = forLoopCondition.getLoopBound().(VariableAccess).getTarget() |
| 212 | + | |
| 213 | + exprWithVarAccessMaybeImpure(mutatingExpr, loopBoundVariable) |
| 214 | + ) |
| 215 | + or |
| 216 | + /* 5-2. The mutating expression mutates the loop step. */ |
| 217 | + exists(VariableAccess loopStep | loopStep = getLoopStepOfForStmt(forLoop) | |
| 218 | + exprWithVarAccessMaybeImpure(mutatingExpr, loopStep.getTarget()) |
| 219 | + ) |
| 220 | + ) |
| 221 | + or |
| 222 | + /* |
| 223 | + * 6. Any of the loop counter, loop bound, or a loop step is taken as a mutable reference |
| 224 | + * or its address to a mutable pointer. |
| 225 | + */ |
| 226 | + |
| 227 | + /* 6-1. The loop counter is taken a mutable reference or its address to a mutable pointer. */ |
| 228 | + variableAddressTakenInDeclaration(forLoop, |
| 229 | + forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter()) |
| 230 | + or |
| 231 | + /* 6-2. The loop bound is taken a mutable reference or its address to a mutable pointer. */ |
| 232 | + none() |
| 233 | + or |
| 234 | + /* 6-3. The loop step is taken a mutable reference or its address to a mutable pointer. */ |
| 235 | + none() |
| 236 | +select forLoop, "TODO" |
| 237 | + |
| 238 | +private module Notebook { |
| 239 | + private predicate test(Function function) { |
| 240 | + function.getParameter(_).getType().(PointerType).getBaseType().isConst() or |
| 241 | + function.getParameter(_).getType().(ReferenceType).getBaseType().isConst() |
| 242 | + } |
| 243 | + |
| 244 | + private predicate test2(Expr expr, string qlClasses) { |
| 245 | + expr.getType().isConst() and |
| 246 | + qlClasses = expr.getPrimaryQlClasses() |
| 247 | + } |
| 248 | + |
| 249 | + private predicate test3(Function function, string qlClasses) { |
| 250 | + qlClasses = function.getParameter(_).getType().getAQlClass() |
| 251 | + } |
| 252 | +} |
0 commit comments