|
| 1 | +/** |
| 2 | + * @name Errors After Refactoring |
| 3 | + * @description --In some situations, after code refactoring, parts of the old constructs may remain. |
| 4 | + * --They are correctly accepted by the compiler, but can critically affect program execution. |
| 5 | + * --For example, if you switch from `do {...} while ();` to `while () {...}` with errors, you run the risk of running out of resources. |
| 6 | + * --These code snippets look suspicious and require the developer's attention. |
| 7 | + * @kind problem |
| 8 | + * @id cpp/errors-after-refactoring |
| 9 | + * @problem.severity warning |
| 10 | + * @precision medium |
| 11 | + * @tags correctness |
| 12 | + * security |
| 13 | + * external/cwe/cwe-691 |
| 14 | + */ |
| 15 | + |
| 16 | +import cpp |
| 17 | +import semmle.code.cpp.valuenumbering.HashCons |
| 18 | +import semmle.code.cpp.valuenumbering.GlobalValueNumbering |
| 19 | + |
| 20 | +/** |
| 21 | + * Using `while` directly after the body of another` while`. |
| 22 | + */ |
| 23 | +class UsingWhileAfterWhile extends WhileStmt { |
| 24 | + /** |
| 25 | + * Using a loop call after another loop has finished running can result in an eternal loop. |
| 26 | + * For example, perhaps as a result of refactoring, the `do ... while ()` loop was incorrectly corrected. |
| 27 | + * Even in the case of deliberate use of such an expression, it is better to correct it. |
| 28 | + */ |
| 29 | + UsingWhileAfterWhile() { |
| 30 | + exists(WhileStmt wh1 | |
| 31 | + wh1.getStmt().getAChild*().(BreakStmt).(ControlFlowNode).getASuccessor().getASuccessor() = |
| 32 | + this and |
| 33 | + hashCons(wh1.getCondition()) = hashCons(this.getCondition()) and |
| 34 | + this.getStmt() instanceof EmptyStmt |
| 35 | + ) |
| 36 | + or |
| 37 | + exists(ForStmt fr1 | |
| 38 | + fr1.getStmt().getAChild*().(BreakStmt).(ControlFlowNode).getASuccessor().getASuccessor() = |
| 39 | + this and |
| 40 | + hashCons(fr1.getCondition()) = hashCons(this.getCondition()) and |
| 41 | + this.getStmt() instanceof EmptyStmt |
| 42 | + ) |
| 43 | + } |
| 44 | +} |
| 45 | + |
| 46 | +/** |
| 47 | + * Using arithmetic in a condition. |
| 48 | + */ |
| 49 | +class UsingArithmeticInComparison extends BinaryArithmeticOperation { |
| 50 | + /** |
| 51 | + * Using arithmetic operations in a comparison operation can be dangerous. |
| 52 | + * For example, part of the comparison may have been lost as a result of refactoring. |
| 53 | + * Even if you deliberately use such an expression, it is better to add an explicit comparison. |
| 54 | + */ |
| 55 | + UsingArithmeticInComparison() { |
| 56 | + this.getParent*() instanceof IfStmt and |
| 57 | + not this.getAChild*().isConstant() and |
| 58 | + not this.getParent*() instanceof Call and |
| 59 | + not this.getParent*() instanceof AssignExpr and |
| 60 | + not this.getParent*() instanceof ArrayExpr and |
| 61 | + not this.getParent*() instanceof RemExpr and |
| 62 | + not this.getParent*() instanceof AssignBitwiseOperation and |
| 63 | + not this.getParent*() instanceof AssignArithmeticOperation and |
| 64 | + not this.getParent*() instanceof EqualityOperation and |
| 65 | + not this.getParent*() instanceof RelationalOperation |
| 66 | + } |
| 67 | + |
| 68 | + /** Holds when the expression is inside the loop body. */ |
| 69 | + predicate insideTheLoop() { exists(Loop lp | lp.getStmt().getAChild*() = this.getParent*()) } |
| 70 | + |
| 71 | + /** Holds when the expression is used in binary operations. */ |
| 72 | + predicate workingWithValue() { |
| 73 | + this.getParent*() instanceof BinaryBitwiseOperation or |
| 74 | + this.getParent*() instanceof NotExpr |
| 75 | + } |
| 76 | + |
| 77 | + /** Holds when the expression contains a pointer. */ |
| 78 | + predicate workingWithPointer() { |
| 79 | + this.getAChild*().getFullyConverted().getType() instanceof DerivedType |
| 80 | + } |
| 81 | + |
| 82 | + /** Holds when a null comparison expression exists. */ |
| 83 | + predicate compareWithZero() { |
| 84 | + exists(Expr exp | |
| 85 | + exp instanceof ComparisonOperation and |
| 86 | + ( |
| 87 | + globalValueNumber(exp.getAChild*()) = globalValueNumber(this) or |
| 88 | + hashCons(exp.getAChild*()) = hashCons(this) |
| 89 | + ) and |
| 90 | + ( |
| 91 | + exp.(ComparisonOperation).getLeftOperand().getValue() = "0" or |
| 92 | + exp.(ComparisonOperation).getRightOperand().getValue() = "0" |
| 93 | + ) |
| 94 | + ) |
| 95 | + } |
| 96 | + |
| 97 | + /** Holds when a comparison expression exists. */ |
| 98 | + predicate compareWithOutZero() { |
| 99 | + exists(Expr exp | |
| 100 | + exp instanceof ComparisonOperation and |
| 101 | + ( |
| 102 | + globalValueNumber(exp.getAChild*()) = globalValueNumber(this) or |
| 103 | + hashCons(exp.getAChild*()) = hashCons(this) |
| 104 | + ) |
| 105 | + ) |
| 106 | + } |
| 107 | +} |
| 108 | + |
| 109 | +from Expr exp |
| 110 | +where |
| 111 | + exp instanceof UsingArithmeticInComparison and |
| 112 | + not exp.(UsingArithmeticInComparison).workingWithValue() and |
| 113 | + not exp.(UsingArithmeticInComparison).workingWithPointer() and |
| 114 | + not exp.(UsingArithmeticInComparison).insideTheLoop() and |
| 115 | + not exp.(UsingArithmeticInComparison).compareWithZero() and |
| 116 | + exp.(UsingArithmeticInComparison).compareWithOutZero() |
| 117 | + or |
| 118 | + exists(WhileStmt wst | wst instanceof UsingWhileAfterWhile and exp = wst.getCondition()) |
| 119 | +select exp, "this expression needs your attention" |
0 commit comments