diff --git a/ruby/ql/lib/change-notes/2022-05-23-flow-through-instance-variables.md b/ruby/ql/lib/change-notes/2022-05-23-flow-through-instance-variables.md new file mode 100644 index 00000000000..bbb0b4011de --- /dev/null +++ b/ruby/ql/lib/change-notes/2022-05-23-flow-through-instance-variables.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +Support for data flow through instance variables has been added. diff --git a/ruby/ql/lib/codeql/ruby/ast/Variable.qll b/ruby/ql/lib/codeql/ruby/ast/Variable.qll index 36bc0cbe36c..9952b70b2d1 100644 --- a/ruby/ql/lib/codeql/ruby/ast/Variable.qll +++ b/ruby/ql/lib/codeql/ruby/ast/Variable.qll @@ -181,6 +181,17 @@ class GlobalVariableReadAccess extends GlobalVariableAccess, VariableReadAccess /** An access to an instance variable. */ class InstanceVariableAccess extends VariableAccess instanceof InstanceVariableAccessImpl { final override string getAPrimaryQlClass() { result = "InstanceVariableAccess" } + + /** + * Gets the synthetic receiver (`self`) of this instance variable access. + */ + final SelfVariableAccess getReceiver() { synthChild(this, 0, result) } + + final override AstNode getAChild(string pred) { + result = VariableAccess.super.getAChild(pred) + or + pred = "getReceiver" and result = this.getReceiver() + } } /** An access to an instance variable where the value is updated. */ diff --git a/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll b/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll index 0b1137faeb7..3357b54906a 100644 --- a/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll +++ b/ruby/ql/lib/codeql/ruby/ast/internal/Synthesis.qll @@ -210,6 +210,38 @@ private module ImplicitSelfSynthesis { regularMethodCallSelfSynthesis(parent, i, child) } } + + pragma[nomagic] + private AstNode instanceVarAccessSynthParentStar(InstanceVariableAccess var) { + result = var + or + instanceVarAccessSynthParentStar(var) = getSynthChild(result, _) + } + + /** + * Gets the `SelfKind` for instance variable access `var`. This is based on the + * "owner" of `var`; for real nodes this is the node itself, for synthetic nodes + * this is the closest parent that is a real node. + */ + pragma[nomagic] + private SelfKind getSelfKind(InstanceVariableAccess var) { + exists(Ruby::AstNode owner | + owner = toGenerated(instanceVarAccessSynthParentStar(var)) and + result = SelfKind(TSelfVariable(scopeOf(owner).getEnclosingSelfScope())) + ) + } + + pragma[nomagic] + private predicate instanceVariableSelfSynthesis(InstanceVariableAccess var, int i, Child child) { + child = SynthChild(getSelfKind(var)) and + i = 0 + } + + private class InstanceVariableSelfSynthesis extends Synthesis { + final override predicate child(AstNode parent, int i, Child child) { + instanceVariableSelfSynthesis(parent, i, child) + } + } } private module SetterDesugar { diff --git a/ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll b/ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll index 850410b0848..efb69af39eb 100644 --- a/ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll +++ b/ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll @@ -682,6 +682,24 @@ module ExprNodes { final override VariableReadAccess getExpr() { result = ExprCfgNode.super.getExpr() } } + private class InstanceVariableAccessMapping extends ExprChildMapping, InstanceVariableAccess { + override predicate relevantChild(AstNode n) { n = this.getReceiver() } + } + + /** A control-flow node that wraps an `InstanceVariableAccess` AST expression. */ + class InstanceVariableAccessCfgNode extends ExprCfgNode { + override string getAPrimaryQlClass() { result = "InstanceVariableAccessCfgNode" } + + override InstanceVariableAccessMapping e; + + override InstanceVariableAccess getExpr() { result = ExprCfgNode.super.getExpr() } + + /** + * Gets the synthetic receiver (`self`) of this instance variable access. + */ + final CfgNode getReceiver() { e.hasCfgChild(e.getReceiver(), this, result) } + } + /** A control-flow node that wraps a `VariableWriteAccess` AST expression. */ class VariableWriteAccessCfgNode extends ExprCfgNode { override string getAPrimaryQlClass() { result = "VariableWriteAccessCfgNode" } @@ -709,13 +727,26 @@ module ExprNodes { final override ConstantWriteAccess getExpr() { result = ExprCfgNode.super.getExpr() } } - /** A control-flow node that wraps a `InstanceVariableWriteAccess` AST expression. */ - class InstanceVariableWriteAccessCfgNode extends ExprCfgNode { + /** A control-flow node that wraps an `InstanceVariableReadAccess` AST expression. */ + class InstanceVariableReadAccessCfgNode extends InstanceVariableAccessCfgNode { + InstanceVariableReadAccessCfgNode() { this.getNode() instanceof InstanceVariableReadAccess } + + override string getAPrimaryQlClass() { result = "InstanceVariableReadAccessCfgNode" } + + final override InstanceVariableReadAccess getExpr() { + result = InstanceVariableAccessCfgNode.super.getExpr() + } + } + + /** A control-flow node that wraps an `InstanceVariableWriteAccess` AST expression. */ + class InstanceVariableWriteAccessCfgNode extends InstanceVariableAccessCfgNode { + InstanceVariableWriteAccessCfgNode() { this.getNode() instanceof InstanceVariableWriteAccess } + override string getAPrimaryQlClass() { result = "InstanceVariableWriteAccessCfgNode" } - override InstanceVariableWriteAccess e; - - final override InstanceVariableWriteAccess getExpr() { result = ExprCfgNode.super.getExpr() } + final override InstanceVariableWriteAccess getExpr() { + result = InstanceVariableAccessCfgNode.super.getExpr() + } } /** A control-flow node that wraps a `StringInterpolationComponent` AST expression. */ diff --git a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll index e07cb1b419f..e6333d86568 100644 --- a/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll +++ b/ruby/ql/lib/codeql/ruby/controlflow/internal/ControlFlowGraphImpl.qll @@ -1006,7 +1006,9 @@ module Trees { final override ControlFlowTree getChildElement(int i) { result = this.getComponent(i) } } - private class InstanceVariableTree extends LeafTree, InstanceVariableAccess { } + private class InstanceVariableTree extends StandardPostOrderTree, InstanceVariableAccess { + final override ControlFlowTree getChildElement(int i) { result = this.getReceiver() and i = 0 } + } private class KeywordParameterTree extends DefaultValueParameterTree, KeywordParameter { final override Expr getDefaultValueExpr() { result = this.getDefaultValue() } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index 032a89177be..cd18005a417 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -219,7 +219,10 @@ private module Cached { } or TSelfParameterNode(MethodBase m) or TBlockParameterNode(MethodBase m) or - TExprPostUpdateNode(CfgNodes::ExprCfgNode n) { n instanceof Argument } or + TExprPostUpdateNode(CfgNodes::ExprCfgNode n) { + n instanceof Argument or + n = any(CfgNodes::ExprNodes::InstanceVariableAccessCfgNode v).getReceiver() + } or TSummaryNode( FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state @@ -339,6 +342,7 @@ private module Cached { not cv.isInt(_) or cv.getInt() in [0 .. 10] } or + TFieldContent(string name) { name = any(InstanceVariable v).getName() } or TUnknownElementContent() /** @@ -795,11 +799,40 @@ predicate jumpStep(Node pred, Node succ) { succ.asExpr().getExpr().(ConstantReadAccess).getValue() = pred.asExpr().getExpr() } +/** + * Holds if data can flow from `node1` to `node2` via an assignment to + * content `c`. + */ predicate storeStep(Node node1, ContentSet c, Node node2) { + // Instance variable assignment, `@var = src` + node2.(PostUpdateNode).getPreUpdateNode().asExpr() = + any(CfgNodes::ExprNodes::InstanceVariableWriteAccessCfgNode var | + exists(CfgNodes::ExprNodes::AssignExprCfgNode assign | + var = assign.getLhs() and + node1.asExpr() = assign.getRhs() + | + c.isSingleton(any(Content::FieldContent ct | + ct.getName() = var.getExpr().getVariable().getName() + )) + ) + ).getReceiver() + or FlowSummaryImpl::Private::Steps::summaryStoreStep(node1, c, node2) } +/** + * Holds if there is a read step of content `c` from `node1` to `node2`. + */ predicate readStep(Node node1, ContentSet c, Node node2) { + // Instance variable read access, `@var` + node2.asExpr() = + any(CfgNodes::ExprNodes::InstanceVariableReadAccessCfgNode var | + node1.asExpr() = var.getReceiver() and + c.isSingleton(any(Content::FieldContent ct | + ct.getName() = var.getExpr().getVariable().getName() + )) + ) + or FlowSummaryImpl::Private::Steps::summaryReadStep(node1, c, node2) } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll index 6867243bbf0..c147ca9e81f 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll @@ -223,6 +223,18 @@ module Content { override string toString() { result = "element" } } + /** A field of an object, for example an instance variable. */ + class FieldContent extends Content, TFieldContent { + private string name; + + FieldContent() { this = TFieldContent(name) } + + /** Gets the name of the field. */ + string getName() { result = name } + + override string toString() { result = name } + } + /** Gets the element content corresponding to constant value `cv`. */ ElementContent getElementContent(ConstantValue cv) { result = TKnownElementContent(cv) diff --git a/ruby/ql/test/library-tests/ast/Ast.expected b/ruby/ql/test/library-tests/ast/Ast.expected index 6f0242dd1c3..ebfd53fd551 100644 --- a/ruby/ql/test/library-tests/ast/Ast.expected +++ b/ruby/ql/test/library-tests/ast/Ast.expected @@ -1234,6 +1234,7 @@ control/cases.rb: # 150| getBranch: [InClause] in ... then ... # 150| getPattern: [ReferencePattern] ^... # 150| getExpr: [InstanceVariableAccess] @foo +# 150| getReceiver: [SelfVariableAccess] self # 151| getBranch: [InClause] in ... then ... # 151| getPattern: [ReferencePattern] ^... # 151| getExpr: [ClassVariableAccess] @@foo @@ -1246,6 +1247,7 @@ control/cases.rb: # 156| getBranch: [InClause] in ... then ... # 156| getPattern: [ReferencePattern] ^... # 156| getExpr: [InstanceVariableAccess] @foo +# 156| getReceiver: [SelfVariableAccess] self # 157| getBranch: [InClause] in ... then ... # 157| getPattern: [ReferencePattern] ^... # 157| getExpr: [AddExpr] ... + ... @@ -2771,9 +2773,11 @@ operations/operations.rb: # 87| getStmt: [ClassDeclaration] X # 88| getStmt: [AssignExpr] ... = ... # 88| getAnOperand/getLeftOperand: [InstanceVariableAccess] @x +# 88| getReceiver: [SelfVariableAccess] self # 88| getAnOperand/getRightOperand: [IntegerLiteral] 1 # 89| getStmt: [AssignAddExpr] ... += ... # 89| getAnOperand/getLeftOperand: [InstanceVariableAccess] @x +# 89| getReceiver: [SelfVariableAccess] self # 89| getAnOperand/getRightOperand: [IntegerLiteral] 2 # 91| getStmt: [AssignExpr] ... = ... # 91| getAnOperand/getLeftOperand: [ClassVariableAccess] @@y diff --git a/ruby/ql/test/library-tests/ast/AstDesugar.expected b/ruby/ql/test/library-tests/ast/AstDesugar.expected index 7a5d5e0c85c..0e6a0694105 100644 --- a/ruby/ql/test/library-tests/ast/AstDesugar.expected +++ b/ruby/ql/test/library-tests/ast/AstDesugar.expected @@ -836,8 +836,10 @@ operations/operations.rb: # 89| [AssignAddExpr] ... += ... # 89| getDesugared: [AssignExpr] ... = ... # 89| getAnOperand/getLeftOperand: [InstanceVariableAccess] @x +# 89| getReceiver: [SelfVariableAccess] self # 89| getAnOperand/getRightOperand: [AddExpr] ... + ... # 89| getAnOperand/getLeftOperand/getReceiver: [InstanceVariableAccess] @x +# 89| getReceiver: [SelfVariableAccess] self # 89| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 2 # 92| [AssignDivExpr] ... /= ... # 92| getDesugared: [AssignExpr] ... = ... diff --git a/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected b/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected index d190d853634..d6ed8aec706 100644 --- a/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/ruby/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -1423,9 +1423,12 @@ cfg.html.erb: # 5| @title #-----| -> self -# 5| enter cfg.html.erb +# 5| self #-----| -> @title +# 5| enter cfg.html.erb +#-----| -> self + # 5| exit cfg.html.erb # 5| exit cfg.html.erb (normal) @@ -2690,11 +2693,14 @@ cfg.rb: #-----| -> ... > ... # 115| C -#-----| -> @field +#-----| -> self # 116| @field #-----| -> 42 +# 116| self +#-----| -> @field + # 116| ... = ... #-----| -> @@static_field @@ -4194,23 +4200,32 @@ desugar.rb: #-----| -> call to [] # 29| X -#-----| -> @x +#-----| -> self # 30| @x #-----| -> 1 -# 30| ... = ... +# 30| self #-----| -> @x +# 30| ... = ... +#-----| -> self + # 30| 1 #-----| -> ... = ... # 31| @x -#-----| -> @x +#-----| -> self # 31| @x #-----| -> 2 +# 31| self +#-----| -> @x + +# 31| self +#-----| -> @x + # 31| ... = ... #-----| -> @@y diff --git a/ruby/ql/test/library-tests/dataflow/global/Flow.expected b/ruby/ql/test/library-tests/dataflow/global/Flow.expected new file mode 100644 index 00000000000..7975d3d5eb1 --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/global/Flow.expected @@ -0,0 +1,84 @@ +failures +edges +| instance_variables.rb:2:19:2:19 | x : | instance_variables.rb:3:18:3:18 | x : | +| instance_variables.rb:2:19:2:19 | x : | instance_variables.rb:3:18:3:18 | x : | +| instance_variables.rb:3:18:3:18 | x : | instance_variables.rb:3:9:3:14 | [post] self [@field] : | +| instance_variables.rb:3:18:3:18 | x : | instance_variables.rb:3:9:3:14 | [post] self [@field] : | +| instance_variables.rb:5:5:7:7 | self in get_field [@field] : | instance_variables.rb:6:16:6:21 | self [@field] : | +| instance_variables.rb:5:5:7:7 | self in get_field [@field] : | instance_variables.rb:6:16:6:21 | self [@field] : | +| instance_variables.rb:6:16:6:21 | @field : | instance_variables.rb:6:9:6:21 | return : | +| instance_variables.rb:6:16:6:21 | @field : | instance_variables.rb:6:9:6:21 | return : | +| instance_variables.rb:6:16:6:21 | self [@field] : | instance_variables.rb:6:16:6:21 | @field : | +| instance_variables.rb:6:16:6:21 | self [@field] : | instance_variables.rb:6:16:6:21 | @field : | +| instance_variables.rb:8:5:10:7 | self in inc_field [@field] : | instance_variables.rb:9:9:9:14 | [post] self [@field] : | +| instance_variables.rb:9:9:9:14 | [post] self [@field] : | instance_variables.rb:9:9:9:14 | [post] self [@field] : | +| instance_variables.rb:11:5:11:8 | [post] self [@foo] : | instance_variables.rb:12:10:12:13 | self [@foo] : | +| instance_variables.rb:11:5:11:8 | [post] self [@foo] : | instance_variables.rb:12:10:12:13 | self [@foo] : | +| instance_variables.rb:11:12:11:22 | call to source : | instance_variables.rb:11:5:11:8 | [post] self [@foo] : | +| instance_variables.rb:11:12:11:22 | call to source : | instance_variables.rb:11:5:11:8 | [post] self [@foo] : | +| instance_variables.rb:12:10:12:13 | self [@foo] : | instance_variables.rb:12:10:12:13 | @foo | +| instance_variables.rb:12:10:12:13 | self [@foo] : | instance_variables.rb:12:10:12:13 | @foo | +| instance_variables.rb:16:1:16:3 | [post] foo [@field] : | instance_variables.rb:17:6:17:8 | foo [@field] : | +| instance_variables.rb:16:1:16:3 | [post] foo [@field] : | instance_variables.rb:17:6:17:8 | foo [@field] : | +| instance_variables.rb:16:15:16:24 | call to source : | instance_variables.rb:2:19:2:19 | x : | +| instance_variables.rb:16:15:16:24 | call to source : | instance_variables.rb:2:19:2:19 | x : | +| instance_variables.rb:16:15:16:24 | call to source : | instance_variables.rb:16:1:16:3 | [post] foo [@field] : | +| instance_variables.rb:16:15:16:24 | call to source : | instance_variables.rb:16:1:16:3 | [post] foo [@field] : | +| instance_variables.rb:17:6:17:8 | foo [@field] : | instance_variables.rb:5:5:7:7 | self in get_field [@field] : | +| instance_variables.rb:17:6:17:8 | foo [@field] : | instance_variables.rb:5:5:7:7 | self in get_field [@field] : | +| instance_variables.rb:17:6:17:8 | foo [@field] : | instance_variables.rb:17:6:17:18 | call to get_field | +| instance_variables.rb:17:6:17:8 | foo [@field] : | instance_variables.rb:17:6:17:18 | call to get_field | +| instance_variables.rb:20:1:20:3 | [post] bar [@field] : | instance_variables.rb:21:6:21:8 | bar [@field] : | +| instance_variables.rb:20:15:20:23 | call to source : | instance_variables.rb:2:19:2:19 | x : | +| instance_variables.rb:20:15:20:23 | call to source : | instance_variables.rb:20:1:20:3 | [post] bar [@field] : | +| instance_variables.rb:21:6:21:8 | bar [@field] : | instance_variables.rb:8:5:10:7 | self in inc_field [@field] : | +| instance_variables.rb:21:6:21:8 | bar [@field] : | instance_variables.rb:21:6:21:18 | call to inc_field | +nodes +| instance_variables.rb:2:19:2:19 | x : | semmle.label | x : | +| instance_variables.rb:2:19:2:19 | x : | semmle.label | x : | +| instance_variables.rb:3:9:3:14 | [post] self [@field] : | semmle.label | [post] self [@field] : | +| instance_variables.rb:3:9:3:14 | [post] self [@field] : | semmle.label | [post] self [@field] : | +| instance_variables.rb:3:18:3:18 | x : | semmle.label | x : | +| instance_variables.rb:3:18:3:18 | x : | semmle.label | x : | +| instance_variables.rb:5:5:7:7 | self in get_field [@field] : | semmle.label | self in get_field [@field] : | +| instance_variables.rb:5:5:7:7 | self in get_field [@field] : | semmle.label | self in get_field [@field] : | +| instance_variables.rb:6:9:6:21 | return : | semmle.label | return : | +| instance_variables.rb:6:9:6:21 | return : | semmle.label | return : | +| instance_variables.rb:6:16:6:21 | @field : | semmle.label | @field : | +| instance_variables.rb:6:16:6:21 | @field : | semmle.label | @field : | +| instance_variables.rb:6:16:6:21 | self [@field] : | semmle.label | self [@field] : | +| instance_variables.rb:6:16:6:21 | self [@field] : | semmle.label | self [@field] : | +| instance_variables.rb:8:5:10:7 | self in inc_field [@field] : | semmle.label | self in inc_field [@field] : | +| instance_variables.rb:9:9:9:14 | [post] self [@field] : | semmle.label | [post] self [@field] : | +| instance_variables.rb:11:5:11:8 | [post] self [@foo] : | semmle.label | [post] self [@foo] : | +| instance_variables.rb:11:5:11:8 | [post] self [@foo] : | semmle.label | [post] self [@foo] : | +| instance_variables.rb:11:12:11:22 | call to source : | semmle.label | call to source : | +| instance_variables.rb:11:12:11:22 | call to source : | semmle.label | call to source : | +| instance_variables.rb:12:10:12:13 | @foo | semmle.label | @foo | +| instance_variables.rb:12:10:12:13 | @foo | semmle.label | @foo | +| instance_variables.rb:12:10:12:13 | self [@foo] : | semmle.label | self [@foo] : | +| instance_variables.rb:12:10:12:13 | self [@foo] : | semmle.label | self [@foo] : | +| instance_variables.rb:16:1:16:3 | [post] foo [@field] : | semmle.label | [post] foo [@field] : | +| instance_variables.rb:16:1:16:3 | [post] foo [@field] : | semmle.label | [post] foo [@field] : | +| instance_variables.rb:16:15:16:24 | call to source : | semmle.label | call to source : | +| instance_variables.rb:16:15:16:24 | call to source : | semmle.label | call to source : | +| instance_variables.rb:17:6:17:8 | foo [@field] : | semmle.label | foo [@field] : | +| instance_variables.rb:17:6:17:8 | foo [@field] : | semmle.label | foo [@field] : | +| instance_variables.rb:17:6:17:18 | call to get_field | semmle.label | call to get_field | +| instance_variables.rb:17:6:17:18 | call to get_field | semmle.label | call to get_field | +| instance_variables.rb:20:1:20:3 | [post] bar [@field] : | semmle.label | [post] bar [@field] : | +| instance_variables.rb:20:15:20:23 | call to source : | semmle.label | call to source : | +| instance_variables.rb:21:6:21:8 | bar [@field] : | semmle.label | bar [@field] : | +| instance_variables.rb:21:6:21:18 | call to inc_field | semmle.label | call to inc_field | +subpaths +| instance_variables.rb:16:15:16:24 | call to source : | instance_variables.rb:2:19:2:19 | x : | instance_variables.rb:3:9:3:14 | [post] self [@field] : | instance_variables.rb:16:1:16:3 | [post] foo [@field] : | +| instance_variables.rb:16:15:16:24 | call to source : | instance_variables.rb:2:19:2:19 | x : | instance_variables.rb:3:9:3:14 | [post] self [@field] : | instance_variables.rb:16:1:16:3 | [post] foo [@field] : | +| instance_variables.rb:17:6:17:8 | foo [@field] : | instance_variables.rb:5:5:7:7 | self in get_field [@field] : | instance_variables.rb:6:9:6:21 | return : | instance_variables.rb:17:6:17:18 | call to get_field | +| instance_variables.rb:17:6:17:8 | foo [@field] : | instance_variables.rb:5:5:7:7 | self in get_field [@field] : | instance_variables.rb:6:9:6:21 | return : | instance_variables.rb:17:6:17:18 | call to get_field | +| instance_variables.rb:20:15:20:23 | call to source : | instance_variables.rb:2:19:2:19 | x : | instance_variables.rb:3:9:3:14 | [post] self [@field] : | instance_variables.rb:20:1:20:3 | [post] bar [@field] : | +| instance_variables.rb:21:6:21:8 | bar [@field] : | instance_variables.rb:8:5:10:7 | self in inc_field [@field] : | instance_variables.rb:8:5:10:7 | self in inc_field [@field] : | instance_variables.rb:21:6:21:18 | call to inc_field | +| instance_variables.rb:21:6:21:8 | bar [@field] : | instance_variables.rb:8:5:10:7 | self in inc_field [@field] : | instance_variables.rb:9:9:9:14 | [post] self [@field] : | instance_variables.rb:21:6:21:18 | call to inc_field | +#select +| instance_variables.rb:12:10:12:13 | @foo | instance_variables.rb:11:12:11:22 | call to source : | instance_variables.rb:12:10:12:13 | @foo | $@ | instance_variables.rb:11:12:11:22 | call to source : | call to source : | +| instance_variables.rb:17:6:17:18 | call to get_field | instance_variables.rb:16:15:16:24 | call to source : | instance_variables.rb:17:6:17:18 | call to get_field | $@ | instance_variables.rb:16:15:16:24 | call to source : | call to source : | +| instance_variables.rb:21:6:21:18 | call to inc_field | instance_variables.rb:20:15:20:23 | call to source : | instance_variables.rb:21:6:21:18 | call to inc_field | $@ | instance_variables.rb:20:15:20:23 | call to source : | call to source : | diff --git a/ruby/ql/test/library-tests/dataflow/global/Flow.ql b/ruby/ql/test/library-tests/dataflow/global/Flow.ql new file mode 100644 index 00000000000..00449a7ac5f --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/global/Flow.ql @@ -0,0 +1,12 @@ +/** + * @kind path-problem + */ + +import ruby +import codeql.ruby.DataFlow +private import TestUtilities.InlineFlowTest +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, DefaultTaintFlowConf conf +where conf.hasFlowPath(source, sink) +select sink, source, sink, "$@", source, source.toString() diff --git a/ruby/ql/test/library-tests/dataflow/global/instance_variables.rb b/ruby/ql/test/library-tests/dataflow/global/instance_variables.rb new file mode 100644 index 00000000000..be91c6da8fb --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/global/instance_variables.rb @@ -0,0 +1,21 @@ +class Foo + def set_field x + @field = x + end + def get_field + return @field + end + def inc_field + @field += 1 + end + @foo = source("7") + sink(@foo) # $ hasValueFlow=7 + +end +foo = Foo.new +foo.set_field(source(42)) +sink(foo.get_field) # $ hasValueFlow=42 + +bar = Foo.new +bar.set_field(source(5)) +sink(bar.inc_field) # $ hasTaintFlow=5 \ No newline at end of file diff --git a/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected b/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected index efbf76dfc76..cd548ace1cd 100644 --- a/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected +++ b/ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected @@ -8,9 +8,11 @@ track | type_tracker.rb:2:5:5:7 | field= | type tracker without call steps | type_tracker.rb:2:5:5:7 | field= | | type_tracker.rb:2:5:5:7 | return return in field= | type tracker without call steps | type_tracker.rb:2:5:5:7 | return return in field= | | type_tracker.rb:2:5:5:7 | return return in field= | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= | +| type_tracker.rb:2:5:5:7 | self (field=) | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:2:5:5:7 | self (field=) | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:2:5:5:7 | self (field=) | type tracker without call steps | type_tracker.rb:2:5:5:7 | self (field=) | | type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) | +| type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:2:5:5:7 | self in field= | type tracker without call steps | type_tracker.rb:2:5:5:7 | self in field= | | type_tracker.rb:2:16:2:18 | val | type tracker with call steps | type_tracker.rb:2:16:2:18 | val | @@ -19,6 +21,7 @@ track | type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= | +| type_tracker.rb:3:9:3:23 | [post] self | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:3:9:3:23 | [post] self | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:3:9:3:23 | [post] self | type tracker without call steps | type_tracker.rb:3:9:3:23 | [post] self | | type_tracker.rb:3:9:3:23 | call to puts | type tracker without call steps | type_tracker.rb:3:9:3:23 | call to puts | @@ -26,16 +29,20 @@ track | type_tracker.rb:3:14:3:23 | [post] call to field | type tracker without call steps | type_tracker.rb:3:14:3:23 | [post] call to field | | type_tracker.rb:3:14:3:23 | call to field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field | | type_tracker.rb:4:9:4:14 | @field | type tracker without call steps | type_tracker.rb:4:9:4:14 | @field | +| type_tracker.rb:4:9:4:14 | [post] self | type tracker without call steps | type_tracker.rb:4:9:4:14 | [post] self | | type_tracker.rb:7:5:9:7 | &block | type tracker without call steps | type_tracker.rb:7:5:9:7 | &block | | type_tracker.rb:7:5:9:7 | field | type tracker without call steps | type_tracker.rb:7:5:9:7 | field | | type_tracker.rb:7:5:9:7 | return return in field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field | | type_tracker.rb:7:5:9:7 | return return in field | type tracker without call steps | type_tracker.rb:7:5:9:7 | return return in field | | type_tracker.rb:7:5:9:7 | return return in field | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field | +| type_tracker.rb:7:5:9:7 | self (field) | type tracker without call steps | type_tracker.rb:7:5:9:7 | self (field) | +| type_tracker.rb:7:5:9:7 | self in field | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:7:5:9:7 | self in field | type tracker without call steps | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:8:9:8:14 | @field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field | | type_tracker.rb:8:9:8:14 | @field | type tracker without call steps | type_tracker.rb:7:5:9:7 | return return in field | | type_tracker.rb:8:9:8:14 | @field | type tracker without call steps | type_tracker.rb:8:9:8:14 | @field | | type_tracker.rb:8:9:8:14 | @field | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field | +| type_tracker.rb:8:9:8:14 | [post] self | type tracker without call steps | type_tracker.rb:8:9:8:14 | [post] self | | type_tracker.rb:12:1:16:3 | &block | type tracker without call steps | type_tracker.rb:12:1:16:3 | &block | | type_tracker.rb:12:1:16:3 | m | type tracker without call steps | type_tracker.rb:12:1:16:3 | m | | type_tracker.rb:12:1:16:3 | return return in m | type tracker without call steps | type_tracker.rb:12:1:16:3 | return return in m | @@ -47,13 +54,16 @@ track | type_tracker.rb:13:11:13:19 | [post] Container | type tracker without call steps | type_tracker.rb:13:11:13:19 | [post] Container | | type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) | | type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:2:5:5:7 | self in field= | +| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:13:11:13:23 | call to new | type tracker without call steps | type_tracker.rb:13:11:13:23 | call to new | +| type_tracker.rb:14:5:14:7 | [post] var | type tracker with call steps | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:14:5:14:7 | [post] var | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:14:5:14:7 | [post] var | type tracker without call steps | type_tracker.rb:14:5:14:7 | [post] var | | type_tracker.rb:14:5:14:13 | call to field= | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= | | type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps | type_tracker.rb:2:16:2:18 | val | +| type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps with content field | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:14:17:14:23 | "hello" | type tracker with call steps with content field | type_tracker.rb:7:5:9:7 | self in field | | type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= | | type_tracker.rb:14:17:14:23 | "hello" | type tracker without call steps | type_tracker.rb:14:17:14:23 | "hello" | @@ -196,12 +206,18 @@ trackEnd | type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:2:5:5:7 | self (field=) | | type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:9:3:23 | self | | type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:14:3:17 | self | +| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:4:9:4:14 | self | +| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:7:5:9:7 | self in field | +| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:8:9:8:14 | self | | type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:2:5:5:7 | self (field=) | | type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:2:5:5:7 | self in field= | | type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:3:9:3:23 | self | | type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:3:14:3:17 | self | +| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:4:9:4:14 | self | +| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:7:5:9:7 | self in field | +| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:8:9:8:14 | self | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:5:5:7 | return return in field= | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val | | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val | @@ -214,23 +230,33 @@ trackEnd | type_tracker.rb:2:16:2:18 | val | type_tracker.rb:14:5:14:13 | call to field= | | type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:3:9:3:23 | [post] self | | type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:3:14:3:17 | self | +| type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:4:9:4:14 | self | +| type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:7:5:9:7 | self in field | +| type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:8:9:8:14 | self | | type_tracker.rb:3:9:3:23 | call to puts | type_tracker.rb:3:9:3:23 | call to puts | | type_tracker.rb:3:14:3:17 | [post] self | type_tracker.rb:3:14:3:17 | [post] self | +| type_tracker.rb:3:14:3:17 | [post] self | type_tracker.rb:4:9:4:14 | self | | type_tracker.rb:3:14:3:23 | [post] call to field | type_tracker.rb:3:14:3:23 | [post] call to field | | type_tracker.rb:3:14:3:23 | call to field | type_tracker.rb:3:14:3:23 | call to field | | type_tracker.rb:4:9:4:14 | @field | type_tracker.rb:4:9:4:14 | @field | +| type_tracker.rb:4:9:4:14 | [post] self | type_tracker.rb:4:9:4:14 | [post] self | | type_tracker.rb:7:5:9:7 | &block | type_tracker.rb:7:5:9:7 | &block | | type_tracker.rb:7:5:9:7 | field | type_tracker.rb:1:1:10:3 | Container | | type_tracker.rb:7:5:9:7 | field | type_tracker.rb:7:5:9:7 | field | | type_tracker.rb:7:5:9:7 | return return in field | type_tracker.rb:3:14:3:23 | call to field | | type_tracker.rb:7:5:9:7 | return return in field | type_tracker.rb:7:5:9:7 | return return in field | | type_tracker.rb:7:5:9:7 | return return in field | type_tracker.rb:15:10:15:18 | call to field | +| type_tracker.rb:7:5:9:7 | self (field) | type_tracker.rb:7:5:9:7 | self (field) | +| type_tracker.rb:7:5:9:7 | self (field) | type_tracker.rb:8:9:8:14 | self | +| type_tracker.rb:7:5:9:7 | self in field | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:7:5:9:7 | self in field | type_tracker.rb:7:5:9:7 | self in field | +| type_tracker.rb:7:5:9:7 | self in field | type_tracker.rb:8:9:8:14 | self | | type_tracker.rb:8:9:8:14 | @field | type_tracker.rb:3:14:3:23 | call to field | | type_tracker.rb:8:9:8:14 | @field | type_tracker.rb:7:5:9:7 | return return in field | | type_tracker.rb:8:9:8:14 | @field | type_tracker.rb:8:9:8:14 | @field | | type_tracker.rb:8:9:8:14 | @field | type_tracker.rb:15:10:15:18 | call to field | +| type_tracker.rb:8:9:8:14 | [post] self | type_tracker.rb:8:9:8:14 | [post] self | | type_tracker.rb:12:1:16:3 | &block | type_tracker.rb:12:1:16:3 | &block | | type_tracker.rb:12:1:16:3 | m | type_tracker.rb:12:1:16:3 | m | | type_tracker.rb:12:1:16:3 | return return in m | type_tracker.rb:12:1:16:3 | return return in m | @@ -246,13 +272,18 @@ trackEnd | type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:2:5:5:7 | self in field= | | type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:3:9:3:23 | self | | type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:3:14:3:17 | self | +| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:4:9:4:14 | self | +| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:7:5:9:7 | self in field | +| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:8:9:8:14 | self | | type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:13:5:13:23 | ... = ... | | type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:13:5:13:23 | ... = ... | | type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:13:11:13:23 | call to new | | type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:14:5:14:7 | var | | type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:15:10:15:12 | var | +| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:7:5:9:7 | self (field) | | type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:7:5:9:7 | self in field | +| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:8:9:8:14 | self | | type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:14:5:14:7 | [post] var | | type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:15:10:15:12 | var | | type_tracker.rb:14:5:14:13 | call to field= | type_tracker.rb:14:5:14:13 | call to field= | diff --git a/ruby/ql/test/library-tests/variables/ssa.expected b/ruby/ql/test/library-tests/variables/ssa.expected index 583c9686b83..62a3bee1a81 100644 --- a/ruby/ql/test/library-tests/variables/ssa.expected +++ b/ruby/ql/test/library-tests/variables/ssa.expected @@ -6,8 +6,19 @@ definition | class_variables.rb:13:3:15:5 | self (s) | class_variables.rb:13:3:15:5 | self | | class_variables.rb:26:1:29:3 | self (N) | class_variables.rb:26:1:29:3 | self | | instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | +| instance_variables.rb:1:1:44:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | +| instance_variables.rb:3:1:5:3 | self (foo) | instance_variables.rb:3:1:5:3 | self | | instance_variables.rb:7:1:9:3 | self (print_foo) | instance_variables.rb:7:1:9:3 | self | +| instance_variables.rb:13:1:18:3 | self (X) | instance_variables.rb:13:1:18:3 | self | +| instance_variables.rb:15:3:17:5 | self (m) | instance_variables.rb:15:3:17:5 | self | +| instance_variables.rb:20:1:25:3 | self (M) | instance_variables.rb:20:1:25:3 | self | +| instance_variables.rb:22:2:24:4 | self (n) | instance_variables.rb:22:2:24:4 | self | +| instance_variables.rb:27:6:29:1 | | instance_variables.rb:1:1:44:4 | self | +| instance_variables.rb:31:1:33:3 | self (bar) | instance_variables.rb:31:1:33:3 | self | +| instance_variables.rb:32:10:32:21 | | instance_variables.rb:31:1:33:3 | self | +| instance_variables.rb:35:1:44:4 | self (C) | instance_variables.rb:35:1:44:4 | self | | instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | +| instance_variables.rb:38:4:40:6 | self (y) | instance_variables.rb:38:4:40:6 | self | | nested_scopes.rb:1:1:3:3 | self (a) | nested_scopes.rb:1:1:3:3 | self | | nested_scopes.rb:4:1:39:3 | self (C) | nested_scopes.rb:4:1:39:3 | self | | nested_scopes.rb:5:3:5:7 | ... = ... | nested_scopes.rb:5:3:5:3 | a | @@ -158,10 +169,23 @@ read | class_variables.rb:26:1:29:3 | self (N) | class_variables.rb:26:1:29:3 | self | class_variables.rb:27:3:27:11 | self | | class_variables.rb:26:1:29:3 | self (N) | class_variables.rb:26:1:29:3 | self | class_variables.rb:28:3:28:7 | self | | instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:11:1:11:9 | self | +| instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:11:6:11:9 | self | | instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:27:1:29:1 | self | +| instance_variables.rb:1:1:44:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:1:1:1:4 | self | +| instance_variables.rb:3:1:5:3 | self (foo) | instance_variables.rb:3:1:5:3 | self | instance_variables.rb:4:3:4:6 | self | | instance_variables.rb:7:1:9:3 | self (print_foo) | instance_variables.rb:7:1:9:3 | self | instance_variables.rb:8:3:8:11 | self | +| instance_variables.rb:7:1:9:3 | self (print_foo) | instance_variables.rb:7:1:9:3 | self | instance_variables.rb:8:8:8:11 | self | +| instance_variables.rb:13:1:18:3 | self (X) | instance_variables.rb:13:1:18:3 | self | instance_variables.rb:14:3:14:4 | self | +| instance_variables.rb:15:3:17:5 | self (m) | instance_variables.rb:15:3:17:5 | self | instance_variables.rb:16:5:16:6 | self | +| instance_variables.rb:20:1:25:3 | self (M) | instance_variables.rb:20:1:25:3 | self | instance_variables.rb:21:2:21:3 | self | +| instance_variables.rb:22:2:24:4 | self (n) | instance_variables.rb:22:2:24:4 | self | instance_variables.rb:23:4:23:5 | self | +| instance_variables.rb:27:6:29:1 | | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self | +| instance_variables.rb:32:10:32:21 | | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self | +| instance_variables.rb:35:1:44:4 | self (C) | instance_variables.rb:35:1:44:4 | self | instance_variables.rb:36:3:36:4 | self | | instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:41:4:41:4 | self | | instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:42:4:42:7 | self | +| instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:42:6:42:7 | self | +| instance_variables.rb:38:4:40:6 | self (y) | instance_variables.rb:38:4:40:6 | self | instance_variables.rb:39:6:39:7 | self | | nested_scopes.rb:1:1:3:3 | self (a) | nested_scopes.rb:1:1:3:3 | self | nested_scopes.rb:2:3:2:17 | self | | nested_scopes.rb:4:1:39:3 | self (C) | nested_scopes.rb:4:1:39:3 | self | nested_scopes.rb:38:3:38:8 | self | | nested_scopes.rb:5:3:5:7 | ... = ... | nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:38:8:38:8 | a | @@ -327,8 +351,18 @@ firstRead | class_variables.rb:13:3:15:5 | self (s) | class_variables.rb:13:3:15:5 | self | class_variables.rb:14:4:14:8 | self | | class_variables.rb:26:1:29:3 | self (N) | class_variables.rb:26:1:29:3 | self | class_variables.rb:27:3:27:11 | self | | instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:11:1:11:9 | self | +| instance_variables.rb:1:1:44:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:1:1:1:4 | self | +| instance_variables.rb:3:1:5:3 | self (foo) | instance_variables.rb:3:1:5:3 | self | instance_variables.rb:4:3:4:6 | self | | instance_variables.rb:7:1:9:3 | self (print_foo) | instance_variables.rb:7:1:9:3 | self | instance_variables.rb:8:3:8:11 | self | +| instance_variables.rb:13:1:18:3 | self (X) | instance_variables.rb:13:1:18:3 | self | instance_variables.rb:14:3:14:4 | self | +| instance_variables.rb:15:3:17:5 | self (m) | instance_variables.rb:15:3:17:5 | self | instance_variables.rb:16:5:16:6 | self | +| instance_variables.rb:20:1:25:3 | self (M) | instance_variables.rb:20:1:25:3 | self | instance_variables.rb:21:2:21:3 | self | +| instance_variables.rb:22:2:24:4 | self (n) | instance_variables.rb:22:2:24:4 | self | instance_variables.rb:23:4:23:5 | self | +| instance_variables.rb:27:6:29:1 | | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self | +| instance_variables.rb:32:10:32:21 | | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self | +| instance_variables.rb:35:1:44:4 | self (C) | instance_variables.rb:35:1:44:4 | self | instance_variables.rb:36:3:36:4 | self | | instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:41:4:41:4 | self | +| instance_variables.rb:38:4:40:6 | self (y) | instance_variables.rb:38:4:40:6 | self | instance_variables.rb:39:6:39:7 | self | | nested_scopes.rb:1:1:3:3 | self (a) | nested_scopes.rb:1:1:3:3 | self | nested_scopes.rb:2:3:2:17 | self | | nested_scopes.rb:4:1:39:3 | self (C) | nested_scopes.rb:4:1:39:3 | self | nested_scopes.rb:38:3:38:8 | self | | nested_scopes.rb:5:3:5:7 | ... = ... | nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:38:8:38:8 | a | @@ -455,9 +489,20 @@ lastRead | class_variables.rb:10:3:12:5 | self (b) | class_variables.rb:10:3:12:5 | self | class_variables.rb:11:5:11:9 | self | | class_variables.rb:13:3:15:5 | self (s) | class_variables.rb:13:3:15:5 | self | class_variables.rb:14:4:14:8 | self | | class_variables.rb:26:1:29:3 | self (N) | class_variables.rb:26:1:29:3 | self | class_variables.rb:28:3:28:7 | self | +| instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:1:1:1:4 | self | | instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:27:1:29:1 | self | -| instance_variables.rb:7:1:9:3 | self (print_foo) | instance_variables.rb:7:1:9:3 | self | instance_variables.rb:8:3:8:11 | self | -| instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:42:4:42:7 | self | +| instance_variables.rb:1:1:44:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:1:1:1:4 | self | +| instance_variables.rb:3:1:5:3 | self (foo) | instance_variables.rb:3:1:5:3 | self | instance_variables.rb:4:3:4:6 | self | +| instance_variables.rb:7:1:9:3 | self (print_foo) | instance_variables.rb:7:1:9:3 | self | instance_variables.rb:8:8:8:11 | self | +| instance_variables.rb:13:1:18:3 | self (X) | instance_variables.rb:13:1:18:3 | self | instance_variables.rb:14:3:14:4 | self | +| instance_variables.rb:15:3:17:5 | self (m) | instance_variables.rb:15:3:17:5 | self | instance_variables.rb:16:5:16:6 | self | +| instance_variables.rb:20:1:25:3 | self (M) | instance_variables.rb:20:1:25:3 | self | instance_variables.rb:21:2:21:3 | self | +| instance_variables.rb:22:2:24:4 | self (n) | instance_variables.rb:22:2:24:4 | self | instance_variables.rb:23:4:23:5 | self | +| instance_variables.rb:27:6:29:1 | | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self | +| instance_variables.rb:32:10:32:21 | | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self | +| instance_variables.rb:35:1:44:4 | self (C) | instance_variables.rb:35:1:44:4 | self | instance_variables.rb:36:3:36:4 | self | +| instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:42:6:42:7 | self | +| instance_variables.rb:38:4:40:6 | self (y) | instance_variables.rb:38:4:40:6 | self | instance_variables.rb:39:6:39:7 | self | | nested_scopes.rb:1:1:3:3 | self (a) | nested_scopes.rb:1:1:3:3 | self | nested_scopes.rb:2:3:2:17 | self | | nested_scopes.rb:4:1:39:3 | self (C) | nested_scopes.rb:4:1:39:3 | self | nested_scopes.rb:38:3:38:8 | self | | nested_scopes.rb:5:3:5:7 | ... = ... | nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:38:8:38:8 | a | @@ -580,8 +625,12 @@ lastRead | ssa.rb:84:10:86:8 | | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured | adjacentReads | class_variables.rb:26:1:29:3 | self (N) | class_variables.rb:26:1:29:3 | self | class_variables.rb:27:3:27:11 | self | class_variables.rb:28:3:28:7 | self | -| instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:11:1:11:9 | self | instance_variables.rb:27:1:29:1 | self | +| instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:1:1:1:4 | self | instance_variables.rb:11:1:11:9 | self | +| instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:11:1:11:9 | self | instance_variables.rb:11:6:11:9 | self | +| instance_variables.rb:1:1:1:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:11:6:11:9 | self | instance_variables.rb:27:1:29:1 | self | +| instance_variables.rb:7:1:9:3 | self (print_foo) | instance_variables.rb:7:1:9:3 | self | instance_variables.rb:8:3:8:11 | self | instance_variables.rb:8:8:8:11 | self | | instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:41:4:41:4 | self | instance_variables.rb:42:4:42:7 | self | +| instance_variables.rb:37:3:43:5 | self (x) | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:42:4:42:7 | self | instance_variables.rb:42:6:42:7 | self | | nested_scopes.rb:8:5:35:7 | self (N) | nested_scopes.rb:8:5:35:7 | self | nested_scopes.rb:27:11:27:14 | self | nested_scopes.rb:30:16:30:19 | self | | nested_scopes.rb:8:5:35:7 | self (N) | nested_scopes.rb:8:5:35:7 | self | nested_scopes.rb:30:16:30:19 | self | nested_scopes.rb:34:7:34:12 | self | | nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:14:16:14:16 | a | nested_scopes.rb:15:11:15:11 | a | diff --git a/ruby/ql/test/library-tests/variables/varaccess.expected b/ruby/ql/test/library-tests/variables/varaccess.expected index 2b3294bc0a7..59a5ee362f6 100644 --- a/ruby/ql/test/library-tests/variables/varaccess.expected +++ b/ruby/ql/test/library-tests/variables/varaccess.expected @@ -15,23 +15,36 @@ variableAccess | class_variables.rb:28:3:28:7 | self | class_variables.rb:26:1:29:3 | self | class_variables.rb:26:1:29:3 | N | | class_variables.rb:28:5:28:7 | @@x | class_variables.rb:28:5:28:7 | @@x | class_variables.rb:26:1:29:3 | N | | instance_variables.rb:1:1:1:4 | @top | instance_variables.rb:1:1:1:4 | @top | instance_variables.rb:1:1:44:4 | instance_variables.rb | +| instance_variables.rb:1:1:1:4 | self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:1:1:44:4 | instance_variables.rb | | instance_variables.rb:4:3:4:6 | @foo | instance_variables.rb:4:3:4:6 | @foo | instance_variables.rb:1:1:44:4 | instance_variables.rb | +| instance_variables.rb:4:3:4:6 | self | instance_variables.rb:3:1:5:3 | self | instance_variables.rb:3:1:5:3 | foo | | instance_variables.rb:8:3:8:11 | self | instance_variables.rb:7:1:9:3 | self | instance_variables.rb:7:1:9:3 | print_foo | | instance_variables.rb:8:8:8:11 | @foo | instance_variables.rb:4:3:4:6 | @foo | instance_variables.rb:1:1:44:4 | instance_variables.rb | +| instance_variables.rb:8:8:8:11 | self | instance_variables.rb:7:1:9:3 | self | instance_variables.rb:7:1:9:3 | print_foo | | instance_variables.rb:11:1:11:9 | self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:1:1:44:4 | instance_variables.rb | | instance_variables.rb:11:6:11:9 | @top | instance_variables.rb:1:1:1:4 | @top | instance_variables.rb:1:1:44:4 | instance_variables.rb | +| instance_variables.rb:11:6:11:9 | self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:1:1:44:4 | instance_variables.rb | | instance_variables.rb:14:3:14:4 | @x | instance_variables.rb:14:3:14:4 | @x | instance_variables.rb:13:1:18:3 | X | +| instance_variables.rb:14:3:14:4 | self | instance_variables.rb:13:1:18:3 | self | instance_variables.rb:13:1:18:3 | X | | instance_variables.rb:16:5:16:6 | @y | instance_variables.rb:16:5:16:6 | @y | instance_variables.rb:13:1:18:3 | X | +| instance_variables.rb:16:5:16:6 | self | instance_variables.rb:15:3:17:5 | self | instance_variables.rb:15:3:17:5 | m | | instance_variables.rb:21:2:21:3 | @m | instance_variables.rb:21:2:21:3 | @m | instance_variables.rb:20:1:25:3 | M | +| instance_variables.rb:21:2:21:3 | self | instance_variables.rb:20:1:25:3 | self | instance_variables.rb:20:1:25:3 | M | | instance_variables.rb:23:4:23:5 | @n | instance_variables.rb:23:4:23:5 | @n | instance_variables.rb:20:1:25:3 | M | +| instance_variables.rb:23:4:23:5 | self | instance_variables.rb:22:2:24:4 | self | instance_variables.rb:22:2:24:4 | n | | instance_variables.rb:27:1:29:1 | self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:1:1:44:4 | instance_variables.rb | | instance_variables.rb:28:3:28:4 | @x | instance_variables.rb:28:3:28:4 | @x | instance_variables.rb:1:1:44:4 | instance_variables.rb | +| instance_variables.rb:28:3:28:4 | self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:1:1:44:4 | instance_variables.rb | | instance_variables.rb:32:12:32:13 | @x | instance_variables.rb:32:12:32:13 | @x | instance_variables.rb:1:1:44:4 | instance_variables.rb | +| instance_variables.rb:32:12:32:13 | self | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:31:1:33:3 | bar | | instance_variables.rb:36:3:36:4 | @x | instance_variables.rb:36:3:36:4 | @x | instance_variables.rb:35:1:44:4 | C | +| instance_variables.rb:36:3:36:4 | self | instance_variables.rb:35:1:44:4 | self | instance_variables.rb:35:1:44:4 | C | | instance_variables.rb:39:6:39:7 | @x | instance_variables.rb:39:6:39:7 | @x | instance_variables.rb:35:1:44:4 | C | +| instance_variables.rb:39:6:39:7 | self | instance_variables.rb:38:4:40:6 | self | instance_variables.rb:38:4:40:6 | y | | instance_variables.rb:41:4:41:4 | self | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:37:3:43:5 | x | | instance_variables.rb:42:4:42:7 | self | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:37:3:43:5 | x | | instance_variables.rb:42:6:42:7 | @x | instance_variables.rb:39:6:39:7 | @x | instance_variables.rb:35:1:44:4 | C | +| instance_variables.rb:42:6:42:7 | self | instance_variables.rb:37:3:43:5 | self | instance_variables.rb:37:3:43:5 | x | | nested_scopes.rb:2:3:2:17 | self | nested_scopes.rb:1:1:3:3 | self | nested_scopes.rb:1:1:3:3 | a | | nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:5:3:5:3 | a | nested_scopes.rb:4:1:39:3 | C | | nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:7:5:7:5 | a | nested_scopes.rb:6:3:37:5 | M | @@ -390,14 +403,27 @@ readAccess | class_variables.rb:27:3:27:11 | self | | class_variables.rb:28:3:28:7 | self | | class_variables.rb:28:5:28:7 | @@x | +| instance_variables.rb:1:1:1:4 | self | +| instance_variables.rb:4:3:4:6 | self | | instance_variables.rb:8:3:8:11 | self | | instance_variables.rb:8:8:8:11 | @foo | +| instance_variables.rb:8:8:8:11 | self | | instance_variables.rb:11:1:11:9 | self | | instance_variables.rb:11:6:11:9 | @top | +| instance_variables.rb:11:6:11:9 | self | +| instance_variables.rb:14:3:14:4 | self | +| instance_variables.rb:16:5:16:6 | self | +| instance_variables.rb:21:2:21:3 | self | +| instance_variables.rb:23:4:23:5 | self | | instance_variables.rb:27:1:29:1 | self | +| instance_variables.rb:28:3:28:4 | self | +| instance_variables.rb:32:12:32:13 | self | +| instance_variables.rb:36:3:36:4 | self | +| instance_variables.rb:39:6:39:7 | self | | instance_variables.rb:41:4:41:4 | self | | instance_variables.rb:42:4:42:7 | self | | instance_variables.rb:42:6:42:7 | @x | +| instance_variables.rb:42:6:42:7 | self | | nested_scopes.rb:2:3:2:17 | self | | nested_scopes.rb:14:11:14:16 | self | | nested_scopes.rb:14:16:14:16 | a | diff --git a/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.expected b/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.expected index 503e9ec0529..8f2503c8884 100644 --- a/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.expected +++ b/ruby/ql/test/query-tests/security/cwe-079/ReflectedXSS.expected @@ -1,7 +1,10 @@ edges | app/controllers/foo/bars_controller.rb:9:12:9:17 | call to params : | app/controllers/foo/bars_controller.rb:9:12:9:29 | ...[...] : | | app/controllers/foo/bars_controller.rb:9:12:9:29 | ...[...] : | app/views/foo/bars/show.html.erb:47:5:47:13 | call to user_name | +| app/controllers/foo/bars_controller.rb:13:5:13:14 | [post] self [@user_name] : | app/controllers/foo/bars_controller.rb:13:5:13:14 | [post] self [@user_name] : | +| app/controllers/foo/bars_controller.rb:13:5:13:14 | [post] self [@user_name] : | app/views/foo/bars/show.html.erb:51:5:51:18 | call to user_name_memo | | app/controllers/foo/bars_controller.rb:13:20:13:25 | call to params : | app/controllers/foo/bars_controller.rb:13:20:13:37 | ...[...] : | +| app/controllers/foo/bars_controller.rb:13:20:13:37 | ...[...] : | app/controllers/foo/bars_controller.rb:13:5:13:14 | [post] self [@user_name] : | | app/controllers/foo/bars_controller.rb:13:20:13:37 | ...[...] : | app/views/foo/bars/show.html.erb:51:5:51:18 | call to user_name_memo | | app/controllers/foo/bars_controller.rb:17:21:17:26 | call to params : | app/controllers/foo/bars_controller.rb:17:21:17:36 | ...[...] : | | app/controllers/foo/bars_controller.rb:17:21:17:36 | ...[...] : | app/views/foo/bars/show.html.erb:2:18:2:30 | @user_website | @@ -22,6 +25,7 @@ edges nodes | app/controllers/foo/bars_controller.rb:9:12:9:17 | call to params : | semmle.label | call to params : | | app/controllers/foo/bars_controller.rb:9:12:9:29 | ...[...] : | semmle.label | ...[...] : | +| app/controllers/foo/bars_controller.rb:13:5:13:14 | [post] self [@user_name] : | semmle.label | [post] self [@user_name] : | | app/controllers/foo/bars_controller.rb:13:20:13:25 | call to params : | semmle.label | call to params : | | app/controllers/foo/bars_controller.rb:13:20:13:37 | ...[...] : | semmle.label | ...[...] : | | app/controllers/foo/bars_controller.rb:17:21:17:26 | call to params : | semmle.label | call to params : |