diff --git a/ql/src/codeql_ruby/controlflow/ControlFlowGraph.qll b/ql/src/codeql_ruby/controlflow/ControlFlowGraph.qll index 080f64da579..75674fb10e5 100644 --- a/ql/src/codeql_ruby/controlflow/ControlFlowGraph.qll +++ b/ql/src/codeql_ruby/controlflow/ControlFlowGraph.qll @@ -7,14 +7,34 @@ private import internal.ControlFlowGraphImpl private import internal.Splitting private import internal.Completion -private class CfgScopeRange = @method or @block or @do_block; +private class CfgScopeRange = + @program or @begin_block or @end_block or @module or @class or @singleton_class or @method or + @singleton_method or @block or @do_block; /** An AST node with an associated control-flow graph. */ class CfgScope extends AstNode, CfgScopeRange { /** Gets the name of this scope. */ string getName() { + this instanceof Program and + result = "top-level" + or + this instanceof BeginBlock and + result = "BEGIN block" + or + this instanceof EndBlock and + result = "END block" + or + result = this.(Module).getName().toString() + or + result = this.(Class).getName().toString() + or + this instanceof SingletonClass and + result = "singleton class" + or result = this.(Method).getName().toString() or + result = this.(SingletonMethod).getName().toString() + or this instanceof Block and result = "block" or diff --git a/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll b/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll index 283f77d4908..1fd3ac8ec72 100644 --- a/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll +++ b/ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll @@ -141,7 +141,14 @@ abstract private class StandardNode extends ControlFlowTree { abstract AstNode getChildNode(int i); private AstNode getChildNodeRanked(int i) { - result = rank[i + 1](AstNode child, int j | child = this.getChildNode(j) | child order by j) + result = + rank[i + 1](AstNode child, int j | + child = this.getChildNode(j) and + // Never descend into children with a separate scope + not child instanceof CfgScope + | + child order by j + ) } /** Gets the first child node of this element. */ @@ -150,24 +157,17 @@ abstract private class StandardNode extends ControlFlowTree { /** Gets the last child node of this node. */ final AstNode getLastChildNode() { exists(int last | - last = max(int i | exists(this.getChildNodeRanked(i))) and - result = this.getChildNodeRanked(last) + result = this.getChildNodeRanked(last) and + not exists(this.getChildNodeRanked(last + 1)) ) } - /** Gets the `i`th child, which is not the last node. */ - pragma[nomagic] - private AstNode getNonLastChildNode(int i) { - result = this.getChildNodeRanked(i) and - not result = this.getLastChildNode() - } - - final override predicate propagatesAbnormal(AstNode child) { child = this.getChildNode(_) } + final override predicate propagatesAbnormal(AstNode child) { child = this.getChildNodeRanked(_) } pragma[nomagic] override predicate succ(AstNode pred, AstNode succ, Completion c) { exists(int i | - last(this.getNonLastChildNode(i), pred, c) and + last(this.getChildNodeRanked(i), pred, c) and c instanceof NormalCompletion and first(this.getChildNodeRanked(i + 1), succ) ) @@ -246,6 +246,10 @@ private module Trees { } } + private class BeginBlockTree extends StandardPreOrderTree, BeginBlock { + final override AstNode getChildNode(int i) { result = this.getChild(i) } + } + private class BinaryTree extends StandardPostOrderTree, Binary { BinaryTree() { not this instanceof LogicalAndAstNode and not this instanceof LogicalOrAstNode } @@ -272,6 +276,12 @@ private module Trees { } } + private class ClassTree extends StandardPreOrderTree, Class { + final override AstNode getChildNode(int i) { result = this.getChild(i) } + + override predicate isHidden() { any() } + } + private class DoTree extends StandardPreOrderTree, Do { final override AstNode getChildNode(int i) { result = this.getChild(i) } @@ -290,6 +300,10 @@ private module Trees { override predicate isHidden() { any() } } + private class EndBlockTree extends StandardPreOrderTree, EndBlock { + final override AstNode getChildNode(int i) { result = this.getChild(i) } + } + private class IdentifierTree extends LeafTree, Identifier { } private class IfElsifTree extends PreOrderTree, IfElsifAstNode { @@ -392,6 +406,12 @@ private module Trees { } } + private class ModuleTree extends StandardPreOrderTree, Module { + final override AstNode getChildNode(int i) { result = this.getChild(i) } + + override predicate isHidden() { any() } + } + private class NextTree extends StandardPostOrderTree, Next { final override AstNode getChildNode(int i) { result = this.getChild() and i = 0 } } @@ -408,6 +428,12 @@ private module Trees { final override AstNode getChildNode(int i) { result = this.getChild(i) } } + private class ProgramTree extends StandardPreOrderTree, Program { + final override AstNode getChildNode(int i) { result = this.getChild(i) } + + override predicate isHidden() { any() } + } + private class RedoTree extends StandardPostOrderTree, Redo { final override AstNode getChildNode(int i) { result = this.getChild() and i = 0 } } @@ -416,6 +442,18 @@ private module Trees { final override AstNode getChildNode(int i) { result = this.getChild() and i = 0 } } + private class SingletonClassTree extends StandardPreOrderTree, SingletonClass { + final override AstNode getChildNode(int i) { result = this.getChild(i) } + + override predicate isHidden() { any() } + } + + private class SingletonMethodTree extends StandardPreOrderTree, SingletonMethod { + final override AstNode getChildNode(int i) { result = this.getChild(i) } + + override predicate isHidden() { any() } + } + private class StringTree extends LeafTree, String { } private class ThenTree extends StandardPreOrderTree, Then {