diff --git a/ql/src/codeql_ruby/ast/Expr.qll b/ql/src/codeql_ruby/ast/Expr.qll index 5307b7b8db1..3440d9bd6b9 100644 --- a/ql/src/codeql_ruby/ast/Expr.qll +++ b/ql/src/codeql_ruby/ast/Expr.qll @@ -145,6 +145,14 @@ class ExprSequence extends Expr { */ class BodyStatement extends ExprSequence { override BodyStatement::Range range; + + /** Gets the `else` block in this block, if any. */ + final ExprSequence getElse() { result = range.getElse() } + + /** Gets the `ensure` block in this block, if any. */ + final ExprSequence getEnsure() { result = range.getEnsure() } + + final predicate hasEnsure() { exists(this.getEnsure()) } } /** diff --git a/ql/src/codeql_ruby/ast/Method.qll b/ql/src/codeql_ruby/ast/Method.qll index b6390e71d06..05245497fa5 100644 --- a/ql/src/codeql_ruby/ast/Method.qll +++ b/ql/src/codeql_ruby/ast/Method.qll @@ -56,14 +56,14 @@ class SingletonMethod extends Callable, BodyStatement, @singleton_method { * -> (x) { x + 1 } * ``` */ -class Lambda extends Callable, @lambda { +class Lambda extends Callable, BodyStatement, @lambda { final override Lambda::Range range; final override string getAPrimaryQlClass() { result = "Lambda" } } /** A block. */ -class Block extends Callable { +class Block extends Callable, ExprSequence { override Block::Range range; } diff --git a/ql/src/codeql_ruby/ast/internal/AST.qll b/ql/src/codeql_ruby/ast/internal/AST.qll index 1c4cf5869c7..5061329da25 100644 --- a/ql/src/codeql_ruby/ast/internal/AST.qll +++ b/ql/src/codeql_ruby/ast/internal/AST.qll @@ -33,8 +33,6 @@ module AstNode { this = any(Generated::Call c).getMethod() and not this instanceof Generated::ScopeResolution or - this instanceof Generated::Ensure - or this instanceof Generated::Rescue or this instanceof Generated::RestAssignment diff --git a/ql/src/codeql_ruby/ast/internal/Expr.qll b/ql/src/codeql_ruby/ast/internal/Expr.qll index f620e0f947b..575af203d61 100644 --- a/ql/src/codeql_ruby/ast/internal/Expr.qll +++ b/ql/src/codeql_ruby/ast/internal/Expr.qll @@ -185,7 +185,25 @@ module ExprSequence { } module BodyStatement { - abstract class Range extends ExprSequence::Range { } + abstract class Range extends ExprSequence::Range { + final override Expr getExpr(int n) { + result = + rank[n + 1](Generated::AstNode node, int i | + node = getChild(i) and + not node instanceof Generated::Else and + not node instanceof Generated::Rescue and + not node instanceof Generated::Ensure + | + node order by i + ) + } + + final ExprSequence getElse() { result = unique(Generated::Else s | s = getChild(_)) } + + final ExprSequence getEnsure() { result = unique(Generated::Ensure s | s = getChild(_)) } + + abstract Generated::AstNode getChild(int i); + } } module ParenthesizedExpr { @@ -228,6 +246,16 @@ module DoExpr { } } +module Ensure { + class Range extends ExprSequence::Range, @ensure { + final override Generated::Ensure generated; + + final override Expr getExpr(int n) { result = generated.getChild(n) } + + final override string toString() { result = "ensure ... end" } + } +} + module Pair { class Range extends Expr::Range, @pair { final override Generated::Pair generated; diff --git a/ql/src/codeql_ruby/ast/internal/Method.qll b/ql/src/codeql_ruby/ast/internal/Method.qll index 834a959abbf..331cf90f987 100644 --- a/ql/src/codeql_ruby/ast/internal/Method.qll +++ b/ql/src/codeql_ruby/ast/internal/Method.qll @@ -23,7 +23,7 @@ module Method { final predicate isSetter() { generated.getName() instanceof Generated::Setter } - final override Expr getExpr(int i) { result = generated.getChild(i) } + final override Generated::AstNode getChild(int i) { result = generated.getChild(i) } final override string toString() { result = this.getName() } } @@ -41,33 +41,40 @@ module SingletonMethod { result = generated.getName().(Generated::Setter).getName().getValue() + "=" } - final override Expr getExpr(int i) { result = generated.getChild(i) } + final override Generated::AstNode getChild(int i) { result = generated.getChild(i) } final override string toString() { result = this.getName() } } } module Lambda { - class Range extends Callable::Range, @lambda { + class Range extends Callable::Range, BodyStatement::Range, @lambda { final override Generated::Lambda generated; final override Parameter::Range getParameter(int n) { result = generated.getParameters().getChild(n) } + final override Generated::AstNode getChild(int i) { + result = generated.getBody().(Generated::DoBlock).getChild(i) or + result = generated.getBody().(Generated::Block).getChild(i) + } + final override string toString() { result = "-> { ... }" } } } module Block { - abstract class Range extends Callable::Range { } + abstract class Range extends Callable::Range, ExprSequence::Range { + Range() { not generated.getParent() instanceof Generated::Lambda } + } } module DoBlock { class Range extends Block::Range, BodyStatement::Range, @do_block { final override Generated::DoBlock generated; - final override Expr getExpr(int i) { result = generated.getChild(i) } + final override Generated::AstNode getChild(int i) { result = generated.getChild(i) } final override Parameter::Range getParameter(int n) { result = generated.getParameters().getChild(n) @@ -85,6 +92,8 @@ module BraceBlock { result = generated.getParameters().getChild(n) } + final override Expr getExpr(int i) { result = generated.getChild(i) } + final override string toString() { result = "{ ... }" } } } diff --git a/ql/src/codeql_ruby/ast/internal/Module.qll b/ql/src/codeql_ruby/ast/internal/Module.qll index 9b1a67be751..b0b2ae67022 100644 --- a/ql/src/codeql_ruby/ast/internal/Module.qll +++ b/ql/src/codeql_ruby/ast/internal/Module.qll @@ -11,7 +11,7 @@ module Class { class Range extends ModuleBase::Range, ConstantWriteAccess::Range, @class { final override Generated::Class generated; - final override Expr getExpr(int i) { result = generated.getChild(i) } + final override Generated::AstNode getChild(int i) { result = generated.getChild(i) } final override string getName() { result = generated.getName().(Generated::Token).getValue() or @@ -40,7 +40,7 @@ module SingletonClass { class Range extends ModuleBase::Range, @singleton_class { final override Generated::SingletonClass generated; - final override Expr getExpr(int i) { result = generated.getChild(i) } + final override Generated::AstNode getChild(int i) { result = generated.getChild(i) } final Expr getValue() { result = generated.getValue() } @@ -52,7 +52,7 @@ module Module { class Range extends ModuleBase::Range, ConstantWriteAccess::Range, @module { final override Generated::Module generated; - final override Expr getExpr(int n) { result = generated.getChild(n) } + final override Generated::AstNode getChild(int i) { result = generated.getChild(i) } final override string getName() { result = generated.getName().(Generated::Token).getValue() or diff --git a/ql/src/codeql_ruby/dataflow/internal/DataFlowPrivate.qll b/ql/src/codeql_ruby/dataflow/internal/DataFlowPrivate.qll index 4ac583160ff..38669d32736 100644 --- a/ql/src/codeql_ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ql/src/codeql_ruby/dataflow/internal/DataFlowPrivate.qll @@ -132,15 +132,15 @@ private module Cached { or nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::CaseExprCfgNode).getBranch(_) or - exists(CfgNodes::ExprCfgNode exprTo, ExprReturnNode n | + exists(CfgNodes::ExprCfgNode exprTo, ReturningStatementNode n | nodeFrom = n and exprTo = nodeTo.asExpr() and - n.getKind() instanceof BreakReturnKind and + n.getReturningNode().getNode() instanceof BreakStmt and exprTo.getNode() instanceof Loop and - nodeTo.asExpr().getAPredecessor(any(SuccessorTypes::BreakSuccessor s)) = n.getExprNode() + nodeTo.asExpr().getAPredecessor(any(SuccessorTypes::BreakSuccessor s)) = n.getReturningNode() ) or - nodeFrom.asExpr() = nodeTo.(ExprReturnNode).getExprNode().getReturnedValueNode() + nodeFrom.asExpr() = nodeTo.(ReturningStatementNode).getReturningNode().getReturnedValueNode() or nodeTo.asExpr() = any(CfgNodes::ExprNodes::ForExprCfgNode for | @@ -182,6 +182,28 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode { override string toStringImpl() { result = def.toString() } } +/** + * A value returning statement, viewed as a node in a data flow graph. + * + * Note that because of control-flow splitting, one `ReturningStmt` may correspond + * to multiple `ReturningStatementNode`s, just like it may correspond to multiple + * `ControlFlow::Node`s. + */ +class ReturningStatementNode extends NodeImpl, TReturningNode { + private CfgNodes::ReturningCfgNode n; + + ReturningStatementNode() { this = TReturningNode(n) } + + /** Gets the expression corresponding to this node. */ + CfgNodes::ReturningCfgNode getReturningNode() { result = n } + + override CfgScope getCfgScope() { result = n.getScope() } + + override Location getLocationImpl() { result = n.getLocation() } + + override string toStringImpl() { result = n.toString() } +} + private module ParameterNodes { abstract private class ParameterNodeImpl extends ParameterNode, NodeImpl { } @@ -241,29 +263,49 @@ abstract class ReturnNode extends Node { } private module ReturnNodes { + private predicate isValid(CfgNodes::ReturningCfgNode node) { + exists(ReturningStmt stmt, Callable scope | + stmt = node.getNode() and + scope = node.getScope() + | + stmt instanceof ReturnStmt and + (scope instanceof Method or scope instanceof SingletonMethod or scope instanceof Lambda) + or + stmt instanceof NextStmt and + (scope instanceof Block or scope instanceof Lambda) + or + stmt instanceof BreakStmt and + (scope instanceof Block or scope instanceof Lambda) + ) + } + /** * A data-flow node that represents an expression returned by a callable, * either using an explict `return` statement or as the expression of a method body. */ - class ExprReturnNode extends ReturnNode, NodeImpl, TReturningNode { + class ExplicitReturnNode extends ReturnNode, ReturningStatementNode { private CfgNodes::ReturningCfgNode n; - ExprReturnNode() { this = TReturningNode(n) } - - /** Gets the statement corresponding to this node. */ - CfgNodes::ReturningCfgNode getExprNode() { result = n } + ExplicitReturnNode() { + isValid(this.getReturningNode()) and + n.getASuccessor().(CfgNodes::AnnotatedExitNode).isNormal() and + n.getScope() instanceof Callable + } override ReturnKind getKind() { if n.getNode() instanceof BreakStmt then result instanceof BreakReturnKind else result instanceof NormalReturnKind } + } - override CfgScope getCfgScope() { result = n.getScope() } + class ExprReturnNode extends ReturnNode, ExprNode { + ExprReturnNode() { + this.getExprNode().getASuccessor().(CfgNodes::AnnotatedExitNode).isNormal() and + this.getEnclosingCallable() instanceof Callable + } - override Location getLocationImpl() { result = n.getLocation() } - - override string toStringImpl() { result = n.toString() } + override ReturnKind getKind() { result instanceof NormalReturnKind } } } diff --git a/ql/test/library-tests/controlflow/graph/Cfg.expected b/ql/test/library-tests/controlflow/graph/Cfg.expected index 306c8cadf94..ee31803fec4 100644 --- a/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -163,7 +163,7 @@ raise.rb: #-----| -> b # 150| enter m13 -#-----| -> Ensure +#-----| -> ensure ... end # 154| enter m14 #-----| -> element @@ -182,7 +182,7 @@ break_ensure.rb: #-----| -> elements # 2| for ... in ... -#-----| -> Ensure +#-----| -> ensure ... end # 2| element #-----| -> element @@ -210,7 +210,7 @@ break_ensure.rb: # 4| break #-----| break -> for ... in ... -# 7| Ensure +# 7| ensure ... end #-----| -> elements # 8| if ... @@ -258,7 +258,7 @@ break_ensure.rb: #-----| -> In # 16| if ... -#-----| -> Ensure +#-----| -> ensure ... end # 16| ... > ... #-----| false -> if ... @@ -271,12 +271,12 @@ break_ensure.rb: #-----| -> ... > ... # 17| break -#-----| break -> [ensure: break] Ensure +#-----| break -> [ensure: break] ensure ... end -# 19| Ensure +# 19| ensure ... end #-----| -> elements -# 19| [ensure: break] Ensure +# 19| [ensure: break] ensure ... end #-----| -> [ensure: break] elements # 20| if ... @@ -333,7 +333,7 @@ break_ensure.rb: #-----| -> elements # 29| if ... -#-----| -> Ensure +#-----| -> ensure ... end # 29| call to nil? #-----| false -> if ... @@ -346,12 +346,12 @@ break_ensure.rb: #-----| -> call to nil? # 30| return -#-----| return -> [ensure: return] Ensure +#-----| return -> [ensure: return] ensure ... end -# 32| Ensure +# 32| ensure ... end #-----| -> elements -# 32| [ensure: return] Ensure +# 32| [ensure: return] ensure ... end #-----| -> [ensure: return] elements # 33| for ... in ... @@ -444,7 +444,7 @@ break_ensure.rb: #-----| -> In # 47| if ... -#-----| -> Ensure +#-----| -> ensure ... end # 47| ... > ... #-----| false -> if ... @@ -457,7 +457,7 @@ break_ensure.rb: #-----| -> ... > ... # 48| call to raise -#-----| raise -> [ensure: raise] Ensure +#-----| raise -> [ensure: raise] ensure ... end # 48| raise #-----| -> @@ -465,10 +465,10 @@ break_ensure.rb: # 48| #-----| -> call to raise -# 50| Ensure +# 50| ensure ... end #-----| -> element -# 50| [ensure: raise] Ensure +# 50| [ensure: raise] ensure ... end #-----| -> [ensure: raise] element # 51| if ... @@ -1110,7 +1110,7 @@ cfg.rb: #-----| -> puts # 83| call to puts -#-----| -> Ensure +#-----| -> ensure ... end # 83| puts #-----| -> ok @@ -1118,7 +1118,7 @@ cfg.rb: # 83| ok #-----| -> call to puts -# 84| Ensure +# 84| ensure ... end #-----| -> puts # 85| call to puts @@ -3049,7 +3049,7 @@ raise.rb: #-----| -> ... > ... # 70| call to raise -#-----| raise -> [ensure: raise] Ensure +#-----| raise -> [ensure: raise] ensure ... end # 70| raise #-----| -> x > 2 @@ -3071,13 +3071,13 @@ raise.rb: #-----| -> ... < ... # 72| return -#-----| return -> [ensure: return] Ensure +#-----| return -> [ensure: return] ensure ... end # 72| x < 0 #-----| -> return # 74| call to puts -#-----| -> Ensure +#-----| -> ensure ... end # 74| puts #-----| -> 0 <= x <= 2 @@ -3085,13 +3085,13 @@ raise.rb: # 74| 0 <= x <= 2 #-----| -> call to puts -# 75| Ensure +# 75| ensure ... end #-----| -> puts -# 75| [ensure: return] Ensure +# 75| [ensure: return] ensure ... end #-----| -> [ensure: return] puts -# 75| [ensure: raise] Ensure +# 75| [ensure: raise] ensure ... end #-----| -> [ensure: raise] puts # 76| call to puts @@ -3153,7 +3153,7 @@ raise.rb: #-----| -> ... > ... # 83| call to raise -#-----| raise -> [ensure: raise] Ensure +#-----| raise -> [ensure: raise] ensure ... end # 83| raise #-----| -> x > 2 @@ -3175,13 +3175,13 @@ raise.rb: #-----| -> ... < ... # 85| return -#-----| return -> [ensure: return] Ensure +#-----| return -> [ensure: return] ensure ... end # 85| x < 0 #-----| -> return # 87| call to puts -#-----| -> Ensure +#-----| -> ensure ... end # 87| puts #-----| -> 0 <= x <= 2 @@ -3189,13 +3189,13 @@ raise.rb: # 87| 0 <= x <= 2 #-----| -> call to puts -# 88| Ensure +# 88| ensure ... end #-----| -> puts -# 88| [ensure: return] Ensure +# 88| [ensure: return] ensure ... end #-----| -> [ensure: return] puts -# 88| [ensure: raise] Ensure +# 88| [ensure: raise] ensure ... end #-----| -> [ensure: raise] puts # 89| call to puts @@ -3272,7 +3272,7 @@ raise.rb: #-----| -> ... > ... # 98| call to raise -#-----| raise -> [ensure: raise] Ensure +#-----| raise -> [ensure: raise] ensure ... end # 98| raise #-----| -> x > 2 @@ -3294,13 +3294,13 @@ raise.rb: #-----| -> ... < ... # 100| return -#-----| return -> [ensure: return] Ensure +#-----| return -> [ensure: return] ensure ... end # 100| x < 0 #-----| -> return # 102| call to puts -#-----| -> Ensure +#-----| -> ensure ... end # 102| puts #-----| -> 0 <= x <= 2 @@ -3308,13 +3308,13 @@ raise.rb: # 102| 0 <= x <= 2 #-----| -> call to puts -# 103| Ensure +# 103| ensure ... end #-----| -> puts -# 103| [ensure: return] Ensure +# 103| [ensure: return] ensure ... end #-----| -> [ensure: return] puts -# 103| [ensure: raise] Ensure +# 103| [ensure: raise] ensure ... end #-----| -> [ensure: raise] puts # 104| call to puts @@ -3345,13 +3345,13 @@ raise.rb: #-----| -> [ensure: raise] call to puts # 106| if ... -#-----| -> Ensure +#-----| -> ensure ... end # 106| [ensure: return] if ... -#-----| -> [ensure: return] Ensure +#-----| -> [ensure: return] ensure ... end # 106| [ensure: raise] if ... -#-----| -> [ensure: raise] Ensure +#-----| -> [ensure: raise] ensure ... end # 106| b1 #-----| false -> if ... @@ -3366,13 +3366,13 @@ raise.rb: #-----| true -> [ensure: raise] raise # 107| call to raise -#-----| raise -> [ensure(1): raise] Ensure +#-----| raise -> [ensure(1): raise] ensure ... end # 107| [ensure: return] call to raise -#-----| raise -> [ensure: return, ensure(1): raise] Ensure +#-----| raise -> [ensure: return, ensure(1): raise] ensure ... end # 107| [ensure: raise] call to raise -#-----| raise -> [ensure: raise, ensure(1): raise] Ensure +#-----| raise -> [ensure: raise, ensure(1): raise] ensure ... end # 107| raise #-----| -> b1 is true @@ -3392,41 +3392,41 @@ raise.rb: # 107| [ensure: raise] b1 is true #-----| -> [ensure: raise] call to raise -# 109| Ensure +# 109| ensure ... end #-----| -> puts -# 109| [ensure(1): raise] Ensure +# 109| [ensure(1): raise] ensure ... end #-----| -> [ensure(1): raise] puts -# 109| [ensure: return] Ensure +# 109| [ensure: return] ensure ... end #-----| -> [ensure: return] puts -# 109| [ensure: return, ensure(1): raise] Ensure +# 109| [ensure: return, ensure(1): raise] ensure ... end #-----| -> [ensure: return, ensure(1): raise] puts -# 109| [ensure: raise] Ensure +# 109| [ensure: raise] ensure ... end #-----| -> [ensure: raise] puts -# 109| [ensure: raise, ensure(1): raise] Ensure +# 109| [ensure: raise, ensure(1): raise] ensure ... end #-----| -> [ensure: raise, ensure(1): raise] puts # 110| call to puts #-----| -> puts # 110| [ensure(1): raise] call to puts -#-----| raise -> [ensure: raise] Ensure +#-----| raise -> [ensure: raise] ensure ... end # 110| [ensure: return] call to puts -#-----| return -> [ensure: return] Ensure +#-----| return -> [ensure: return] ensure ... end # 110| [ensure: return, ensure(1): raise] call to puts -#-----| raise -> [ensure: raise] Ensure +#-----| raise -> [ensure: raise] ensure ... end # 110| [ensure: raise] call to puts -#-----| raise -> [ensure: raise] Ensure +#-----| raise -> [ensure: raise] ensure ... end # 110| [ensure: raise, ensure(1): raise] call to puts -#-----| raise -> [ensure: raise] Ensure +#-----| raise -> [ensure: raise] ensure ... end # 110| puts #-----| -> inner ensure @@ -3465,7 +3465,7 @@ raise.rb: #-----| -> [ensure: raise, ensure(1): raise] call to puts # 113| call to puts -#-----| -> Ensure +#-----| -> ensure ... end # 113| puts #-----| -> End m9 @@ -3473,13 +3473,13 @@ raise.rb: # 113| End m9 #-----| -> call to puts -# 114| Ensure +# 114| ensure ... end #-----| -> puts -# 114| [ensure: return] Ensure +# 114| [ensure: return] ensure ... end #-----| -> [ensure: return] puts -# 114| [ensure: raise] Ensure +# 114| [ensure: raise] ensure ... end #-----| -> [ensure: raise] puts # 115| call to puts @@ -3565,7 +3565,7 @@ raise.rb: # 121| p #-----| no-match -> raise -#-----| match -> Ensure +#-----| match -> ensure ... end # 121| call to raise #-----| raise -> exit m10 (abnormal) @@ -3576,7 +3576,7 @@ raise.rb: # 121| Exception #-----| -> call to raise -# 124| Ensure +# 124| ensure ... end #-----| -> puts # 125| call to puts @@ -3598,7 +3598,7 @@ raise.rb: #-----| -> b # 130| if ... -#-----| -> Ensure +#-----| -> ensure ... end # 130| b #-----| false -> if ... @@ -3618,17 +3618,17 @@ raise.rb: # 133| ExceptionA #-----| no-match -> Rescue -#-----| match -> Ensure +#-----| match -> ensure ... end # 134| Rescue #-----| -> ExceptionB # 134| ExceptionB #-----| match -> puts -#-----| raise -> [ensure: raise] Ensure +#-----| raise -> [ensure: raise] ensure ... end # 135| call to puts -#-----| -> Ensure +#-----| -> ensure ... end # 135| puts #-----| -> ExceptionB @@ -3636,10 +3636,10 @@ raise.rb: # 135| ExceptionB #-----| -> call to puts -# 136| Ensure +# 136| ensure ... end #-----| -> puts -# 136| [ensure: raise] Ensure +# 136| [ensure: raise] ensure ... end #-----| -> [ensure: raise] puts # 137| call to puts @@ -3679,14 +3679,14 @@ raise.rb: #-----| -> b # 143| if ... -#-----| -> Ensure +#-----| -> ensure ... end # 143| b #-----| false -> if ... #-----| true -> raise # 144| call to raise -#-----| raise -> [ensure: raise] Ensure +#-----| raise -> [ensure: raise] ensure ... end # 144| raise #-----| -> @@ -3694,10 +3694,10 @@ raise.rb: # 144| #-----| -> call to raise -# 146| Ensure +# 146| ensure ... end #-----| -> 3 -# 146| [ensure: raise] Ensure +# 146| [ensure: raise] ensure ... end #-----| -> [ensure: raise] 3 # 147| return @@ -3718,7 +3718,7 @@ raise.rb: # 150| m13 #-----| -> m13 -# 151| Ensure +# 151| ensure ... end #-----| -> exit m13 (normal) # 154| m14 diff --git a/ql/test/library-tests/dataflow/local/DataflowStep.expected b/ql/test/library-tests/dataflow/local/DataflowStep.expected index d877f7a867b..3c8f5cfd3a1 100644 --- a/ql/test/library-tests/dataflow/local/DataflowStep.expected +++ b/ql/test/library-tests/dataflow/local/DataflowStep.expected @@ -31,3 +31,18 @@ | local_dataflow.rb:20:17:20:21 | break | local_dataflow.rb:19:1:21:3 | for ... in ... | | local_dataflow.rb:24:2:24:8 | break | local_dataflow.rb:23:1:25:3 | while ... | | local_dataflow.rb:24:8:24:8 | 5 | local_dataflow.rb:24:2:24:8 | break | +| local_dataflow.rb:28:5:28:26 | M | local_dataflow.rb:28:1:28:26 | ... = ... | +| local_dataflow.rb:28:15:28:22 | module | local_dataflow.rb:28:5:28:26 | M | +| local_dataflow.rb:30:5:30:24 | C | local_dataflow.rb:30:1:30:24 | ... = ... | +| local_dataflow.rb:30:14:30:20 | class | local_dataflow.rb:30:5:30:24 | C | +| local_dataflow.rb:32:5:32:25 | bar | local_dataflow.rb:32:1:32:25 | ... = ... | +| local_dataflow.rb:32:5:32:25 | bar | local_dataflow.rb:32:1:32:25 | ... = ... | +| local_dataflow.rb:34:7:34:7 | x | local_dataflow.rb:35:6:35:6 | x | +| local_dataflow.rb:36:13:36:13 | 7 | local_dataflow.rb:36:6:36:13 | return | +| local_dataflow.rb:41:7:41:7 | x | local_dataflow.rb:42:6:42:6 | x | +| local_dataflow.rb:43:13:43:13 | 7 | local_dataflow.rb:43:6:43:13 | return | +| local_dataflow.rb:45:10:45:10 | 6 | local_dataflow.rb:45:3:45:10 | return | +| local_dataflow.rb:49:3:53:3 | | local_dataflow.rb:50:18:50:18 | x | +| local_dataflow.rb:50:8:50:13 | next | local_dataflow.rb:50:3:50:13 | next | +| local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:51:20:51:20 | x | +| local_dataflow.rb:51:9:51:15 | break | local_dataflow.rb:51:3:51:15 | break | diff --git a/ql/test/library-tests/dataflow/local/ReturnNodes.expected b/ql/test/library-tests/dataflow/local/ReturnNodes.expected new file mode 100644 index 00000000000..a4971c21ade --- /dev/null +++ b/ql/test/library-tests/dataflow/local/ReturnNodes.expected @@ -0,0 +1,9 @@ +| local_dataflow.rb:6:3:6:14 | ... = ... | +| local_dataflow.rb:32:14:32:21 | method | +| local_dataflow.rb:36:6:36:13 | return | +| local_dataflow.rb:38:3:38:13 | reachable | +| local_dataflow.rb:43:6:43:13 | return | +| local_dataflow.rb:45:3:45:10 | return | +| local_dataflow.rb:50:3:50:13 | next | +| local_dataflow.rb:51:3:51:15 | break | +| local_dataflow.rb:52:3:52:10 | normal | diff --git a/ql/test/library-tests/dataflow/local/ReturnNodes.ql b/ql/test/library-tests/dataflow/local/ReturnNodes.ql new file mode 100644 index 00000000000..8b04dcd3dc5 --- /dev/null +++ b/ql/test/library-tests/dataflow/local/ReturnNodes.ql @@ -0,0 +1,4 @@ +import ruby +import codeql_ruby.dataflow.internal.DataFlowPrivate + +select any(ReturnNode node) diff --git a/ql/test/library-tests/dataflow/local/local_dataflow.rb b/ql/test/library-tests/dataflow/local/local_dataflow.rb index b212fa9ce16..27fc5f4d841 100644 --- a/ql/test/library-tests/dataflow/local/local_dataflow.rb +++ b/ql/test/library-tests/dataflow/local/local_dataflow.rb @@ -23,3 +23,31 @@ end while true break 5 end + +# string flows to x +x = module M; "module" end +# string flows to x +x = class C; "class" end +# string does not flow to x because "def" evaluates to a method symbol +x = def bar; "method" end + +def m x + if x == 4 + return 7 + end + "reachable" +end + +def m x + if x == 4 + return 7 + end + return 6 + "unreachable" +end + +m do + next "next" if x < 4 + break "break" if x < 9 + "normal" +end