From 01066ea3bb1b2e38283d8d247bb3b268b4ea2dab Mon Sep 17 00:00:00 2001 From: Arthur Baars Date: Mon, 30 Nov 2020 16:14:34 +0100 Subject: [PATCH] CFG: case expression --- .../controlflow/internal/Completion.qll | 2 + .../internal/ControlFlowGraphImpl.qll | 72 +++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/ql/src/codeql_ruby/controlflow/internal/Completion.qll b/ql/src/codeql_ruby/controlflow/internal/Completion.qll index 78684220c91..abdc02b3358 100644 --- a/ql/src/codeql_ruby/controlflow/internal/Completion.qll +++ b/ql/src/codeql_ruby/controlflow/internal/Completion.qll @@ -137,6 +137,8 @@ private predicate inBooleanContext(AstNode n) { n = any(LogicalNotAstNode parent | inBooleanContext(parent)).getOperand() or n = any(ParenthesizedStatement parent | inBooleanContext(parent)).getChild() + or + n instanceof Pattern } /** diff --git a/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll b/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll index a842532eeb1..9a1534cad08 100644 --- a/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll +++ b/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll @@ -276,6 +276,44 @@ private module Trees { } } + private class CaseTree extends PreOrderTree, Case { + final override predicate propagatesAbnormal(AstNode child) { + child = this.getValue() or child = this.getChild(_).(When).getPattern(_) + } + + final override predicate last(AstNode last, Completion c) { + last(this.getValue(), last, c) and not exists(this.getChild(_)) + or + last(this.getChild(_), last, c) and c instanceof SimpleCompletion + or + exists(int i, ControlFlowTree lastBranch | + lastBranch = this.getChild(i) and not exists(this.getChild(i + 1)) + | + last(lastBranch, last, c) and + c instanceof FalseCompletion + ) + } + + final override predicate succ(AstNode pred, AstNode succ, Completion c) { + pred = this and + first(this.getValue(), succ) and + c instanceof SimpleCompletion + or + pred = this and + first(this.getChild(0), succ) and + not exists(this.getValue()) and + c instanceof SimpleCompletion + or + last(this.getValue(), pred, c) and + first(this.getChild(0), succ) and + c instanceof SimpleCompletion + or + exists(int i, ControlFlowTree branch | branch = this.getChild(i) | + last(branch, pred, c) and first(this.getChild(i + 1), succ) and c instanceof FalseCompletion + ) + } + } + private class ClassTree extends StandardPreOrderTree, Class { final override AstNode getChildNode(int i) { result = this.getChild(i) } @@ -529,6 +567,10 @@ private module Trees { final override AstNode getChildNode(int i) { result = this.getChild(i) } } + private class PatternTree extends StandardPostOrderTree, Pattern { + final override AstNode getChildNode(int i) { result = this.getChild() and i = 0 } + } + private class ProgramTree extends StandardPreOrderTree, Program { final override AstNode getChildNode(int i) { result = this.getChild(i) } @@ -569,6 +611,36 @@ private module Trees { final override AstNode getChildNode(int i) { result = this.getOperand() and i = 0 } } + private class WhenTree extends PreOrderTree, When { + final override predicate propagatesAbnormal(AstNode child) { child = this.getPattern(_) } + + final override predicate last(AstNode last, Completion c) { + exists(int i | + not exists(this.getPattern(i + 1)) and + last(this.getPattern(i), last, c) and + c instanceof FalseCompletion + ) + or + last(this.getBody(), last, c) + } + + final override predicate succ(AstNode pred, AstNode succ, Completion c) { + pred = this and + first(this.getPattern(0), succ) and + c instanceof SimpleCompletion + or + exists(int i, Pattern p | + p = this.getPattern(i) and + last(p, pred, c) + | + c instanceof TrueCompletion and first(this.getBody(), succ) + or + c instanceof FalseCompletion and + first(this.getPattern(i + 1), succ) + ) + } + } + private class ConditionalLoopTree extends PreOrderTree, ConditionalLoopAstNode { final override predicate propagatesAbnormal(AstNode child) { child = this.getCondition() }