|
5 | 5 | * @kind problem |
6 | 6 | * @problem.severity error |
7 | 7 | * @id rb/uninitialized-local-variable |
8 | | - * @tags reliability |
| 8 | + * @tags quality |
| 9 | + * reliability |
9 | 10 | * correctness |
10 | | - * @precision low |
| 11 | + * @precision high |
11 | 12 | */ |
12 | 13 |
|
13 | 14 | import codeql.ruby.AST |
14 | 15 | import codeql.ruby.dataflow.SSA |
| 16 | +private import codeql.ruby.dataflow.internal.DataFlowPublic |
| 17 | +import codeql.ruby.controlflow.internal.Guards as Guards |
| 18 | +import codeql.ruby.controlflow.CfgNodes |
| 19 | + |
| 20 | +predicate isInBooleanContext(Expr e) { |
| 21 | + e = any(ConditionalExpr c).getCondition() |
| 22 | + or |
| 23 | + e = any(ConditionalLoop l).getCondition() |
| 24 | + or |
| 25 | + e = any(LogicalAndExpr n).getAnOperand() |
| 26 | + or |
| 27 | + e = any(LogicalOrExpr n).getAnOperand() |
| 28 | + or |
| 29 | + e = any(NotExpr n).getOperand() |
| 30 | +} |
| 31 | + |
| 32 | +predicate isGuarded(LocalVariableReadAccess read) { |
| 33 | + exists(AstCfgNode guard, boolean branch | |
| 34 | + Guards::guardControlsBlock(guard, read.getAControlFlowNode().getBasicBlock(), branch) |
| 35 | + | |
| 36 | + // guard is `var` |
| 37 | + guard.getAstNode() = read.getVariable().getAnAccess() and |
| 38 | + branch = true |
| 39 | + or |
| 40 | + // guard is `!var` |
| 41 | + guard.getAstNode().(NotExpr).getOperand() = read.getVariable().getAnAccess() and |
| 42 | + branch = false |
| 43 | + or |
| 44 | + // guard is `var.nil?` |
| 45 | + exists(MethodCall c | guard.getAstNode() = c | |
| 46 | + c.getReceiver() = read.getVariable().getAnAccess() and |
| 47 | + c.getMethodName() = "nil?" |
| 48 | + ) and |
| 49 | + branch = false |
| 50 | + or |
| 51 | + // guard is `!var.nil?` |
| 52 | + exists(MethodCall c | guard.getAstNode().(NotExpr).getOperand() = c | |
| 53 | + c.getReceiver() = read.getVariable().getAnAccess() and |
| 54 | + c.getMethodName() = "nil?" |
| 55 | + ) and |
| 56 | + branch = true |
| 57 | + ) |
| 58 | +} |
| 59 | + |
| 60 | +predicate isNilChecked(LocalVariableReadAccess read) { |
| 61 | + exists(MethodCall c | c.getReceiver() = read | |
| 62 | + c.getMethodName() = "nil?" |
| 63 | + or |
| 64 | + c.isSafeNavigation() |
| 65 | + ) |
| 66 | +} |
15 | 67 |
|
16 | 68 | class RelevantLocalVariableReadAccess extends LocalVariableReadAccess { |
17 | 69 | RelevantLocalVariableReadAccess() { |
18 | | - not exists(MethodCall c | |
19 | | - c.getReceiver() = this and |
20 | | - c.getMethodName() = "nil?" |
21 | | - ) |
| 70 | + not isInBooleanContext(this) and |
| 71 | + not isNilChecked(this) and |
| 72 | + not isGuarded(this) |
22 | 73 | } |
23 | 74 | } |
24 | 75 |
|
|
0 commit comments