diff --git a/ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll b/ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll index c8ca8ff12e62..9f3fc5fa3f24 100644 --- a/ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll +++ b/ruby/ql/lib/codeql/ruby/controlflow/CfgNodes.qll @@ -727,16 +727,30 @@ module ExprNodes { override VariableAccess e; - final override VariableAccess getExpr() { result = ExprCfgNode.super.getExpr() } + override VariableAccess getExpr() { result = ExprCfgNode.super.getExpr() } + + /** Gets the variable that is being accessed. */ + Variable getVariable() { result = this.getExpr().getVariable() } } /** A control-flow node that wraps a `VariableReadAccess` AST expression. */ - class VariableReadAccessCfgNode extends ExprCfgNode { + class VariableReadAccessCfgNode extends VariableAccessCfgNode { override string getAPrimaryQlClass() { result = "VariableReadAccessCfgNode" } override VariableReadAccess e; - final override VariableReadAccess getExpr() { result = ExprCfgNode.super.getExpr() } + override VariableReadAccess getExpr() { result = VariableAccessCfgNode.super.getExpr() } + } + + /** A control-flow node that wraps a `LocalVariableReadAccess` AST expression. */ + class LocalVariableReadAccessCfgNode extends VariableReadAccessCfgNode { + override string getAPrimaryQlClass() { result = "LocalVariableReadAccessCfgNode" } + + override LocalVariableReadAccess e; + + final override LocalVariableReadAccess getExpr() { result = super.getExpr() } + + final override LocalVariable getVariable() { result = super.getVariable() } } private class InstanceVariableAccessMapping extends ExprChildMapping, InstanceVariableAccess { @@ -762,21 +776,32 @@ module ExprNodes { } /** A control-flow node that wraps a `SelfVariableAccess` AST expression. */ - class SelfVariableAccessCfgNode extends ExprCfgNode { + class SelfVariableAccessCfgNode extends VariableAccessCfgNode { final override string getAPrimaryQlClass() { result = "SelfVariableAccessCfgNode" } override SelfVariableAccessMapping e; - override SelfVariableAccess getExpr() { result = ExprCfgNode.super.getExpr() } + override SelfVariableAccess getExpr() { result = VariableAccessCfgNode.super.getExpr() } } /** A control-flow node that wraps a `VariableWriteAccess` AST expression. */ - class VariableWriteAccessCfgNode extends ExprCfgNode { + class VariableWriteAccessCfgNode extends VariableAccessCfgNode { override string getAPrimaryQlClass() { result = "VariableWriteAccessCfgNode" } override VariableWriteAccess e; - final override VariableWriteAccess getExpr() { result = ExprCfgNode.super.getExpr() } + override VariableWriteAccess getExpr() { result = VariableAccessCfgNode.super.getExpr() } + } + + /** A control-flow node that wraps a `LocalVariableWriteAccess` AST expression. */ + class LocalVariableWriteAccessCfgNode extends VariableWriteAccessCfgNode { + override string getAPrimaryQlClass() { result = "LocalVariableWriteAccessCfgNode" } + + override LocalVariableWriteAccess e; + + final override LocalVariableWriteAccess getExpr() { result = super.getExpr() } + + final override LocalVariable getVariable() { result = super.getVariable() } } /** A control-flow node that wraps a `ConstantReadAccess` AST expression. */ diff --git a/ruby/ql/lib/codeql/ruby/dataflow/SSA.qll b/ruby/ql/lib/codeql/ruby/dataflow/SSA.qll index ca956ed89f53..0c3ed496f986 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/SSA.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/SSA.qll @@ -178,6 +178,9 @@ module Ssa { /** Gets the location of this SSA definition. */ Location getLocation() { result = this.getControlFlowNode().getLocation() } + + /** Gets the scope of this SSA definition. */ + CfgScope getScope() { result = this.getBasicBlock().getScope() } } /** @@ -289,7 +292,7 @@ module Ssa { ) } - final override string toString() { result = " " + this.getSourceVariable() } + final override string toString() { result = " " + this.getSourceVariable() } override Location getLocation() { result = this.getBasicBlock().getLocation() } } @@ -324,7 +327,7 @@ module Ssa { */ final Definition getPriorDefinition() { result = SsaImpl::uncertainWriteDefinitionInput(this) } - override string toString() { result = this.getControlFlowNode().toString() } + override string toString() { result = " " + this.getSourceVariable() } } /** diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll index f30f2a020b68..c4d80e1f6ce2 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll @@ -8,10 +8,17 @@ private import FlowSummaryImpl as FlowSummaryImpl private import FlowSummaryImplSpecific as FlowSummaryImplSpecific private import codeql.ruby.dataflow.FlowSummary private import codeql.ruby.dataflow.SSA +private import codeql.ruby.dataflow.internal.SsaImpl as SsaImpl newtype TReturnKind = TNormalReturnKind() or - TBreakReturnKind() + TBreakReturnKind() or + TCapturedReturnKind(LocalVariable v) { + exists(Ssa::Definition def | + SsaImpl::captureFlowOut(_, def, _) and + v = def.getSourceVariable() + ) + } /** * Gets a node that can read the value returned from `call` with return kind @@ -43,6 +50,19 @@ class BreakReturnKind extends ReturnKind, TBreakReturnKind { override string toString() { result = "break" } } +/** + * A value implicitly returned by updating a captured variable. + */ +class CapturedReturnKind extends ReturnKind, TCapturedReturnKind { + LocalVariable v; + + CapturedReturnKind() { this = TCapturedReturnKind(v) } + + LocalVariable getVariable() { result = v } + + override string toString() { result = "captured write to " + v } +} + /** A callable defined in library code, identified by a unique string. */ abstract class LibraryCallable extends string { bindingset[this] @@ -151,6 +171,33 @@ private class NormalCall extends DataFlowCall, TNormalCall { override Location getLocation() { result = c.getLocation() } } +/** + * A call that may ultimately reach a callable, which reads or updates + * (contents of) a captured variable. + */ +class CapturedCall extends DataFlowCall, TCapturedCall { + private CfgNodes::ExprNodes::CallCfgNode c; + + CapturedCall() { this = TCapturedCall(c) } + + /** Gets a target, in which a captured variable is referenced. */ + Callable getATarget() { + exists(Ssa::Definition def | result = def.getScope() | + SsaImpl::captureFlowIn(c, _, _, _, def) + or + SsaImpl::captureFlowOut(c, def, _) + ) + } + + override CfgNodes::ExprNodes::CallCfgNode asCall() { none() } + + override DataFlowCallable getEnclosingCallable() { result = TCfgScope(c.getScope()) } + + override string toString() { result = " " + c.toString() } + + override Location getLocation() { result = c.getLocation() } +} + /** A call for which we want to compute call targets. */ private class RelevantCall extends CfgNodes::ExprNodes::CallCfgNode { pragma[nomagic] @@ -341,6 +388,11 @@ private module Cached { TNormalCall(CfgNodes::ExprNodes::CallCfgNode c) or TSummaryCall(FlowSummaryImpl::Public::SummarizedCallable c, DataFlow::Node receiver) { FlowSummaryImpl::Private::summaryCallbackRange(c, receiver) + } or + TCapturedCall(CfgNodes::ExprNodes::CallCfgNode c) { + SsaImpl::captureFlowIn(c, _, _, _, _) + or + SsaImpl::captureFlowOut(c, _, _) } pragma[nomagic] @@ -478,6 +530,8 @@ private module Cached { result = viableSourceCallable(call) or result = viableLibraryCallable(call) + or + result.asCallable() = call.(CapturedCall).getATarget() } cached @@ -499,7 +553,13 @@ private module Cached { THashSplatArgumentPosition() or TSplatAllArgumentPosition() or TAnyArgumentPosition() or - TAnyKeywordArgumentPosition() + TAnyKeywordArgumentPosition() or + TCapturedArgumentPosition(LocalVariable v) { + exists(Ssa::Definition def | + SsaImpl::captureFlowIn(_, _, _, _, def) and + v = def.getSourceVariable() + ) + } cached newtype TParameterPosition = @@ -521,7 +581,13 @@ private module Cached { THashSplatParameterPosition() or TSplatAllParameterPosition() or TAnyParameterPosition() or - TAnyKeywordParameterPosition() + TAnyKeywordParameterPosition() or + TCapturedParameterPosition(LocalVariable v) { + exists(Ssa::Definition def | + SsaImpl::captureFlowIn(_, _, _, _, def) and + v = def.getSourceVariable() + ) + } } import Cached @@ -921,7 +987,7 @@ private predicate paramReturnFlow( DataFlow::Node nodeFrom, DataFlow::PostUpdateNode nodeTo, StepSummary summary ) { exists(RelevantCall call, DataFlow::Node arg, DataFlow::ParameterNode p, Expr nodeFromPreExpr | - TypeTrackerSpecific::callStep(call, arg, p) and + TypeTrackerSpecific::callStep(TNormalCall(call), arg, p) and nodeTo.getPreUpdateNode() = arg and summary.toString() = "return" and ( @@ -1151,6 +1217,9 @@ class ParameterPosition extends TParameterPosition { /** Holds if this position represents any positional parameter. */ predicate isAnyNamed() { this = TAnyKeywordParameterPosition() } + /** Holds if this position represents a captured variable `v`. */ + predicate isCapturedVariable(LocalVariable v) { this = TCapturedParameterPosition(v) } + /** Gets a textual representation of this position. */ string toString() { this.isSelf() and result = "self" @@ -1170,6 +1239,8 @@ class ParameterPosition extends TParameterPosition { this.isAny() and result = "any" or this.isAnyNamed() and result = "any-named" + or + exists(LocalVariable v | this.isCapturedVariable(v) and result = "captured " + v) } } @@ -1196,6 +1267,9 @@ class ArgumentPosition extends TArgumentPosition { /** Holds if this position represents any positional parameter. */ predicate isAnyNamed() { this = TAnyKeywordArgumentPosition() } + /** Holds if this position represents a captured variable `v`. */ + predicate isCapturedVariable(LocalVariable v) { this = TCapturedArgumentPosition(v) } + /** * Holds if this position represents a synthesized argument containing all keyword * arguments wrapped in a hash. @@ -1221,6 +1295,8 @@ class ArgumentPosition extends TArgumentPosition { this.isHashSplat() and result = "**" or this.isSplatAll() and result = "*" + or + exists(LocalVariable v | this.isCapturedVariable(v) and result = "captured " + v) } } @@ -1256,4 +1332,6 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos.isAnyNamed() and apos.isKeyword(_) or apos.isAnyNamed() and ppos.isKeyword(_) + or + exists(LocalVariable v | apos.isCapturedVariable(v) and ppos.isCapturedVariable(v)) } diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index ba7f72502b94..fc781ee9a820 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -92,7 +92,7 @@ module LocalFlow { * Holds if `exprFrom` is a last read of SSA definition `def`, which * can reach `next`. */ - predicate localFlowSsaInputFromExpr( + predicate localFlowSsaInputFromRead( CfgNodes::ExprCfgNode exprFrom, Ssa::Definition def, Ssa::Definition next ) { exists(BasicBlock bb, int i | @@ -102,6 +102,15 @@ module LocalFlow { ) } + // /** + // * Holds if `nodeFrom` is a node for SSA definition `def`, which can reach `next`. + // */ + // private predicate localFlowSsaInput(Node nodeFrom, Ssa::Definition def, Ssa::Definition next) { + // exists(BasicBlock bb, int i | + // lastRefBeforeRedef(def, bb, i, next) and + // nodeFrom = getSsaRefNode(def, bb, i) + // ) + // } /** Gets the SSA definition node corresponding to parameter `p`. */ SsaDefinitionNode getParameterDefNode(NamedParameter p) { exists(BasicBlock bb, int i | @@ -118,10 +127,15 @@ module LocalFlow { /** * Holds if `nodeFrom` is a parameter node, and `nodeTo` is a corresponding SSA node. */ - predicate localFlowSsaParamInput(Node nodeFrom, Node nodeTo) { - nodeTo = getParameterDefNode(nodeFrom.(ParameterNodeImpl).getParameter()) + predicate localFlowSsaParamInput(ParameterNodeImpl nodeFrom, Node nodeTo) { + nodeTo = getParameterDefNode(nodeFrom.getParameter()) or nodeTo = getSelfParameterDefNode(nodeFrom.(SelfParameterNode).getMethod()) + or + exists(Ssa::CapturedEntryDefinition entry | + entry = nodeTo.(SsaDefinitionNode).getDefinition() and + nodeFrom = TCapturedParameterNode(entry.getScope(), entry.getSourceVariable()) + ) } /** @@ -168,18 +182,15 @@ module LocalFlow { // Flow into phi node from definition exists(Ssa::PhiNode phi | localFlowSsaInputFromDef(nodeFrom, def, phi) and - phi = nodeTo.(SsaDefinitionNode).getDefinition() and - def = phi.getAnInput() + phi = nodeTo.(SsaDefinitionNode).getDefinition() ) + // or + // // Flow into uncertain SSA definition + // exists(SsaImpl::UncertainWriteDefinition uncertain | + // localFlowSsaInput(nodeFrom, def, uncertain) and + // uncertain = nodeTo.(SsaDefinitionNode).getDefinition() + // ) ) - // TODO - // or - // // Flow into uncertain SSA definition - // exists(LocalFlow::UncertainExplicitSsaDefinition uncertain | - // localFlowSsaInput(nodeFrom, def, uncertain) and - // uncertain = nodeTo.(SsaDefinitionNode).getDefinition() and - // def = uncertain.getPriorDefinition() - // ) } predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) { @@ -225,6 +236,8 @@ module LocalFlow { op.getExpr() instanceof BinaryLogicalOperation and nodeFrom.asExpr() = op.getAnOperand() ) + or + nodeFrom = nodeTo.(CapturedArgumentNode).getAnInput() } } @@ -322,6 +335,23 @@ private module Cached { exists(Argument arg | arg.isArgumentOf(c, any(ArgumentPosition pos | pos.isKeyword(_)))) or c.getAnArgument() instanceof CfgNodes::ExprNodes::PairCfgNode + } or + TCapturedArgumentNode(CfgNodes::ExprNodes::CallCfgNode c, LocalVariable v, boolean post) { + exists(Ssa::Definition def | v = def.getSourceVariable() | + SsaImpl::captureFlowIn(c, def, _, _, _) and post = [false, true] + or + SsaImpl::captureFlowOut(c, _, def) and post = false + ) + } or + TCapturedParameterNode(Callable c, LocalVariable v) { + exists(Ssa::Definition def | + v = def.getSourceVariable() and + c = def.getScope() + | + SsaImpl::captureFlowIn(_, _, _, _, def) + or + SsaImpl::captureFlowOut(_, def, _) + ) } class TParameterNode = @@ -353,7 +383,7 @@ private module Cached { or // Flow into phi node from read exists(Ssa::Definition def, Ssa::PhiNode phi, CfgNodes::ExprCfgNode exprFrom | - LocalFlow::localFlowSsaInputFromExpr(exprFrom, def, phi) and + LocalFlow::localFlowSsaInputFromRead(exprFrom, def, phi) and phi = nodeTo.(SsaDefinitionNode).getDefinition() and def = phi.getAnInput() | @@ -364,6 +394,12 @@ private module Cached { ) or FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, true) + or + exists(CapturedArgumentNode arg | + arg = nodeFrom.(CapturedArgumentPostUpdateNode).getPreUpdateNode() and + simpleLocalFlowStep(arg.getAnInput(), nodeTo) and + nodeTo != arg + ) } /** This is the local flow predicate that is exposed. */ @@ -380,6 +416,12 @@ private module Cached { // Simple flow through library code is included in the exposed local // step relation, even though flow is technically inter-procedural FlowSummaryImpl::Private::Steps::summaryThroughStepValue(nodeFrom, nodeTo, _) + or + exists(CapturedArgumentNode arg | + arg = nodeFrom.(CapturedArgumentPostUpdateNode).getPreUpdateNode() and + localFlowStepImpl(arg.getAnInput(), nodeTo) and + nodeTo != arg + ) } /** @@ -401,11 +443,17 @@ private module Cached { or // Flow into phi node from read exists(Ssa::Definition def, Ssa::PhiNode phi, CfgNodes::ExprCfgNode exprFrom | - LocalFlow::localFlowSsaInputFromExpr(exprFrom, def, phi) and + LocalFlow::localFlowSsaInputFromRead(exprFrom, def, phi) and phi = nodeTo.(SsaDefinitionNode).getDefinition() and def = phi.getAnInput() and exprFrom = [nodeFrom.asExpr(), nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr()] ) + or + exists(CapturedArgumentNode arg | + arg = nodeFrom.(CapturedArgumentPostUpdateNode).getPreUpdateNode() and + localFlowStepTypeTracker(arg.getAnInput(), nodeTo) and + nodeTo != arg + ) } private predicate entrySsaDefinition(SsaDefinitionNode n) { @@ -449,6 +497,10 @@ private module Cached { or // Needed for stores in type tracking TypeTrackerSpecific::storeStepIntoSourceNode(_, n, _) + or + n instanceof CapturedParameterNode + or + n instanceof CapturedArgumentPostUpdateNode } cached @@ -539,6 +591,10 @@ predicate nodeIsHidden(Node n) { n instanceof SynthHashSplatParameterNode or n instanceof SynthHashSplatArgumentNode + or + n instanceof TCapturedArgumentNode + or + n instanceof CapturedParameterNode } /** An SSA definition, viewed as a node in a data flow graph. */ @@ -806,6 +862,29 @@ private module ParameterNodes { override string toStringImpl() { result = "parameter " + pos_ + " of " + sc } } + + /** A parameter representing a captured variable. */ + class CapturedParameterNode extends ParameterNodeImpl, TCapturedParameterNode { + private Callable c_; + private LocalVariable v; + + CapturedParameterNode() { this = TCapturedParameterNode(c_, v) } + + override Parameter getParameter() { none() } + + override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { + c.asCallable() = c_ and + pos.isCapturedVariable(v) + } + + override CfgScope getCfgScope() { result = c_ } + + override DataFlowCallable getEnclosingCallable() { result.asCallable() = c_ } + + override Location getLocationImpl() { result = c_.getLocation() } + + override string toStringImpl() { result = "captured parameter " + v + " of " + c_ } + } } import ParameterNodes @@ -931,6 +1010,48 @@ private module ArgumentNodes { override string toStringImpl() { result = "**" } } + + /** + * An implicit argument that represents the value of a captured variable. + */ + class CapturedArgumentNode extends ArgumentNode, NodeImpl, TCapturedArgumentNode { + CfgNodes::ExprNodes::CallCfgNode c; + LocalVariable v; + + CapturedArgumentNode() { this = TCapturedArgumentNode(c, v, false) } + + /** Gets a node that flows into this implicit argument. */ + Node getAnInput() { + exists(Ssa::Definition def, BasicBlock bb, int i | + SsaImpl::captureFlowIn(c, def, bb, i, _) and + def.getSourceVariable() = v + | + def = result.(SsaDefinitionNode).getDefinition() and + def.definesAt(_, bb, i) + or + exists(CfgNodes::ExprCfgNode e | + e = [result, result.(PostUpdateNode).getPreUpdateNode()].asExpr() and + e = bb.getNode(i) and + e = def.getARead() + ) + ) + } + + override CfgScope getCfgScope() { result = c.getScope() } + + override Location getLocationImpl() { result = c.getLocation() } + + override string toStringImpl() { result = "captured argument " + v } + + override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { + call = TCapturedCall(c) and + pos = TCapturedArgumentPosition(v) + } + + override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) { + none() + } + } } import ArgumentNodes @@ -1040,6 +1161,16 @@ private module ReturnNodes { override ReturnKind getKind() { result = rk } } + + /** + * A data-flow node that represents an updated value of a captured variable, + * which is being returned out of the capturing callable. + */ + class CapturedReturnNode extends ReturningNode, SsaDefinitionNode { + CapturedReturnNode() { SsaImpl::captureFlowOut(_, def, _) } + + override CapturedReturnKind getKind() { result.getVariable() = def.getSourceVariable() } + } } import ReturnNodes @@ -1073,17 +1204,26 @@ private module OutNodes { FlowSummaryImpl::Private::summaryOutNode(result, this, kind) } } + + /** + * A data-flow node that reads a value returned implicitly by a callable + * using a captured variable. + */ + class CapturedOutNode extends OutNode, SsaDefinitionNode { + private CfgNodes::ExprNodes::CallCfgNode call; + + CapturedOutNode() { SsaImpl::captureFlowOut(call, _, this.getDefinition()) } + + override CapturedCall getCall(ReturnKind kind) { + result = TCapturedCall(call) and + kind = TCapturedReturnKind(this.getDefinition().getSourceVariable()) + } + } } import OutNodes predicate jumpStep(Node pred, Node succ) { - SsaImpl::captureFlowIn(_, pred.(SsaDefinitionNode).getDefinition(), - succ.(SsaDefinitionNode).getDefinition()) - or - SsaImpl::captureFlowOut(_, pred.(SsaDefinitionNode).getDefinition(), - succ.(SsaDefinitionNode).getDefinition()) - or succ.asExpr().getExpr().(ConstantReadAccess).getValue() = pred.asExpr().getExpr() or FlowSummaryImpl::Private::Steps::summaryJumpStep(pred, succ) @@ -1275,6 +1415,25 @@ private module PostUpdateNodes { override Node getPreUpdateNode() { result = pre } } + + /** + * A post-update node for an implicit argument that represents the value of a + * captured variable. + */ + class CapturedArgumentPostUpdateNode extends NodeImpl, PostUpdateNodeImpl, TCapturedArgumentNode { + CfgNodes::ExprNodes::CallCfgNode c; + LocalVariable v; + + CapturedArgumentPostUpdateNode() { this = TCapturedArgumentNode(c, v, true) } + + override CfgScope getCfgScope() { result = c.getScope() } + + override Location getLocationImpl() { result = c.getLocation() } + + override string toStringImpl() { result = "[post] captured argument " + v } + + override CapturedArgumentNode getPreUpdateNode() { result = TCapturedArgumentNode(c, v, false) } + } } private import PostUpdateNodes diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll index c2123089251f..dbadd57edc58 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll @@ -661,7 +661,7 @@ module BarrierGuard { | def.getARead() = testedNode and guardChecks(g, testedNode, branch) and - SsaImpl::captureFlowIn(call, def, result) and + SsaImpl::captureFlowIn(call, def, _, _, result) and guardControlsBlock(g, call.getBasicBlock(), branch) and result.getBasicBlock().getScope() = call.getExpr().(MethodCall).getBlock() ) @@ -726,7 +726,7 @@ abstract deprecated class BarrierGuard extends CfgNodes::ExprCfgNode { | def.getARead() = testedNode and this.checks(testedNode, branch) and - SsaImpl::captureFlowIn(call, def, result) and + SsaImpl::captureFlowIn(call, def, _, _, result) and this.controlsBlock(call.getBasicBlock(), branch) and result.getBasicBlock().getScope() = call.getExpr().(MethodCall).getBlock() ) diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImpl.qll index 2f3b1e085b09..56ece27c0185 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImpl.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImpl.qll @@ -89,9 +89,9 @@ predicate uninitializedWrite(Cfg::EntryBasicBlock bb, int i, LocalVariable v) { /** Holds if `bb` contains a captured read of variable `v`. */ pragma[noinline] private predicate hasCapturedVariableRead(Cfg::BasicBlock bb, LocalVariable v) { - exists(LocalVariableReadAccess read | - read = bb.getANode().getNode() and - read.isCapturedAccess() and + exists(LocalVariableReadAccessCfgNode read | + read = bb.getANode() and + read.getExpr().isCapturedAccess() and read.getVariable() = v ) } @@ -99,9 +99,9 @@ private predicate hasCapturedVariableRead(Cfg::BasicBlock bb, LocalVariable v) { /** Holds if `bb` contains a captured write to variable `v`. */ pragma[noinline] private predicate writesCapturedVariable(Cfg::BasicBlock bb, LocalVariable v) { - exists(LocalVariableWriteAccess write | - write = bb.getANode().getNode() and - write.isCapturedAccess() and + exists(LocalVariableWriteAccessCfgNode write | + write = bb.getANode() and + write.getExpr().isCapturedAccess() and write.getVariable() = v ) } @@ -133,13 +133,16 @@ private predicate namespaceSelfExitRead(Cfg::AnnotatedExitBasicBlock bb, int i, /** * Holds if captured variable `v` is read directly inside `scope`, + * Holds if captured variable `v` is read at `read` directly inside `scope`, * or inside a (transitively) nested scope of `scope`. */ pragma[noinline] -private predicate hasCapturedRead(Variable v, Cfg::CfgScope scope) { - any(LocalVariableReadAccess read | - read.getVariable() = v and scope = read.getCfgScope().getOuterCfgScope*() - ).isCapturedAccess() +private predicate isCapturedRead( + LocalVariableReadAccessCfgNode read, Variable v, Cfg::CfgScope scope +) { + read.getVariable() = v and + scope = read.getScope().getOuterCfgScope*() and + read.getExpr().isCapturedAccess() } /** @@ -153,11 +156,13 @@ private predicate variableWriteInOuterScope(Cfg::BasicBlock bb, LocalVariable v, } pragma[noinline] -private predicate hasVariableWriteWithCapturedRead( +private predicate proceedsVariableWriteWithCapturedRead( Cfg::BasicBlock bb, LocalVariable v, Cfg::CfgScope scope ) { - hasCapturedRead(v, scope) and + isCapturedRead(_, v, scope) and variableWriteInOuterScope(bb, v, scope) + or + proceedsVariableWriteWithCapturedRead(bb.getAPredecessor(), v, scope) } /** @@ -166,7 +171,7 @@ private predicate hasVariableWriteWithCapturedRead( */ private predicate capturedCallRead(CallCfgNode call, Cfg::BasicBlock bb, int i, LocalVariable v) { exists(Cfg::CfgScope scope | - hasVariableWriteWithCapturedRead(bb.getAPredecessor*(), v, scope) and + proceedsVariableWriteWithCapturedRead(bb, v, scope) and call = bb.getNode(i) | // If the read happens inside a block, we restrict to the call that @@ -191,9 +196,9 @@ private predicate variableReadActual(Cfg::BasicBlock bb, int i, LocalVariable v) */ pragma[noinline] private predicate hasCapturedWrite(Variable v, Cfg::CfgScope scope) { - any(LocalVariableWriteAccess write | - write.getVariable() = v and scope = write.getCfgScope().getOuterCfgScope*() - ).isCapturedAccess() + any(LocalVariableWriteAccessCfgNode write | + write.getVariable() = v and scope = write.getScope().getOuterCfgScope*() + ).getExpr().isCapturedAccess() } /** @@ -327,19 +332,46 @@ private module Cached { ) } - pragma[noinline] - private predicate defReachesCallReadInOuterScope( - Definition def, CallCfgNode call, LocalVariable v, Cfg::CfgScope scope + /** + * Holds if `def` is accessed at index `i` in basic block `bb`, and this access + * is the call `call`, which may ultimately invoke a capturing method that reads + * from the underlying variable. + * + * `scope` is a CFG scope that has the CFG scope of `bb` as its outer scope. + */ + pragma[nomagic] + private predicate hasCapturedExitReadInOuterScope( + CallCfgNode call, Definition def, Cfg::BasicBlock bb, int i, LocalVariable v, + Cfg::CfgScope scope ) { - exists(Cfg::BasicBlock bb, int i | - Impl::ssaDefReachesRead(v, def, bb, i) and - capturedCallRead(call, bb, i, v) and - scope.getOuterCfgScope() = bb.getScope() + capturedCallRead(call, pragma[only_bind_into](bb), pragma[only_bind_into](i), + pragma[only_bind_into](v)) and + Impl::ssaDefReachesRead(v, def, bb, i) and + scope.getOuterCfgScope() = bb.getScope() + } + + /** + * Holds if `def` is accessed at index `i` in basic block `bb`, and this access + * can reach `call` while only going through uncertain reads. + * + * `scope` is a CFG scope that has the CFG scope of `bb` as its outer scope. + */ + pragma[nomagic] + private predicate refReachesCapturedExitReadInOuterScope( + Definition def, Cfg::BasicBlock bb, int i, CallCfgNode call, LocalVariable v, + Cfg::CfgScope scope + ) { + hasCapturedExitReadInOuterScope(call, def, bb, i, v, scope) + or + exists(Cfg::BasicBlock bb0, int i0 | + refReachesCapturedExitReadInOuterScope(def, bb0, i0, call, v, scope) and + Impl::adjacentDefRead(def, bb, i, bb0, i0) and + SsaInput::variableRead(bb0, i0, v, false) ) } pragma[noinline] - private predicate hasCapturedEntryWrite(Definition entry, LocalVariable v, Cfg::CfgScope scope) { + private predicate hasCapturedEntryDef(Definition entry, LocalVariable v, Cfg::CfgScope scope) { exists(Cfg::BasicBlock bb, int i | capturedEntryWrite(bb, i, v) and entry.definesAt(v, bb, i) and @@ -348,19 +380,32 @@ private module Cached { } /** - * Holds if there is flow for a captured variable from the enclosing scope into a block. + * Holds if `def` is accessed at index `i` in basic block `bb`, and this access + * can reach `call`, which may ultimately invoke a capturing method that reads + * from the underlying variable. + * + * `entry` is the entry definition of the captued variable inside the capturing + * method. + * + * For example, in * ```rb * foo = 0 * bar { * puts foo * } * ``` + * + * the access to `foo` in `foo = 0` can reach the call to `bar`, which may invoke + * the passed in block, which in turn reads the captured variable. */ cached - predicate captureFlowIn(CallCfgNode call, Definition def, Definition entry) { + predicate captureFlowIn( + CallCfgNode call, Definition def, Cfg::BasicBlock bb, int i, Definition entry + ) { exists(LocalVariable v, Cfg::CfgScope scope | - defReachesCallReadInOuterScope(def, call, v, scope) and - hasCapturedEntryWrite(entry, v, scope) + refReachesCapturedExitReadInOuterScope(def, bb, i, call, v, scope) and + not SsaInput::variableRead(bb, i, v, false) and + hasCapturedEntryDef(entry, v, scope) | // If the read happens inside a block, we restrict to the call that // contains the block @@ -379,12 +424,13 @@ private module Cached { exists(Cfg::BasicBlock bb, int i | Impl::ssaDefReachesRead(v, def, bb, i) and capturedExitRead(bb, i, v) and - scope = bb.getScope().getOuterCfgScope*() + scope = bb.getScope().getOuterCfgScope*() and + not def instanceof Ssa::CapturedEntryDefinition ) } pragma[noinline] - private predicate hasCapturedExitRead( + private predicate hasCapturedExitDef( Definition exit, CallCfgNode call, LocalVariable v, Cfg::CfgScope scope ) { exists(Cfg::BasicBlock bb, int i | @@ -395,7 +441,12 @@ private module Cached { } /** - * Holds if there is outgoing flow for a captured variable that is updated in a block. + * Holds if `def` is updating a captured variable inside some method `m`, and + * `call` may ultimately invoke `m`. + * + * `exit` is a definition representing the potential updated value at the call. + * + * For example, in * ```rb * foo = 0 * bar { @@ -403,12 +454,14 @@ private module Cached { * } * puts foo * ``` + * + * The update `foo += 10` inside the block may be invoked via the call to `bar`. */ cached predicate captureFlowOut(CallCfgNode call, Definition def, Definition exit) { exists(LocalVariable v, Cfg::CfgScope scope | defReachesExitReadInInnerScope(def, v, scope) and - hasCapturedExitRead(exit, call, v, _) + hasCapturedExitDef(exit, call, v, scope) | // If the read happens inside a block, we restrict to the call that // contains the block diff --git a/ruby/ql/lib/codeql/ruby/regexp/internal/DebugRegExpConfiguration.ql b/ruby/ql/lib/codeql/ruby/regexp/internal/DebugRegExpConfiguration.ql index a61ca712eb41..948483d9a39a 100644 --- a/ruby/ql/lib/codeql/ruby/regexp/internal/DebugRegExpConfiguration.ql +++ b/ruby/ql/lib/codeql/ruby/regexp/internal/DebugRegExpConfiguration.ql @@ -7,6 +7,8 @@ import RegExpConfiguration import codeql.ruby.dataflow.internal.DataFlowImplForRegExp import PathGraph +predicate stats = stageStats/8; + from RegExpConfiguration c, PathNode source, PathNode sink where c.hasFlowPath(source, sink) select source.getNode(), source, sink, source.toString() diff --git a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll index 1c636c6987fa..c926c1b780a3 100644 --- a/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll +++ b/ruby/ql/lib/codeql/ruby/typetracking/TypeTrackerSpecific.qll @@ -89,9 +89,10 @@ private predicate flowThrough(DataFlowPublic::ParameterNode param) { /** Holds if there is a level step from `nodeFrom` to `nodeTo`, which may depend on the call graph. */ pragma[nomagic] predicate levelStepCall(Node nodeFrom, Node nodeTo) { - exists(DataFlowPublic::ParameterNode param | + exists(DataFlowPublic::ParameterNode param, DataFlowDispatch::DataFlowCall call | flowThrough(param) and - callStep(nodeTo.asExpr(), nodeFrom, param) + callStep(call, nodeFrom, param) and + nodeTo.asExpr() = call.asCall() ) } @@ -169,29 +170,38 @@ private predicate localFieldStep(Node pred, Node succ) { pragma[noinline] private predicate argumentPositionMatch( - ExprNodes::CallCfgNode call, DataFlowPrivate::ArgumentNode arg, + DataFlowDispatch::DataFlowCall call, DataFlowPrivate::ArgumentNode arg, DataFlowDispatch::ParameterPosition ppos ) { exists(DataFlowDispatch::ArgumentPosition apos | - arg.sourceArgumentOf(call, apos) and + arg.argumentOf(call, apos) and DataFlowDispatch::parameterMatch(ppos, apos) ) } +pragma[noinline] +private Cfg::CfgScope getTarget(DataFlowDispatch::DataFlowCall call) { + result = DataFlowDispatch::getTarget(call.asCall()) + or + result = call.(DataFlowDispatch::CapturedCall).getATarget() +} + pragma[noinline] private predicate viableParam( - ExprNodes::CallCfgNode call, DataFlowPrivate::ParameterNodeImpl p, + DataFlowDispatch::DataFlowCall call, DataFlowPrivate::ParameterNodeImpl p, DataFlowDispatch::ParameterPosition ppos ) { exists(Cfg::CfgScope callable | - DataFlowDispatch::getTarget(call) = callable and - p.isSourceParameterOf(callable, ppos) + p.isSourceParameterOf(callable, ppos) and + callable = getTarget(call) ) } /** Holds if there is flow from `arg` to `p` via the call `call`. */ pragma[nomagic] -predicate callStep(ExprNodes::CallCfgNode call, Node arg, DataFlowPrivate::ParameterNodeImpl p) { +predicate callStep( + DataFlowDispatch::DataFlowCall call, Node arg, DataFlowPrivate::ParameterNodeImpl p +) { exists(DataFlowDispatch::ParameterPosition pos | argumentPositionMatch(call, arg, pos) and viableParam(call, p, pos) @@ -223,10 +233,12 @@ predicate callStep(Node nodeFrom, Node nodeTo) { * methods is done using API graphs (which uses type tracking). */ predicate returnStep(Node nodeFrom, Node nodeTo) { - exists(ExprNodes::CallCfgNode call | - nodeFrom instanceof DataFlowPrivate::ReturnNode and - nodeFrom.(DataFlowPrivate::NodeImpl).getCfgScope() = DataFlowDispatch::getTarget(call) and - nodeTo.asExpr().getNode() = call.getNode() + exists(DataFlowDispatch::DataFlowCall call | + nodeFrom = + any(DataFlowPrivate::SynthReturnNode ret | + ret.getCfgScope() = getTarget(call) and + nodeTo = DataFlowDispatch::getAnOutNode(call, ret.getKind()) + ) ) or // In normal data-flow, this will be a local flow step. But for type tracking @@ -510,9 +522,10 @@ bindingset[call, component] private DataFlow::Node evaluateSummaryComponentLocal( DataFlow::CallNode call, SummaryComponent component ) { - exists(DataFlowDispatch::ParameterPosition pos | + exists(DataFlowDispatch::ParameterPosition pos, DataFlowDispatch::DataFlowCall call0 | component = SummaryComponent::argument(pos) and - argumentPositionMatch(call.asExpr(), result, pos) + argumentPositionMatch(call0, result, pos) and + call.asExpr() = call0.asCall() ) or component = SummaryComponent::return() and diff --git a/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.expected b/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.expected index 399a65de5256..c2052018587d 100644 --- a/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/array-flow/array-flow.expected @@ -710,12 +710,10 @@ edges | array_flow.rb:399:10:399:10 | b [element 2] : | array_flow.rb:399:10:399:13 | ...[...] | | array_flow.rb:403:16:403:25 | call to source : | array_flow.rb:404:18:404:18 | a [element 2] : | | array_flow.rb:403:16:403:25 | call to source : | array_flow.rb:404:18:404:18 | a [element 2] : | -| array_flow.rb:404:9:406:7 | ... = ... : | array_flow.rb:407:10:407:10 | x | -| array_flow.rb:404:9:406:7 | ... = ... : | array_flow.rb:407:10:407:10 | x | +| array_flow.rb:404:9:406:7 | ... = ... : | array_flow.rb:405:14:405:14 | x | +| array_flow.rb:404:9:406:7 | ... = ... : | array_flow.rb:405:14:405:14 | x | | array_flow.rb:404:9:406:7 | __synth__0__1 : | array_flow.rb:404:9:406:7 | ... = ... : | | array_flow.rb:404:9:406:7 | __synth__0__1 : | array_flow.rb:404:9:406:7 | ... = ... : | -| array_flow.rb:404:9:406:7 | __synth__0__1 : | array_flow.rb:405:14:405:14 | x | -| array_flow.rb:404:9:406:7 | __synth__0__1 : | array_flow.rb:405:14:405:14 | x | | array_flow.rb:404:18:404:18 | a [element 2] : | array_flow.rb:404:9:406:7 | __synth__0__1 : | | array_flow.rb:404:18:404:18 | a [element 2] : | array_flow.rb:404:9:406:7 | __synth__0__1 : | | array_flow.rb:404:18:404:18 | a [element 2] : | array_flow.rb:408:10:408:10 | b [element 2] : | @@ -4238,8 +4236,6 @@ nodes | array_flow.rb:404:18:404:18 | a [element 2] : | semmle.label | a [element 2] : | | array_flow.rb:405:14:405:14 | x | semmle.label | x | | array_flow.rb:405:14:405:14 | x | semmle.label | x | -| array_flow.rb:407:10:407:10 | x | semmle.label | x | -| array_flow.rb:407:10:407:10 | x | semmle.label | x | | array_flow.rb:408:10:408:10 | b [element 2] : | semmle.label | b [element 2] : | | array_flow.rb:408:10:408:10 | b [element 2] : | semmle.label | b [element 2] : | | array_flow.rb:408:10:408:13 | ...[...] | semmle.label | ...[...] | @@ -7254,7 +7250,6 @@ subpaths | array_flow.rb:397:14:397:14 | x | array_flow.rb:395:16:395:25 | call to source : | array_flow.rb:397:14:397:14 | x | $@ | array_flow.rb:395:16:395:25 | call to source : | call to source : | | array_flow.rb:399:10:399:13 | ...[...] | array_flow.rb:395:16:395:25 | call to source : | array_flow.rb:399:10:399:13 | ...[...] | $@ | array_flow.rb:395:16:395:25 | call to source : | call to source : | | array_flow.rb:405:14:405:14 | x | array_flow.rb:403:16:403:25 | call to source : | array_flow.rb:405:14:405:14 | x | $@ | array_flow.rb:403:16:403:25 | call to source : | call to source : | -| array_flow.rb:407:10:407:10 | x | array_flow.rb:403:16:403:25 | call to source : | array_flow.rb:407:10:407:10 | x | $@ | array_flow.rb:403:16:403:25 | call to source : | call to source : | | array_flow.rb:408:10:408:13 | ...[...] | array_flow.rb:403:16:403:25 | call to source : | array_flow.rb:408:10:408:13 | ...[...] | $@ | array_flow.rb:403:16:403:25 | call to source : | call to source : | | array_flow.rb:414:14:414:19 | ( ... ) | array_flow.rb:412:16:412:25 | call to source : | array_flow.rb:414:14:414:19 | ( ... ) | $@ | array_flow.rb:412:16:412:25 | call to source : | call to source : | | array_flow.rb:421:14:421:14 | x | array_flow.rb:419:16:419:25 | call to source : | array_flow.rb:421:14:421:14 | x | $@ | array_flow.rb:419:16:419:25 | call to source : | call to source : | diff --git a/ruby/ql/test/library-tests/dataflow/array-flow/array_flow.rb b/ruby/ql/test/library-tests/dataflow/array-flow/array_flow.rb index 9600b64eaa3e..c82e74a65f25 100644 --- a/ruby/ql/test/library-tests/dataflow/array-flow/array_flow.rb +++ b/ruby/ql/test/library-tests/dataflow/array-flow/array_flow.rb @@ -404,7 +404,7 @@ def m45 b = for x in a # desugars to an `each` call sink x # $ hasValueFlow=45 end - sink x # $ hasValueFlow=45 + sink x # $ MISSING: hasValueFlow=45 sink(b[2]) # $ hasValueFlow=45 end diff --git a/ruby/ql/test/library-tests/dataflow/array-flow/type-tracking-array-flow.expected b/ruby/ql/test/library-tests/dataflow/array-flow/type-tracking-array-flow.expected index d92fb3132b17..bee342f11f11 100644 --- a/ruby/ql/test/library-tests/dataflow/array-flow/type-tracking-array-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/array-flow/type-tracking-array-flow.expected @@ -13,7 +13,6 @@ | array_flow.rb:376:10:376:13 | ...[...] | Unexpected result: hasValueFlow=42.3 | | array_flow.rb:377:10:377:13 | ...[...] | Unexpected result: hasValueFlow=42.3 | | array_flow.rb:378:10:378:13 | ...[...] | Unexpected result: hasValueFlow=42.3 | -| array_flow.rb:407:12:407:30 | # $ hasValueFlow=45 | Missing result:hasValueFlow=45 | | array_flow.rb:484:10:484:13 | ...[...] | Unexpected result: hasValueFlow=54.3 | | array_flow.rb:484:10:484:13 | ...[...] | Unexpected result: hasValueFlow=54.4 | | array_flow.rb:484:10:484:13 | ...[...] | Unexpected result: hasValueFlow=54.5 | diff --git a/ruby/ql/test/library-tests/dataflow/capture-flow/CaptureFlow.expected b/ruby/ql/test/library-tests/dataflow/capture-flow/CaptureFlow.expected new file mode 100644 index 000000000000..91fd1c5f1db8 --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/capture-flow/CaptureFlow.expected @@ -0,0 +1,119 @@ +failures +edges +| capture_flow.rb:9:5:9:12 | call to taint : | capture_flow.rb:11:10:11:10 | x | +| capture_flow.rb:9:5:9:12 | call to taint : | capture_flow.rb:11:10:11:10 | x | +| capture_flow.rb:12:5:12:16 | ... = ... : | capture_flow.rb:15:6:15:6 | x | +| capture_flow.rb:12:5:12:16 | ... = ... : | capture_flow.rb:15:6:15:6 | x | +| capture_flow.rb:12:9:12:16 | call to taint : | capture_flow.rb:12:5:12:16 | ... = ... : | +| capture_flow.rb:12:9:12:16 | call to taint : | capture_flow.rb:12:5:12:16 | ... = ... : | +| capture_flow.rb:18:19:18:19 | x : | capture_flow.rb:19:18:19:18 | x : | +| capture_flow.rb:18:19:18:19 | x : | capture_flow.rb:19:18:19:18 | x : | +| capture_flow.rb:19:18:19:18 | x : | capture_flow.rb:19:9:19:14 | [post] self [@field] : | +| capture_flow.rb:19:18:19:18 | x : | capture_flow.rb:19:9:19:14 | [post] self [@field] : | +| capture_flow.rb:21:5:23:7 | self in get_field [@field] : | capture_flow.rb:22:16:22:21 | self [@field] : | +| capture_flow.rb:21:5:23:7 | self in get_field [@field] : | capture_flow.rb:22:16:22:21 | self [@field] : | +| capture_flow.rb:22:16:22:21 | @field : | capture_flow.rb:22:9:22:21 | return : | +| capture_flow.rb:22:16:22:21 | @field : | capture_flow.rb:22:9:22:21 | return : | +| capture_flow.rb:22:16:22:21 | self [@field] : | capture_flow.rb:22:16:22:21 | @field : | +| capture_flow.rb:22:16:22:21 | self [@field] : | capture_flow.rb:22:16:22:21 | @field : | +| capture_flow.rb:27:1:27:3 | [post] foo [@field] : | capture_flow.rb:29:10:29:12 | foo [@field] : | +| capture_flow.rb:27:1:27:3 | [post] foo [@field] : | capture_flow.rb:29:10:29:12 | foo [@field] : | +| capture_flow.rb:27:1:27:3 | [post] foo [@field] : | capture_flow.rb:33:6:33:8 | foo [@field] : | +| capture_flow.rb:27:1:27:3 | [post] foo [@field] : | capture_flow.rb:33:6:33:8 | foo [@field] : | +| capture_flow.rb:27:15:27:22 | call to taint : | capture_flow.rb:18:19:18:19 | x : | +| capture_flow.rb:27:15:27:22 | call to taint : | capture_flow.rb:18:19:18:19 | x : | +| capture_flow.rb:27:15:27:22 | call to taint : | capture_flow.rb:27:1:27:3 | [post] foo [@field] : | +| capture_flow.rb:27:15:27:22 | call to taint : | capture_flow.rb:27:1:27:3 | [post] foo [@field] : | +| capture_flow.rb:29:10:29:12 | foo [@field] : | capture_flow.rb:21:5:23:7 | self in get_field [@field] : | +| capture_flow.rb:29:10:29:12 | foo [@field] : | capture_flow.rb:21:5:23:7 | self in get_field [@field] : | +| capture_flow.rb:29:10:29:12 | foo [@field] : | capture_flow.rb:29:10:29:22 | call to get_field | +| capture_flow.rb:29:10:29:12 | foo [@field] : | capture_flow.rb:29:10:29:22 | call to get_field | +| capture_flow.rb:30:5:30:7 | [post] foo [@field] : | capture_flow.rb:33:6:33:8 | foo [@field] : | +| capture_flow.rb:30:5:30:7 | [post] foo [@field] : | capture_flow.rb:33:6:33:8 | foo [@field] : | +| capture_flow.rb:30:19:30:26 | call to taint : | capture_flow.rb:18:19:18:19 | x : | +| capture_flow.rb:30:19:30:26 | call to taint : | capture_flow.rb:18:19:18:19 | x : | +| capture_flow.rb:30:19:30:26 | call to taint : | capture_flow.rb:30:5:30:7 | [post] foo [@field] : | +| capture_flow.rb:30:19:30:26 | call to taint : | capture_flow.rb:30:5:30:7 | [post] foo [@field] : | +| capture_flow.rb:33:6:33:8 | foo [@field] : | capture_flow.rb:21:5:23:7 | self in get_field [@field] : | +| capture_flow.rb:33:6:33:8 | foo [@field] : | capture_flow.rb:21:5:23:7 | self in get_field [@field] : | +| capture_flow.rb:33:6:33:8 | foo [@field] : | capture_flow.rb:33:6:33:18 | call to get_field | +| capture_flow.rb:33:6:33:8 | foo [@field] : | capture_flow.rb:33:6:33:18 | call to get_field | +| capture_flow.rb:40:9:40:11 | [post] foo [@field] : | capture_flow.rb:44:6:44:8 | foo [@field] : | +| capture_flow.rb:40:9:40:11 | [post] foo [@field] : | capture_flow.rb:44:6:44:8 | foo [@field] : | +| capture_flow.rb:40:23:40:30 | call to taint : | capture_flow.rb:18:19:18:19 | x : | +| capture_flow.rb:40:23:40:30 | call to taint : | capture_flow.rb:18:19:18:19 | x : | +| capture_flow.rb:40:23:40:30 | call to taint : | capture_flow.rb:40:9:40:11 | [post] foo [@field] : | +| capture_flow.rb:40:23:40:30 | call to taint : | capture_flow.rb:40:9:40:11 | [post] foo [@field] : | +| capture_flow.rb:44:6:44:8 | foo [@field] : | capture_flow.rb:21:5:23:7 | self in get_field [@field] : | +| capture_flow.rb:44:6:44:8 | foo [@field] : | capture_flow.rb:21:5:23:7 | self in get_field [@field] : | +| capture_flow.rb:44:6:44:8 | foo [@field] : | capture_flow.rb:44:6:44:18 | call to get_field | +| capture_flow.rb:44:6:44:8 | foo [@field] : | capture_flow.rb:44:6:44:18 | call to get_field | +nodes +| capture_flow.rb:9:5:9:12 | call to taint : | semmle.label | call to taint : | +| capture_flow.rb:9:5:9:12 | call to taint : | semmle.label | call to taint : | +| capture_flow.rb:11:10:11:10 | x | semmle.label | x | +| capture_flow.rb:11:10:11:10 | x | semmle.label | x | +| capture_flow.rb:12:5:12:16 | ... = ... : | semmle.label | ... = ... : | +| capture_flow.rb:12:5:12:16 | ... = ... : | semmle.label | ... = ... : | +| capture_flow.rb:12:9:12:16 | call to taint : | semmle.label | call to taint : | +| capture_flow.rb:12:9:12:16 | call to taint : | semmle.label | call to taint : | +| capture_flow.rb:15:6:15:6 | x | semmle.label | x | +| capture_flow.rb:15:6:15:6 | x | semmle.label | x | +| capture_flow.rb:18:19:18:19 | x : | semmle.label | x : | +| capture_flow.rb:18:19:18:19 | x : | semmle.label | x : | +| capture_flow.rb:19:9:19:14 | [post] self [@field] : | semmle.label | [post] self [@field] : | +| capture_flow.rb:19:9:19:14 | [post] self [@field] : | semmle.label | [post] self [@field] : | +| capture_flow.rb:19:18:19:18 | x : | semmle.label | x : | +| capture_flow.rb:19:18:19:18 | x : | semmle.label | x : | +| capture_flow.rb:21:5:23:7 | self in get_field [@field] : | semmle.label | self in get_field [@field] : | +| capture_flow.rb:21:5:23:7 | self in get_field [@field] : | semmle.label | self in get_field [@field] : | +| capture_flow.rb:22:9:22:21 | return : | semmle.label | return : | +| capture_flow.rb:22:9:22:21 | return : | semmle.label | return : | +| capture_flow.rb:22:16:22:21 | @field : | semmle.label | @field : | +| capture_flow.rb:22:16:22:21 | @field : | semmle.label | @field : | +| capture_flow.rb:22:16:22:21 | self [@field] : | semmle.label | self [@field] : | +| capture_flow.rb:22:16:22:21 | self [@field] : | semmle.label | self [@field] : | +| capture_flow.rb:27:1:27:3 | [post] foo [@field] : | semmle.label | [post] foo [@field] : | +| capture_flow.rb:27:1:27:3 | [post] foo [@field] : | semmle.label | [post] foo [@field] : | +| capture_flow.rb:27:15:27:22 | call to taint : | semmle.label | call to taint : | +| capture_flow.rb:27:15:27:22 | call to taint : | semmle.label | call to taint : | +| capture_flow.rb:29:10:29:12 | foo [@field] : | semmle.label | foo [@field] : | +| capture_flow.rb:29:10:29:12 | foo [@field] : | semmle.label | foo [@field] : | +| capture_flow.rb:29:10:29:22 | call to get_field | semmle.label | call to get_field | +| capture_flow.rb:29:10:29:22 | call to get_field | semmle.label | call to get_field | +| capture_flow.rb:30:5:30:7 | [post] foo [@field] : | semmle.label | [post] foo [@field] : | +| capture_flow.rb:30:5:30:7 | [post] foo [@field] : | semmle.label | [post] foo [@field] : | +| capture_flow.rb:30:19:30:26 | call to taint : | semmle.label | call to taint : | +| capture_flow.rb:30:19:30:26 | call to taint : | semmle.label | call to taint : | +| capture_flow.rb:33:6:33:8 | foo [@field] : | semmle.label | foo [@field] : | +| capture_flow.rb:33:6:33:8 | foo [@field] : | semmle.label | foo [@field] : | +| capture_flow.rb:33:6:33:18 | call to get_field | semmle.label | call to get_field | +| capture_flow.rb:33:6:33:18 | call to get_field | semmle.label | call to get_field | +| capture_flow.rb:40:9:40:11 | [post] foo [@field] : | semmle.label | [post] foo [@field] : | +| capture_flow.rb:40:9:40:11 | [post] foo [@field] : | semmle.label | [post] foo [@field] : | +| capture_flow.rb:40:23:40:30 | call to taint : | semmle.label | call to taint : | +| capture_flow.rb:40:23:40:30 | call to taint : | semmle.label | call to taint : | +| capture_flow.rb:44:6:44:8 | foo [@field] : | semmle.label | foo [@field] : | +| capture_flow.rb:44:6:44:8 | foo [@field] : | semmle.label | foo [@field] : | +| capture_flow.rb:44:6:44:18 | call to get_field | semmle.label | call to get_field | +| capture_flow.rb:44:6:44:18 | call to get_field | semmle.label | call to get_field | +subpaths +| capture_flow.rb:27:15:27:22 | call to taint : | capture_flow.rb:18:19:18:19 | x : | capture_flow.rb:19:9:19:14 | [post] self [@field] : | capture_flow.rb:27:1:27:3 | [post] foo [@field] : | +| capture_flow.rb:27:15:27:22 | call to taint : | capture_flow.rb:18:19:18:19 | x : | capture_flow.rb:19:9:19:14 | [post] self [@field] : | capture_flow.rb:27:1:27:3 | [post] foo [@field] : | +| capture_flow.rb:29:10:29:12 | foo [@field] : | capture_flow.rb:21:5:23:7 | self in get_field [@field] : | capture_flow.rb:22:9:22:21 | return : | capture_flow.rb:29:10:29:22 | call to get_field | +| capture_flow.rb:29:10:29:12 | foo [@field] : | capture_flow.rb:21:5:23:7 | self in get_field [@field] : | capture_flow.rb:22:9:22:21 | return : | capture_flow.rb:29:10:29:22 | call to get_field | +| capture_flow.rb:30:19:30:26 | call to taint : | capture_flow.rb:18:19:18:19 | x : | capture_flow.rb:19:9:19:14 | [post] self [@field] : | capture_flow.rb:30:5:30:7 | [post] foo [@field] : | +| capture_flow.rb:30:19:30:26 | call to taint : | capture_flow.rb:18:19:18:19 | x : | capture_flow.rb:19:9:19:14 | [post] self [@field] : | capture_flow.rb:30:5:30:7 | [post] foo [@field] : | +| capture_flow.rb:33:6:33:8 | foo [@field] : | capture_flow.rb:21:5:23:7 | self in get_field [@field] : | capture_flow.rb:22:9:22:21 | return : | capture_flow.rb:33:6:33:18 | call to get_field | +| capture_flow.rb:33:6:33:8 | foo [@field] : | capture_flow.rb:21:5:23:7 | self in get_field [@field] : | capture_flow.rb:22:9:22:21 | return : | capture_flow.rb:33:6:33:18 | call to get_field | +| capture_flow.rb:40:23:40:30 | call to taint : | capture_flow.rb:18:19:18:19 | x : | capture_flow.rb:19:9:19:14 | [post] self [@field] : | capture_flow.rb:40:9:40:11 | [post] foo [@field] : | +| capture_flow.rb:40:23:40:30 | call to taint : | capture_flow.rb:18:19:18:19 | x : | capture_flow.rb:19:9:19:14 | [post] self [@field] : | capture_flow.rb:40:9:40:11 | [post] foo [@field] : | +| capture_flow.rb:44:6:44:8 | foo [@field] : | capture_flow.rb:21:5:23:7 | self in get_field [@field] : | capture_flow.rb:22:9:22:21 | return : | capture_flow.rb:44:6:44:18 | call to get_field | +| capture_flow.rb:44:6:44:8 | foo [@field] : | capture_flow.rb:21:5:23:7 | self in get_field [@field] : | capture_flow.rb:22:9:22:21 | return : | capture_flow.rb:44:6:44:18 | call to get_field | +#select +| capture_flow.rb:11:10:11:10 | x | capture_flow.rb:9:5:9:12 | call to taint : | capture_flow.rb:11:10:11:10 | x | $@ | capture_flow.rb:9:5:9:12 | call to taint : | call to taint : | +| capture_flow.rb:15:6:15:6 | x | capture_flow.rb:12:9:12:16 | call to taint : | capture_flow.rb:15:6:15:6 | x | $@ | capture_flow.rb:12:9:12:16 | call to taint : | call to taint : | +| capture_flow.rb:29:10:29:22 | call to get_field | capture_flow.rb:27:15:27:22 | call to taint : | capture_flow.rb:29:10:29:22 | call to get_field | $@ | capture_flow.rb:27:15:27:22 | call to taint : | call to taint : | +| capture_flow.rb:33:6:33:18 | call to get_field | capture_flow.rb:27:15:27:22 | call to taint : | capture_flow.rb:33:6:33:18 | call to get_field | $@ | capture_flow.rb:27:15:27:22 | call to taint : | call to taint : | +| capture_flow.rb:33:6:33:18 | call to get_field | capture_flow.rb:30:19:30:26 | call to taint : | capture_flow.rb:33:6:33:18 | call to get_field | $@ | capture_flow.rb:30:19:30:26 | call to taint : | call to taint : | +| capture_flow.rb:44:6:44:18 | call to get_field | capture_flow.rb:40:23:40:30 | call to taint : | capture_flow.rb:44:6:44:18 | call to get_field | $@ | capture_flow.rb:40:23:40:30 | call to taint : | call to taint : | diff --git a/ruby/ql/test/library-tests/dataflow/capture-flow/CaptureFlow.ql b/ruby/ql/test/library-tests/dataflow/capture-flow/CaptureFlow.ql new file mode 100644 index 000000000000..33825f765c2a --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/capture-flow/CaptureFlow.ql @@ -0,0 +1,12 @@ +/** + * @kind path-problem + */ + +import codeql.ruby.AST +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/capture-flow/capture_flow.rb b/ruby/ql/test/library-tests/dataflow/capture-flow/capture_flow.rb new file mode 100644 index 000000000000..445885cf12c1 --- /dev/null +++ b/ruby/ql/test/library-tests/dataflow/capture-flow/capture_flow.rb @@ -0,0 +1,44 @@ +def taint x + x +end + +def sink x + puts "SINK: #{x}" +end + +x = taint(1) +[1, 2, 3].each do |i| + sink x # $ hasValueFlow=1 $ MISSING: hasValueFlow=2 + x = taint(2) +end + +sink x # $ hasValueFlow=2 + +class Foo + def set_field x + @field = x + end + def get_field + return @field + end +end + +foo = Foo.new +foo.set_field(taint(3)) +[1, 2, 3].each do |i| + sink(foo.get_field) # $ hasValueFlow=3 $ MISSING: hasValueFlow=4 + foo.set_field(taint(4)) +end + +sink(foo.get_field) # $ hasValueFlow=4 $ SPURIOUS: hasValueFlow=3 + +foo = Foo.new +if (rand() < 0) then + foo = Foo.new +else + [1, 2, 3].each do |i| + foo.set_field(taint(5)) + end +end + +sink(foo.get_field) # $ hasValueFlow=5 diff --git a/ruby/ql/test/library-tests/dataflow/local/DataflowStep.expected b/ruby/ql/test/library-tests/dataflow/local/DataflowStep.expected index db3bc7b7296e..515f1d40ef4d 100644 --- a/ruby/ql/test/library-tests/dataflow/local/DataflowStep.expected +++ b/ruby/ql/test/library-tests/dataflow/local/DataflowStep.expected @@ -1,5 +1,6 @@ | local_dataflow.rb:1:1:7:3 | self (foo) | local_dataflow.rb:3:8:3:10 | self | | local_dataflow.rb:1:1:7:3 | self in foo | local_dataflow.rb:1:1:7:3 | self (foo) | +| local_dataflow.rb:1:1:150:3 | self (local_dataflow.rb) | local_dataflow.rb:10:5:13:3 | captured argument self | | local_dataflow.rb:1:1:150:3 | self (local_dataflow.rb) | local_dataflow.rb:49:1:53:3 | self | | local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:1:9:1:9 | a | | local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:2:7:2:7 | a | @@ -26,12 +27,14 @@ | local_dataflow.rb:9:9:9:15 | call to [] | local_dataflow.rb:9:1:9:15 | ... = ... | | local_dataflow.rb:9:9:9:15 | call to [] | local_dataflow.rb:9:1:9:15 | ... = ... | | local_dataflow.rb:10:5:13:3 | ... = ... | local_dataflow.rb:12:5:12:5 | x | -| local_dataflow.rb:10:5:13:3 | self | local_dataflow.rb:11:1:11:2 | self | +| local_dataflow.rb:10:5:13:3 | self | local_dataflow.rb:11:1:11:2 | self | +| local_dataflow.rb:10:5:13:3 | [post] captured argument self | local_dataflow.rb:49:1:53:3 | self | | local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | ... = ... | | local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | ... = ... | | local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | __synth__0__1 | | local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | __synth__0__1 | | local_dataflow.rb:10:5:13:3 | call to each | local_dataflow.rb:10:1:13:3 | ... = ... | +| local_dataflow.rb:10:5:13:3 | captured parameter self of { ... } | local_dataflow.rb:10:5:13:3 | self | | local_dataflow.rb:10:14:10:18 | [post] array | local_dataflow.rb:15:10:15:14 | array | | local_dataflow.rb:10:14:10:18 | array | local_dataflow.rb:15:10:15:14 | array | | local_dataflow.rb:11:1:11:2 | [post] self | local_dataflow.rb:12:3:12:5 | self | @@ -54,6 +57,7 @@ | 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:1:32:25 | ... = ... | local_dataflow.rb:49:1:53:3 | captured argument x | | 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:34:7:34:7 | x | @@ -65,7 +69,8 @@ | local_dataflow.rb:45:10:45:10 | 6 | local_dataflow.rb:45:3:45:10 | return | | local_dataflow.rb:49:1:53:3 | [post] self | local_dataflow.rb:55:1:55:14 | self | | local_dataflow.rb:49:1:53:3 | self | local_dataflow.rb:55:1:55:14 | self | -| local_dataflow.rb:49:3:53:3 | x | local_dataflow.rb:50:18:50:18 | x | +| local_dataflow.rb:49:3:53:3 | x | local_dataflow.rb:50:18:50:18 | x | +| local_dataflow.rb:49:3:53:3 | captured parameter x of do ... end | local_dataflow.rb:49:3:53:3 | x | | local_dataflow.rb:50:8:50:13 | "next" | local_dataflow.rb:50:3:50:13 | next | | local_dataflow.rb:50:18:50:18 | [post] x | local_dataflow.rb:51:20:51:20 | x | | local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:51:20:51:20 | x | @@ -261,10 +266,14 @@ | local_dataflow.rb:117:8:117:16 | [post] self | local_dataflow.rb:118:3:118:11 | self | | local_dataflow.rb:117:8:117:16 | call to source | local_dataflow.rb:117:8:117:23 | call to tap | | local_dataflow.rb:117:8:117:16 | self | local_dataflow.rb:118:3:118:11 | self | +| local_dataflow.rb:118:3:118:11 | [post] self | local_dataflow.rb:118:3:118:31 | captured argument self | | local_dataflow.rb:118:3:118:11 | [post] self | local_dataflow.rb:119:3:119:31 | self | | local_dataflow.rb:118:3:118:11 | call to source | local_dataflow.rb:118:3:118:31 | call to tap | +| local_dataflow.rb:118:3:118:11 | self | local_dataflow.rb:118:3:118:31 | captured argument self | | local_dataflow.rb:118:3:118:11 | self | local_dataflow.rb:119:3:119:31 | self | -| local_dataflow.rb:118:17:118:31 | self | local_dataflow.rb:118:23:118:29 | self | +| local_dataflow.rb:118:3:118:31 | [post] captured argument self | local_dataflow.rb:119:3:119:31 | self | +| local_dataflow.rb:118:17:118:31 | self | local_dataflow.rb:118:23:118:29 | self | +| local_dataflow.rb:118:17:118:31 | captured parameter self of { ... } | local_dataflow.rb:118:17:118:31 | self | | local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:20:118:20 | x | | local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:28:118:28 | x | | local_dataflow.rb:119:3:119:31 | [post] self | local_dataflow.rb:119:8:119:16 | self | @@ -275,10 +284,13 @@ | local_dataflow.rb:122:1:124:3 | self in dup_tap | local_dataflow.rb:122:1:124:3 | self (dup_tap) | | local_dataflow.rb:123:3:123:50 | [post] self | local_dataflow.rb:123:8:123:16 | self | | local_dataflow.rb:123:3:123:50 | self | local_dataflow.rb:123:8:123:16 | self | +| local_dataflow.rb:123:8:123:16 | [post] self | local_dataflow.rb:123:8:123:45 | captured argument self | | local_dataflow.rb:123:8:123:16 | call to source | local_dataflow.rb:123:8:123:20 | call to dup | +| local_dataflow.rb:123:8:123:16 | self | local_dataflow.rb:123:8:123:45 | captured argument self | | local_dataflow.rb:123:8:123:20 | call to dup | local_dataflow.rb:123:8:123:45 | call to tap | | local_dataflow.rb:123:8:123:45 | call to tap | local_dataflow.rb:123:8:123:49 | call to dup | -| local_dataflow.rb:123:26:123:45 | self | local_dataflow.rb:123:32:123:43 | self | +| local_dataflow.rb:123:26:123:45 | self | local_dataflow.rb:123:32:123:43 | self | +| local_dataflow.rb:123:26:123:45 | captured parameter self of { ... } | local_dataflow.rb:123:26:123:45 | self | | local_dataflow.rb:126:1:128:3 | self (use) | local_dataflow.rb:127:3:127:8 | self | | local_dataflow.rb:126:1:128:3 | self in use | local_dataflow.rb:126:1:128:3 | self (use) | | local_dataflow.rb:130:1:150:3 | self (use_use_madness) | local_dataflow.rb:132:6:132:11 | self | diff --git a/ruby/ql/test/library-tests/dataflow/local/Nodes.expected b/ruby/ql/test/library-tests/dataflow/local/Nodes.expected index fcb55f6ada7c..5421defc2048 100644 --- a/ruby/ql/test/library-tests/dataflow/local/Nodes.expected +++ b/ruby/ql/test/library-tests/dataflow/local/Nodes.expected @@ -30,6 +30,7 @@ arg | local_dataflow.rb:9:10:9:10 | 1 | local_dataflow.rb:9:9:9:15 | call to [] | position 0 | | local_dataflow.rb:9:12:9:12 | 2 | local_dataflow.rb:9:9:9:15 | call to [] | position 1 | | local_dataflow.rb:9:14:9:14 | 3 | local_dataflow.rb:9:9:9:15 | call to [] | position 2 | +| local_dataflow.rb:10:5:13:3 | captured argument self | local_dataflow.rb:10:5:13:3 | call to each | captured self | | local_dataflow.rb:10:5:13:3 | { ... } | local_dataflow.rb:10:5:13:3 | call to each | block | | local_dataflow.rb:10:14:10:18 | array | local_dataflow.rb:10:5:13:3 | call to each | self | | local_dataflow.rb:11:1:11:2 | self | local_dataflow.rb:11:1:11:2 | call to do | self | @@ -45,6 +46,7 @@ arg | local_dataflow.rb:35:11:35:11 | 4 | local_dataflow.rb:35:6:35:11 | ... == ... | position 0 | | local_dataflow.rb:42:6:42:6 | x | local_dataflow.rb:42:6:42:11 | ... == ... | self | | local_dataflow.rb:42:11:42:11 | 4 | local_dataflow.rb:42:6:42:11 | ... == ... | position 0 | +| local_dataflow.rb:49:1:53:3 | captured argument x | local_dataflow.rb:49:1:53:3 | call to m | captured x | | local_dataflow.rb:49:1:53:3 | self | local_dataflow.rb:49:1:53:3 | call to m | self | | local_dataflow.rb:49:3:53:3 | do ... end | local_dataflow.rb:49:1:53:3 | call to m | block | | local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:50:18:50:22 | ... < ... | self | @@ -150,6 +152,7 @@ arg | local_dataflow.rb:117:22:117:23 | { ... } | local_dataflow.rb:117:8:117:23 | call to tap | block | | local_dataflow.rb:118:3:118:11 | call to source | local_dataflow.rb:118:3:118:31 | call to tap | self | | local_dataflow.rb:118:3:118:11 | self | local_dataflow.rb:118:3:118:11 | call to source | self | +| local_dataflow.rb:118:3:118:31 | captured argument self | local_dataflow.rb:118:3:118:31 | call to tap | captured self | | local_dataflow.rb:118:10:118:10 | 1 | local_dataflow.rb:118:3:118:11 | call to source | position 0 | | local_dataflow.rb:118:17:118:31 | { ... } | local_dataflow.rb:118:3:118:31 | call to tap | block | | local_dataflow.rb:118:23:118:29 | self | local_dataflow.rb:118:23:118:29 | call to sink | self | @@ -167,6 +170,7 @@ arg | local_dataflow.rb:123:8:123:16 | self | local_dataflow.rb:123:8:123:16 | call to source | self | | local_dataflow.rb:123:8:123:20 | call to dup | local_dataflow.rb:123:8:123:45 | call to tap | self | | local_dataflow.rb:123:8:123:45 | call to tap | local_dataflow.rb:123:8:123:49 | call to dup | self | +| local_dataflow.rb:123:8:123:45 | captured argument self | local_dataflow.rb:123:8:123:45 | call to tap | captured self | | local_dataflow.rb:123:8:123:49 | call to dup | local_dataflow.rb:123:3:123:50 | call to sink | position 0 | | local_dataflow.rb:123:15:123:15 | 1 | local_dataflow.rb:123:8:123:16 | call to source | position 0 | | local_dataflow.rb:123:26:123:45 | { ... } | local_dataflow.rb:123:8:123:45 | call to tap | block | diff --git a/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected b/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected index 34947d0005dc..fb1c7a6228fb 100644 --- a/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected +++ b/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected @@ -28,6 +28,7 @@ | file://:0:0:0:0 | parameter self of each(0) | file://:0:0:0:0 | [summary] read: argument self.any element in each(0) | | local_dataflow.rb:1:1:7:3 | self (foo) | local_dataflow.rb:3:8:3:10 | self | | local_dataflow.rb:1:1:7:3 | self in foo | local_dataflow.rb:1:1:7:3 | self (foo) | +| local_dataflow.rb:1:1:150:3 | self (local_dataflow.rb) | local_dataflow.rb:10:5:13:3 | captured argument self | | local_dataflow.rb:1:1:150:3 | self (local_dataflow.rb) | local_dataflow.rb:49:1:53:3 | self | | local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:1:9:1:9 | a | | local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:2:7:2:7 | a | @@ -57,12 +58,14 @@ | local_dataflow.rb:9:9:9:15 | call to [] | local_dataflow.rb:9:1:9:15 | ... = ... | | local_dataflow.rb:9:9:9:15 | call to [] | local_dataflow.rb:9:1:9:15 | ... = ... | | local_dataflow.rb:10:5:13:3 | ... = ... | local_dataflow.rb:12:5:12:5 | x | -| local_dataflow.rb:10:5:13:3 | self | local_dataflow.rb:11:1:11:2 | self | +| local_dataflow.rb:10:5:13:3 | self | local_dataflow.rb:11:1:11:2 | self | +| local_dataflow.rb:10:5:13:3 | [post] captured argument self | local_dataflow.rb:49:1:53:3 | self | | local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | ... = ... | | local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | ... = ... | | local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | __synth__0__1 | | local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | __synth__0__1 | | local_dataflow.rb:10:5:13:3 | call to each | local_dataflow.rb:10:1:13:3 | ... = ... | +| local_dataflow.rb:10:5:13:3 | captured parameter self of { ... } | local_dataflow.rb:10:5:13:3 | self | | local_dataflow.rb:10:14:10:18 | [post] array | local_dataflow.rb:15:10:15:14 | array | | local_dataflow.rb:10:14:10:18 | array | local_dataflow.rb:15:10:15:14 | array | | local_dataflow.rb:11:1:11:2 | [post] self | local_dataflow.rb:12:3:12:5 | self | @@ -87,6 +90,7 @@ | 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:1:32:25 | ... = ... | local_dataflow.rb:49:1:53:3 | captured argument x | | 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:34:7:34:7 | x | @@ -102,7 +106,8 @@ | local_dataflow.rb:45:10:45:10 | 6 | local_dataflow.rb:45:3:45:10 | return | | local_dataflow.rb:49:1:53:3 | [post] self | local_dataflow.rb:55:1:55:14 | self | | local_dataflow.rb:49:1:53:3 | self | local_dataflow.rb:55:1:55:14 | self | -| local_dataflow.rb:49:3:53:3 | x | local_dataflow.rb:50:18:50:18 | x | +| local_dataflow.rb:49:3:53:3 | x | local_dataflow.rb:50:18:50:18 | x | +| local_dataflow.rb:49:3:53:3 | captured parameter x of do ... end | local_dataflow.rb:49:3:53:3 | x | | local_dataflow.rb:50:8:50:13 | "next" | local_dataflow.rb:50:3:50:13 | next | | local_dataflow.rb:50:18:50:18 | [post] x | local_dataflow.rb:51:20:51:20 | x | | local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:50:18:50:22 | ... < ... | @@ -314,10 +319,14 @@ | local_dataflow.rb:117:8:117:16 | [post] self | local_dataflow.rb:118:3:118:11 | self | | local_dataflow.rb:117:8:117:16 | call to source | local_dataflow.rb:117:8:117:23 | call to tap | | local_dataflow.rb:117:8:117:16 | self | local_dataflow.rb:118:3:118:11 | self | +| local_dataflow.rb:118:3:118:11 | [post] self | local_dataflow.rb:118:3:118:31 | captured argument self | | local_dataflow.rb:118:3:118:11 | [post] self | local_dataflow.rb:119:3:119:31 | self | | local_dataflow.rb:118:3:118:11 | call to source | local_dataflow.rb:118:3:118:31 | call to tap | +| local_dataflow.rb:118:3:118:11 | self | local_dataflow.rb:118:3:118:31 | captured argument self | | local_dataflow.rb:118:3:118:11 | self | local_dataflow.rb:119:3:119:31 | self | -| local_dataflow.rb:118:17:118:31 | self | local_dataflow.rb:118:23:118:29 | self | +| local_dataflow.rb:118:3:118:31 | [post] captured argument self | local_dataflow.rb:119:3:119:31 | self | +| local_dataflow.rb:118:17:118:31 | self | local_dataflow.rb:118:23:118:29 | self | +| local_dataflow.rb:118:17:118:31 | captured parameter self of { ... } | local_dataflow.rb:118:17:118:31 | self | | local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:20:118:20 | x | | local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:28:118:28 | x | | local_dataflow.rb:119:3:119:31 | [post] self | local_dataflow.rb:119:8:119:16 | self | @@ -328,10 +337,13 @@ | local_dataflow.rb:122:1:124:3 | self in dup_tap | local_dataflow.rb:122:1:124:3 | self (dup_tap) | | local_dataflow.rb:123:3:123:50 | [post] self | local_dataflow.rb:123:8:123:16 | self | | local_dataflow.rb:123:3:123:50 | self | local_dataflow.rb:123:8:123:16 | self | +| local_dataflow.rb:123:8:123:16 | [post] self | local_dataflow.rb:123:8:123:45 | captured argument self | | local_dataflow.rb:123:8:123:16 | call to source | local_dataflow.rb:123:8:123:20 | call to dup | +| local_dataflow.rb:123:8:123:16 | self | local_dataflow.rb:123:8:123:45 | captured argument self | | local_dataflow.rb:123:8:123:20 | call to dup | local_dataflow.rb:123:8:123:45 | call to tap | | local_dataflow.rb:123:8:123:45 | call to tap | local_dataflow.rb:123:8:123:49 | call to dup | -| local_dataflow.rb:123:26:123:45 | self | local_dataflow.rb:123:32:123:43 | self | +| local_dataflow.rb:123:26:123:45 | self | local_dataflow.rb:123:32:123:43 | self | +| local_dataflow.rb:123:26:123:45 | captured parameter self of { ... } | local_dataflow.rb:123:26:123:45 | self | | local_dataflow.rb:126:1:128:3 | self (use) | local_dataflow.rb:127:3:127:8 | self | | local_dataflow.rb:126:1:128:3 | self in use | local_dataflow.rb:126:1:128:3 | self (use) | | local_dataflow.rb:130:1:150:3 | self (use_use_madness) | local_dataflow.rb:132:6:132:11 | self | diff --git a/ruby/ql/test/library-tests/dataflow/string-flow/string-flow.expected b/ruby/ql/test/library-tests/dataflow/string-flow/string-flow.expected index 122a1d8eb1f5..55f4038cffbd 100644 --- a/ruby/ql/test/library-tests/dataflow/string-flow/string-flow.expected +++ b/ruby/ql/test/library-tests/dataflow/string-flow/string-flow.expected @@ -201,8 +201,6 @@ edges | string_flow.rb:240:9:240:19 | call to scan [element] : | string_flow.rb:242:10:242:10 | b [element] : | | string_flow.rb:241:10:241:10 | b [element] : | string_flow.rb:241:10:241:13 | ...[...] | | string_flow.rb:242:10:242:10 | b [element] : | string_flow.rb:242:10:242:13 | ...[...] | -| string_flow.rb:246:5:246:18 | ... = ... : | string_flow.rb:250:26:250:26 | a : | -| string_flow.rb:246:9:246:18 | call to source : | string_flow.rb:246:5:246:18 | ... = ... : | | string_flow.rb:246:9:246:18 | call to source : | string_flow.rb:247:10:247:10 | a : | | string_flow.rb:246:9:246:18 | call to source : | string_flow.rb:248:20:248:20 | a : | | string_flow.rb:246:9:246:18 | call to source : | string_flow.rb:249:5:249:5 | a : | @@ -212,15 +210,13 @@ edges | string_flow.rb:248:20:248:20 | a : | string_flow.rb:248:10:248:21 | call to scrub | | string_flow.rb:249:5:249:5 | a : | string_flow.rb:249:16:249:16 | x : | | string_flow.rb:249:16:249:16 | x : | string_flow.rb:249:24:249:24 | x | -| string_flow.rb:250:26:250:26 | a : | string_flow.rb:250:10:250:28 | call to scrub | +| string_flow.rb:250:26:250:35 | call to source : | string_flow.rb:250:10:250:37 | call to scrub | | string_flow.rb:252:10:252:10 | a : | string_flow.rb:252:10:252:22 | call to scrub! | | string_flow.rb:253:21:253:21 | a : | string_flow.rb:253:10:253:22 | call to scrub! | -| string_flow.rb:255:5:255:18 | ... = ... : | string_flow.rb:258:27:258:27 | a : | -| string_flow.rb:255:9:255:18 | call to source : | string_flow.rb:255:5:255:18 | ... = ... : | | string_flow.rb:255:9:255:18 | call to source : | string_flow.rb:256:5:256:5 | a : | | string_flow.rb:256:5:256:5 | a : | string_flow.rb:256:17:256:17 | x : | | string_flow.rb:256:17:256:17 | x : | string_flow.rb:256:25:256:25 | x | -| string_flow.rb:258:27:258:27 | a : | string_flow.rb:258:10:258:29 | call to scrub! | +| string_flow.rb:258:27:258:36 | call to source : | string_flow.rb:258:10:258:38 | call to scrub! | | string_flow.rb:262:9:262:18 | call to source : | string_flow.rb:263:10:263:10 | a : | | string_flow.rb:263:10:263:10 | a : | string_flow.rb:263:10:263:22 | call to shellescape | | string_flow.rb:267:9:267:18 | call to source : | string_flow.rb:268:9:268:9 | a : | @@ -527,7 +523,6 @@ nodes | string_flow.rb:241:10:241:13 | ...[...] | semmle.label | ...[...] | | string_flow.rb:242:10:242:10 | b [element] : | semmle.label | b [element] : | | string_flow.rb:242:10:242:13 | ...[...] | semmle.label | ...[...] | -| string_flow.rb:246:5:246:18 | ... = ... : | semmle.label | ... = ... : | | string_flow.rb:246:9:246:18 | call to source : | semmle.label | call to source : | | string_flow.rb:247:10:247:10 | a : | semmle.label | a : | | string_flow.rb:247:10:247:21 | call to scrub | semmle.label | call to scrub | @@ -536,19 +531,18 @@ nodes | string_flow.rb:249:5:249:5 | a : | semmle.label | a : | | string_flow.rb:249:16:249:16 | x : | semmle.label | x : | | string_flow.rb:249:24:249:24 | x | semmle.label | x | -| string_flow.rb:250:10:250:28 | call to scrub | semmle.label | call to scrub | -| string_flow.rb:250:26:250:26 | a : | semmle.label | a : | +| string_flow.rb:250:10:250:37 | call to scrub | semmle.label | call to scrub | +| string_flow.rb:250:26:250:35 | call to source : | semmle.label | call to source : | | string_flow.rb:252:10:252:10 | a : | semmle.label | a : | | string_flow.rb:252:10:252:22 | call to scrub! | semmle.label | call to scrub! | | string_flow.rb:253:10:253:22 | call to scrub! | semmle.label | call to scrub! | | string_flow.rb:253:21:253:21 | a : | semmle.label | a : | -| string_flow.rb:255:5:255:18 | ... = ... : | semmle.label | ... = ... : | | string_flow.rb:255:9:255:18 | call to source : | semmle.label | call to source : | | string_flow.rb:256:5:256:5 | a : | semmle.label | a : | | string_flow.rb:256:17:256:17 | x : | semmle.label | x : | | string_flow.rb:256:25:256:25 | x | semmle.label | x | -| string_flow.rb:258:10:258:29 | call to scrub! | semmle.label | call to scrub! | -| string_flow.rb:258:27:258:27 | a : | semmle.label | a : | +| string_flow.rb:258:10:258:38 | call to scrub! | semmle.label | call to scrub! | +| string_flow.rb:258:27:258:36 | call to source : | semmle.label | call to source : | | string_flow.rb:262:9:262:18 | call to source : | semmle.label | call to source : | | string_flow.rb:263:10:263:10 | a : | semmle.label | a : | | string_flow.rb:263:10:263:22 | call to shellescape | semmle.label | call to shellescape | diff --git a/ruby/ql/test/library-tests/dataflow/string-flow/string_flow.rb b/ruby/ql/test/library-tests/dataflow/string-flow/string_flow.rb index 3336aaae74bf..6b97c2b80973 100644 --- a/ruby/ql/test/library-tests/dataflow/string-flow/string_flow.rb +++ b/ruby/ql/test/library-tests/dataflow/string-flow/string_flow.rb @@ -247,7 +247,7 @@ def m_scrub sink a.scrub("b") # $ hasTaintFlow=a sink "b".scrub(a) # $ hasTaintFlow=a a.scrub { |x| sink x } # $ hasTaintFlow=a - sink("b".scrub { |x| a }) # $ hasTaintFlow=a + sink("b".scrub { |x| source "a" }) # $ hasTaintFlow=a sink a.scrub!("b") # $ hasTaintFlow=a sink "b".scrub!(a) # $ hasTaintFlow=a @@ -255,7 +255,7 @@ def m_scrub a = source "a" a.scrub! { |x| sink x } # $ hasTaintFlow=a - sink("b".scrub! { |x| a }) # $ hasTaintFlow=a + sink("b".scrub! { |x| source "a" }) # $ hasTaintFlow=a end def m_shellescape diff --git a/ruby/ql/test/library-tests/variables/ssa.expected b/ruby/ql/test/library-tests/variables/ssa.expected index 20133a718574..4ed22f2427c2 100644 --- a/ruby/ql/test/library-tests/variables/ssa.expected +++ b/ruby/ql/test/library-tests/variables/ssa.expected @@ -14,9 +14,9 @@ definition | 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 | self | instance_variables.rb:1:1:44:4 | self | +| instance_variables.rb:27:6:29:1 | self | 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 | self | instance_variables.rb:31:1:33:3 | self | +| instance_variables.rb:32:10:32:21 | self | 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 | @@ -33,8 +33,8 @@ definition | nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | | nested_scopes.rb:17:15:17:19 | ... = ... | nested_scopes.rb:16:29:16:29 | a | -| nested_scopes.rb:18:23:18:36 | a | nested_scopes.rb:16:29:16:29 | a | -| nested_scopes.rb:18:23:18:36 | self | nested_scopes.rb:12:9:21:11 | self | +| nested_scopes.rb:18:23:18:36 | a | nested_scopes.rb:16:29:16:29 | a | +| nested_scopes.rb:18:23:18:36 | self | nested_scopes.rb:12:9:21:11 | self | | nested_scopes.rb:22:9:24:11 | self (show_a2) | nested_scopes.rb:22:9:24:11 | self | | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | | nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self | @@ -42,7 +42,7 @@ definition | nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a | | nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d | | parameters.rb:1:1:62:1 | self (parameters.rb) | parameters.rb:1:1:62:1 | self | -| parameters.rb:1:9:5:3 | self | parameters.rb:1:1:62:1 | self | +| parameters.rb:1:9:5:3 | self | parameters.rb:1:1:62:1 | self | | parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | | parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | | parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self | @@ -50,7 +50,7 @@ definition | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | | parameters.rb:15:1:19:3 | self (print_map) | parameters.rb:15:1:19:3 | self | | parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | -| parameters.rb:16:12:18:5 | self | parameters.rb:15:1:19:3 | self | +| parameters.rb:16:12:18:5 | self | parameters.rb:15:1:19:3 | self | | parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | | parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | | parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | @@ -77,8 +77,8 @@ definition | parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | | parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | | parameters.rb:53:1:53:6 | ... = ... | parameters.rb:53:1:53:1 | x | -| parameters.rb:54:9:57:3 | self | parameters.rb:1:1:62:1 | self | -| parameters.rb:54:9:57:3 | x | parameters.rb:53:1:53:1 | x | +| parameters.rb:54:9:57:3 | self | parameters.rb:1:1:62:1 | self | +| parameters.rb:54:9:57:3 | x | parameters.rb:53:1:53:1 | x | | parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | | parameters.rb:54:19:54:23 | ... = ... | parameters.rb:53:1:53:1 | x | | parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | @@ -87,11 +87,11 @@ definition | parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | | parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | | scopes.rb:1:1:49:4 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | | scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | | scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | -| scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | +| scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | | scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | | scopes.rb:13:4:13:4 | ... = ... | scopes.rb:7:1:7:1 | a | | scopes.rb:13:7:13:7 | ... = ... | scopes.rb:13:7:13:7 | b | @@ -124,11 +124,11 @@ definition | ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | | ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | | ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem | -| ssa.rb:26:3:28:5 | self | ssa.rb:25:1:30:3 | self | +| ssa.rb:26:3:28:5 | self | ssa.rb:25:1:30:3 | self | +| ssa.rb:26:3:28:5 | elem | ssa.rb:26:7:26:10 | elem | | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | -| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem | | ssa.rb:32:1:36:3 | self (m3) | ssa.rb:32:1:36:3 | self | -| ssa.rb:33:16:35:5 | self | ssa.rb:32:1:36:3 | self | +| ssa.rb:33:16:35:5 | self | ssa.rb:32:1:36:3 | self | | ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | | ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | | ssa.rb:40:3:40:9 | ... = ... | ssa.rb:40:3:40:4 | m3 | @@ -150,20 +150,20 @@ definition | ssa.rb:64:1:72:3 | self (m9) | ssa.rb:64:1:72:3 | self | | ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | | ssa.rb:65:3:65:15 | ... = ... | ssa.rb:65:3:65:10 | captured | -| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | -| ssa.rb:66:11:70:5 | captured | ssa.rb:65:3:65:10 | captured | -| ssa.rb:66:11:70:5 | self | ssa.rb:64:1:72:3 | self | +| ssa.rb:66:3:70:5 | captured | ssa.rb:65:3:65:10 | captured | +| ssa.rb:66:11:70:5 | captured | ssa.rb:65:3:65:10 | captured | +| ssa.rb:66:11:70:5 | self | ssa.rb:64:1:72:3 | self | | ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | | ssa.rb:69:5:69:17 | ... = ... | ssa.rb:65:3:65:10 | captured | | ssa.rb:74:1:79:3 | self (m10) | ssa.rb:74:1:79:3 | self | | ssa.rb:75:3:75:14 | ... = ... | ssa.rb:75:3:75:10 | captured | -| ssa.rb:76:7:78:5 | captured | ssa.rb:75:3:75:10 | captured | -| ssa.rb:76:7:78:5 | self | ssa.rb:74:1:79:3 | self | +| ssa.rb:76:7:78:5 | captured | ssa.rb:75:3:75:10 | captured | +| ssa.rb:76:7:78:5 | self | ssa.rb:74:1:79:3 | self | | ssa.rb:81:1:88:3 | self (m11) | ssa.rb:81:1:88:3 | self | | ssa.rb:82:3:82:14 | ... = ... | ssa.rb:82:3:82:10 | captured | -| ssa.rb:83:7:87:5 | self | ssa.rb:81:1:88:3 | self | -| ssa.rb:84:10:86:8 | captured | ssa.rb:82:3:82:10 | captured | -| ssa.rb:84:10:86:8 | self | ssa.rb:81:1:88:3 | self | +| ssa.rb:83:7:87:5 | self | ssa.rb:81:1:88:3 | self | +| ssa.rb:84:10:86:8 | captured | ssa.rb:82:3:82:10 | captured | +| ssa.rb:84:10:86:8 | self | ssa.rb:81:1:88:3 | self | | ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | | ssa.rb:90:9:90:10 | b1 | ssa.rb:90:9:90:10 | b1 | | ssa.rb:90:13:90:14 | b2 | ssa.rb:90:13:90:14 | b2 | @@ -189,8 +189,8 @@ read | 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 | self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self | -| instance_variables.rb:32:10:32:21 | self | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self | +| instance_variables.rb:27:6:29:1 | self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self | +| instance_variables.rb:32:10:32:21 | self | 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 | @@ -212,8 +212,8 @@ read | nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:15:11:15:11 | a | | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:16:13:16:13 | a | | nested_scopes.rb:17:15:17:19 | ... = ... | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:15:18:15 | a | -| nested_scopes.rb:18:23:18:36 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a | -| nested_scopes.rb:18:23:18:36 | self | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self | +| nested_scopes.rb:18:23:18:36 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a | +| nested_scopes.rb:18:23:18:36 | self | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self | | nested_scopes.rb:22:9:24:11 | self (show_a2) | nested_scopes.rb:22:9:24:11 | self | nested_scopes.rb:23:11:23:16 | self | | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:23:16:23:16 | a | | nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self | nested_scopes.rb:28:11:28:16 | self | @@ -221,8 +221,8 @@ read | nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:32:11:32:16 | self | | nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:32:16:32:16 | a | | nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:41:1:41:1 | d | -| parameters.rb:1:9:5:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self | -| parameters.rb:1:9:5:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:4:4:4:9 | self | +| parameters.rb:1:9:5:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self | +| parameters.rb:1:9:5:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:4:4:4:9 | self | | parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:3:9:3:9 | x | | parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y | | parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self | parameters.rb:9:5:9:33 | self | @@ -232,7 +232,7 @@ read | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:11:14:11:19 | pizzas | | parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map | -| parameters.rb:16:12:18:5 | self | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self | +| parameters.rb:16:12:18:5 | self | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self | | parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key | | parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value | | parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block | @@ -256,8 +256,8 @@ read | parameters.rb:49:1:51:3 | self (tuples) | parameters.rb:49:1:51:3 | self | parameters.rb:50:3:50:18 | self | | parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:50:11:50:11 | a | | parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:50:16:50:16 | b | -| parameters.rb:54:9:57:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self | -| parameters.rb:54:9:57:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:56:4:56:9 | self | +| parameters.rb:54:9:57:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self | +| parameters.rb:54:9:57:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:56:4:56:9 | self | | parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:56:9:56:9 | y | | parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:55:9:55:9 | x | | parameters.rb:59:1:61:3 | self (tuples_nested) | parameters.rb:59:1:61:3 | self | parameters.rb:60:3:60:23 | self | @@ -265,19 +265,19 @@ read | parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b | | parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c | | scopes.rb:1:1:49:4 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | scopes.rb:8:1:8:6 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:5:4:5:9 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:5:4:5:9 | self | | scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a | | scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a | -| scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | -| scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:12:4:12:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:14:4:14:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:15:4:15:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:16:4:16:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:17:4:17:9 | self | +| scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | +| scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:12:4:12:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:14:4:14:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:15:4:15:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:16:4:16:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:17:4:17:9 | self | | scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a | | scopes.rb:13:4:13:4 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a | | scopes.rb:13:7:13:7 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b | @@ -318,10 +318,10 @@ read | ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:29:3:29:11 | self | | ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements | | ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem | -| ssa.rb:26:3:28:5 | self | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self | +| ssa.rb:26:3:28:5 | self | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self | +| ssa.rb:26:3:28:5 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem | | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | -| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem | -| ssa.rb:33:16:35:5 | self | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self | +| ssa.rb:33:16:35:5 | self | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self | | ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | ssa.rb:34:10:34:10 | x | | ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:3:39:9 | self | | ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:8:39:9 | self | @@ -340,19 +340,19 @@ read | ssa.rb:60:3:60:9 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x | | ssa.rb:64:1:72:3 | self (m9) | ssa.rb:64:1:72:3 | self | ssa.rb:71:3:71:15 | self | | ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a | -| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured | -| ssa.rb:66:11:70:5 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | -| ssa.rb:66:11:70:5 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured | -| ssa.rb:66:11:70:5 | self | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self | -| ssa.rb:66:11:70:5 | self | ssa.rb:64:1:72:3 | self | ssa.rb:68:5:68:17 | self | +| ssa.rb:66:3:70:5 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured | +| ssa.rb:66:11:70:5 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | +| ssa.rb:66:11:70:5 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured | +| ssa.rb:66:11:70:5 | self | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self | +| ssa.rb:66:11:70:5 | self | ssa.rb:64:1:72:3 | self | ssa.rb:68:5:68:17 | self | | ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:67:10:67:10 | a | | ssa.rb:74:1:79:3 | self (m10) | ssa.rb:74:1:79:3 | self | ssa.rb:76:3:78:5 | self | -| ssa.rb:76:7:78:5 | captured | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured | -| ssa.rb:76:7:78:5 | self | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self | +| ssa.rb:76:7:78:5 | captured | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured | +| ssa.rb:76:7:78:5 | self | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self | | ssa.rb:81:1:88:3 | self (m11) | ssa.rb:81:1:88:3 | self | ssa.rb:83:3:87:5 | self | -| ssa.rb:83:7:87:5 | self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self | -| ssa.rb:84:10:86:8 | captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured | -| ssa.rb:84:10:86:8 | self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self | +| ssa.rb:83:7:87:5 | self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self | +| ssa.rb:84:10:86:8 | captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured | +| ssa.rb:84:10:86:8 | self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self | | ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:93:5:93:10 | self | | ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:95:5:95:10 | self | | ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:99:5:99:10 | self | @@ -379,8 +379,8 @@ firstRead | 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 | self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self | -| instance_variables.rb:32:10:32:21 | self | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self | +| instance_variables.rb:27:6:29:1 | self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self | +| instance_variables.rb:32:10:32:21 | self | 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 | @@ -397,15 +397,15 @@ firstRead | 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:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:16:13:16:13 | a | | nested_scopes.rb:17:15:17:19 | ... = ... | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:15:18:15 | a | -| nested_scopes.rb:18:23:18:36 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a | -| nested_scopes.rb:18:23:18:36 | self | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self | +| nested_scopes.rb:18:23:18:36 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a | +| nested_scopes.rb:18:23:18:36 | self | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self | | nested_scopes.rb:22:9:24:11 | self (show_a2) | nested_scopes.rb:22:9:24:11 | self | nested_scopes.rb:23:11:23:16 | self | | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:23:16:23:16 | a | | nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self | nested_scopes.rb:28:11:28:16 | self | | nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:32:11:32:16 | self | | nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:32:16:32:16 | a | | nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:41:1:41:1 | d | -| parameters.rb:1:9:5:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self | +| parameters.rb:1:9:5:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self | | parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:3:9:3:9 | x | | parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y | | parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self | parameters.rb:9:5:9:33 | self | @@ -414,7 +414,7 @@ firstRead | parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client | parameters.rb:11:41:11:46 | client | | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | | parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map | -| parameters.rb:16:12:18:5 | self | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self | +| parameters.rb:16:12:18:5 | self | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self | | parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key | | parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value | | parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block | @@ -437,7 +437,7 @@ firstRead | parameters.rb:49:1:51:3 | self (tuples) | parameters.rb:49:1:51:3 | self | parameters.rb:50:3:50:18 | self | | parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:50:11:50:11 | a | | parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:50:16:50:16 | b | -| parameters.rb:54:9:57:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self | +| parameters.rb:54:9:57:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self | | parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:56:9:56:9 | y | | parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:55:9:55:9 | x | | parameters.rb:59:1:61:3 | self (tuples_nested) | parameters.rb:59:1:61:3 | self | parameters.rb:60:3:60:23 | self | @@ -445,11 +445,11 @@ firstRead | parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b | | parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c | | scopes.rb:1:1:49:4 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | scopes.rb:8:1:8:6 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self | | scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a | | scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a | -| scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self | +| scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self | | scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a | | scopes.rb:13:4:13:4 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a | | scopes.rb:13:7:13:7 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b | @@ -472,10 +472,10 @@ firstRead | ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:29:3:29:11 | self | | ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements | | ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem | -| ssa.rb:26:3:28:5 | self | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self | +| ssa.rb:26:3:28:5 | self | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self | +| ssa.rb:26:3:28:5 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem | | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | -| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem | -| ssa.rb:33:16:35:5 | self | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self | +| ssa.rb:33:16:35:5 | self | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self | | ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | ssa.rb:34:10:34:10 | x | | ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:3:39:9 | self | | ssa.rb:40:3:40:9 | ... = ... | ssa.rb:40:3:40:4 | m3 | ssa.rb:41:8:41:9 | m3 | @@ -492,17 +492,17 @@ firstRead | ssa.rb:60:3:60:9 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x | | ssa.rb:64:1:72:3 | self (m9) | ssa.rb:64:1:72:3 | self | ssa.rb:71:3:71:15 | self | | ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a | -| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured | -| ssa.rb:66:11:70:5 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | -| ssa.rb:66:11:70:5 | self | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self | +| ssa.rb:66:3:70:5 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured | +| ssa.rb:66:11:70:5 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | +| ssa.rb:66:11:70:5 | self | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self | | ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:67:10:67:10 | a | | ssa.rb:74:1:79:3 | self (m10) | ssa.rb:74:1:79:3 | self | ssa.rb:76:3:78:5 | self | -| ssa.rb:76:7:78:5 | captured | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured | -| ssa.rb:76:7:78:5 | self | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self | +| ssa.rb:76:7:78:5 | captured | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured | +| ssa.rb:76:7:78:5 | self | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self | | ssa.rb:81:1:88:3 | self (m11) | ssa.rb:81:1:88:3 | self | ssa.rb:83:3:87:5 | self | -| ssa.rb:83:7:87:5 | self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self | -| ssa.rb:84:10:86:8 | captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured | -| ssa.rb:84:10:86:8 | self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self | +| ssa.rb:83:7:87:5 | self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self | +| ssa.rb:84:10:86:8 | captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured | +| ssa.rb:84:10:86:8 | self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self | | ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:93:5:93:10 | self | | ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:95:5:95:10 | self | | ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:99:5:99:10 | self | @@ -529,8 +529,8 @@ lastRead | 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 | self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self | -| instance_variables.rb:32:10:32:21 | self | instance_variables.rb:31:1:33:3 | self | instance_variables.rb:32:12:32:13 | self | +| instance_variables.rb:27:6:29:1 | self | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:28:3:28:4 | self | +| instance_variables.rb:32:10:32:21 | self | 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 | @@ -547,15 +547,15 @@ lastRead | nested_scopes.rb:13:11:13:15 | ... = ... | nested_scopes.rb:13:11:13:11 | a | nested_scopes.rb:15:11:15:11 | a | | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:15:23:15:23 | a | nested_scopes.rb:16:13:16:13 | a | | nested_scopes.rb:17:15:17:19 | ... = ... | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:15:18:15 | a | -| nested_scopes.rb:18:23:18:36 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a | -| nested_scopes.rb:18:23:18:36 | self | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self | +| nested_scopes.rb:18:23:18:36 | a | nested_scopes.rb:16:29:16:29 | a | nested_scopes.rb:18:34:18:34 | a | +| nested_scopes.rb:18:23:18:36 | self | nested_scopes.rb:12:9:21:11 | self | nested_scopes.rb:18:29:18:34 | self | | nested_scopes.rb:22:9:24:11 | self (show_a2) | nested_scopes.rb:22:9:24:11 | self | nested_scopes.rb:23:11:23:16 | self | | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:22:21:22:21 | a | nested_scopes.rb:23:16:23:16 | a | | nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self | nested_scopes.rb:28:16:28:16 | self | | nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:32:11:32:16 | self | | nested_scopes.rb:31:11:31:16 | ... = ... | nested_scopes.rb:31:11:31:11 | a | nested_scopes.rb:32:16:32:16 | a | | nested_scopes.rb:40:1:40:18 | ... = ... | nested_scopes.rb:40:1:40:1 | d | nested_scopes.rb:41:1:41:1 | d | -| parameters.rb:1:9:5:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:4:4:4:9 | self | +| parameters.rb:1:9:5:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:4:4:4:9 | self | | parameters.rb:1:14:1:14 | x | parameters.rb:1:14:1:14 | x | parameters.rb:3:9:3:9 | x | | parameters.rb:2:4:2:8 | ... = ... | parameters.rb:1:18:1:18 | y | parameters.rb:4:9:4:9 | y | | parameters.rb:7:1:13:3 | self (order_pizza) | parameters.rb:7:1:13:3 | self | parameters.rb:9:5:9:33 | self | @@ -565,7 +565,7 @@ lastRead | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:11:14:11:19 | pizzas | | parameters.rb:15:17:15:19 | map | parameters.rb:15:17:15:19 | map | parameters.rb:16:3:16:5 | map | -| parameters.rb:16:12:18:5 | self | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self | +| parameters.rb:16:12:18:5 | self | parameters.rb:15:1:19:3 | self | parameters.rb:17:5:17:28 | self | | parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key | parameters.rb:17:13:17:15 | key | | parameters.rb:16:21:16:25 | value | parameters.rb:16:21:16:25 | value | parameters.rb:17:22:17:26 | value | | parameters.rb:21:17:21:21 | block | parameters.rb:21:17:21:21 | block | parameters.rb:22:3:22:7 | block | @@ -587,7 +587,7 @@ lastRead | parameters.rb:49:1:51:3 | self (tuples) | parameters.rb:49:1:51:3 | self | parameters.rb:50:3:50:18 | self | | parameters.rb:49:13:49:13 | a | parameters.rb:49:13:49:13 | a | parameters.rb:50:11:50:11 | a | | parameters.rb:49:15:49:15 | b | parameters.rb:49:15:49:15 | b | parameters.rb:50:16:50:16 | b | -| parameters.rb:54:9:57:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:56:4:56:9 | self | +| parameters.rb:54:9:57:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:56:4:56:9 | self | | parameters.rb:54:14:54:14 | y | parameters.rb:54:14:54:14 | y | parameters.rb:56:9:56:9 | y | | parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:55:9:55:9 | x | | parameters.rb:59:1:61:3 | self (tuples_nested) | parameters.rb:59:1:61:3 | self | parameters.rb:60:3:60:23 | self | @@ -595,11 +595,11 @@ lastRead | parameters.rb:59:23:59:23 | b | parameters.rb:59:23:59:23 | b | parameters.rb:60:16:60:16 | b | | parameters.rb:59:25:59:25 | c | parameters.rb:59:25:59:25 | c | parameters.rb:60:21:60:21 | c | | scopes.rb:1:1:49:4 | self (scopes.rb) | scopes.rb:1:1:49:4 | self | scopes.rb:8:1:8:6 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:5:4:5:9 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:5:4:5:9 | self | | scopes.rb:4:4:4:8 | ... = ... | scopes.rb:4:4:4:4 | a | scopes.rb:5:9:5:9 | a | | scopes.rb:7:1:7:5 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:8:6:8:6 | a | -| scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:17:4:17:9 | self | +| scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | scopes.rb:11:4:11:4 | a | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:17:4:17:9 | self | | scopes.rb:11:4:11:9 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:12:9:12:9 | a | | scopes.rb:13:4:13:4 | ... = ... | scopes.rb:7:1:7:1 | a | scopes.rb:14:9:14:9 | a | | scopes.rb:13:7:13:7 | ... = ... | scopes.rb:13:7:13:7 | b | scopes.rb:15:9:15:9 | b | @@ -623,10 +623,10 @@ lastRead | ssa.rb:25:1:30:3 | self (m2) | ssa.rb:25:1:30:3 | self | ssa.rb:29:3:29:11 | self | | ssa.rb:25:8:25:15 | elements | ssa.rb:25:8:25:15 | elements | ssa.rb:26:15:26:22 | elements | | ssa.rb:26:3:28:5 | ... = ... | ssa.rb:26:7:26:10 | elem | ssa.rb:27:10:27:13 | elem | -| ssa.rb:26:3:28:5 | self | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self | +| ssa.rb:26:3:28:5 | self | ssa.rb:25:1:30:3 | self | ssa.rb:27:5:27:13 | self | +| ssa.rb:26:3:28:5 | elem | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem | | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | ssa.rb:26:3:28:5 | __synth__0__1 | -| ssa.rb:26:3:28:5 | call to each | ssa.rb:26:7:26:10 | elem | ssa.rb:29:8:29:11 | elem | -| ssa.rb:33:16:35:5 | self | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self | +| ssa.rb:33:16:35:5 | self | ssa.rb:32:1:36:3 | self | ssa.rb:34:5:34:10 | self | | ssa.rb:33:20:33:20 | x | ssa.rb:33:20:33:20 | x | ssa.rb:34:10:34:10 | x | | ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:41:3:41:13 | self | | ssa.rb:40:3:40:9 | ... = ... | ssa.rb:40:3:40:4 | m3 | ssa.rb:41:8:41:9 | m3 | @@ -643,17 +643,17 @@ lastRead | ssa.rb:60:3:60:9 | ... = ... | ssa.rb:59:3:59:3 | x | ssa.rb:61:8:61:8 | x | | ssa.rb:64:1:72:3 | self (m9) | ssa.rb:64:1:72:3 | self | ssa.rb:71:3:71:15 | self | | ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | ssa.rb:66:3:66:3 | a | -| ssa.rb:66:3:70:5 | call to times | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured | -| ssa.rb:66:11:70:5 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured | -| ssa.rb:66:11:70:5 | self | ssa.rb:64:1:72:3 | self | ssa.rb:68:5:68:17 | self | +| ssa.rb:66:3:70:5 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:71:8:71:15 | captured | +| ssa.rb:66:11:70:5 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:69:5:69:12 | captured | +| ssa.rb:66:11:70:5 | self | ssa.rb:64:1:72:3 | self | ssa.rb:68:5:68:17 | self | | ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | ssa.rb:67:10:67:10 | a | | ssa.rb:74:1:79:3 | self (m10) | ssa.rb:74:1:79:3 | self | ssa.rb:76:3:78:5 | self | -| ssa.rb:76:7:78:5 | captured | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured | -| ssa.rb:76:7:78:5 | self | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self | +| ssa.rb:76:7:78:5 | captured | ssa.rb:75:3:75:10 | captured | ssa.rb:77:15:77:22 | captured | +| ssa.rb:76:7:78:5 | self | ssa.rb:74:1:79:3 | self | ssa.rb:77:6:77:23 | self | | ssa.rb:81:1:88:3 | self (m11) | ssa.rb:81:1:88:3 | self | ssa.rb:83:3:87:5 | self | -| ssa.rb:83:7:87:5 | self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self | -| ssa.rb:84:10:86:8 | captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured | -| ssa.rb:84:10:86:8 | self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self | +| ssa.rb:83:7:87:5 | self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self | +| ssa.rb:84:10:86:8 | captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured | +| ssa.rb:84:10:86:8 | self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self | | ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:93:5:93:10 | self | | ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:95:5:95:10 | self | | ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:99:5:99:10 | self | @@ -679,19 +679,19 @@ adjacentReads | 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 | | nested_scopes.rb:27:7:29:9 | self (show) | nested_scopes.rb:27:7:29:9 | self | nested_scopes.rb:28:11:28:16 | self | nested_scopes.rb:28:16:28:16 | self | | nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self | nested_scopes.rb:30:16:30:19 | self | nested_scopes.rb:32:11:32:16 | self | -| parameters.rb:1:9:5:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self | parameters.rb:4:4:4:9 | self | +| parameters.rb:1:9:5:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:3:4:3:9 | self | parameters.rb:4:4:4:9 | self | | parameters.rb:7:26:7:31 | pizzas | parameters.rb:7:26:7:31 | pizzas | parameters.rb:8:6:8:11 | pizzas | parameters.rb:11:14:11:19 | pizzas | | parameters.rb:25:1:28:3 | self (opt_param) | parameters.rb:25:1:28:3 | self | parameters.rb:26:3:26:11 | self | parameters.rb:27:3:27:11 | self | | parameters.rb:25:15:25:18 | name | parameters.rb:25:15:25:18 | name | parameters.rb:25:40:25:43 | name | parameters.rb:26:8:26:11 | name | -| parameters.rb:54:9:57:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self | parameters.rb:56:4:56:9 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self | scopes.rb:3:9:3:9 | self | -| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self | scopes.rb:5:4:5:9 | self | -| scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | scopes.rb:11:4:11:4 | a | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self | scopes.rb:12:4:12:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:12:4:12:9 | self | scopes.rb:14:4:14:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:14:4:14:9 | self | scopes.rb:15:4:15:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:15:4:15:9 | self | scopes.rb:16:4:16:9 | self | -| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:16:4:16:9 | self | scopes.rb:17:4:17:9 | self | +| parameters.rb:54:9:57:3 | self | parameters.rb:1:1:62:1 | self | parameters.rb:55:4:55:9 | self | parameters.rb:56:4:56:9 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:3:4:3:9 | self | scopes.rb:3:9:3:9 | self | +| scopes.rb:2:9:6:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:3:9:3:9 | self | scopes.rb:5:4:5:9 | self | +| scopes.rb:9:9:18:3 | a | scopes.rb:7:1:7:1 | a | scopes.rb:10:9:10:9 | a | scopes.rb:11:4:11:4 | a | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:10:4:10:9 | self | scopes.rb:12:4:12:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:12:4:12:9 | self | scopes.rb:14:4:14:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:14:4:14:9 | self | scopes.rb:15:4:15:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:15:4:15:9 | self | scopes.rb:16:4:16:9 | self | +| scopes.rb:9:9:18:3 | self | scopes.rb:1:1:49:4 | self | scopes.rb:16:4:16:9 | self | scopes.rb:17:4:17:9 | self | | scopes.rb:13:10:13:15 | ... = ... | scopes.rb:13:10:13:15 | __synth__0__1 | scopes.rb:13:11:13:11 | __synth__0__1 | scopes.rb:13:14:13:14 | __synth__0__1 | | scopes.rb:13:19:13:32 | ... = ... | scopes.rb:13:4:13:32 | __synth__0 | scopes.rb:13:4:13:4 | __synth__0 | scopes.rb:13:7:13:7 | __synth__0 | | scopes.rb:13:19:13:32 | ... = ... | scopes.rb:13:4:13:32 | __synth__0 | scopes.rb:13:7:13:7 | __synth__0 | scopes.rb:13:10:13:15 | __synth__0 | @@ -714,8 +714,8 @@ adjacentReads | ssa.rb:19:9:19:9 | phi | ssa.rb:18:8:18:8 | x | ssa.rb:20:10:20:10 | x | ssa.rb:21:5:21:5 | x | | ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:3:39:9 | self | ssa.rb:39:8:39:9 | self | | ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:8:39:9 | self | ssa.rb:41:3:41:13 | self | -| ssa.rb:66:11:70:5 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | ssa.rb:69:5:69:12 | captured | -| ssa.rb:66:11:70:5 | self | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self | ssa.rb:68:5:68:17 | self | +| ssa.rb:66:11:70:5 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | ssa.rb:69:5:69:12 | captured | +| ssa.rb:66:11:70:5 | self | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self | ssa.rb:68:5:68:17 | self | | ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:93:5:93:10 | self | ssa.rb:99:5:99:10 | self | | ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:93:5:93:10 | self | ssa.rb:101:5:101:10 | self | | ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:95:5:95:10 | self | ssa.rb:99:5:99:10 | self | @@ -729,7 +729,7 @@ phi | parameters.rb:37:3:37:18 | phi | parameters.rb:35:16:35:16 | b | parameters.rb:35:16:35:20 | ... = ... | | parameters.rb:42:3:42:18 | phi | parameters.rb:40:15:40:15 | e | parameters.rb:40:1:43:3 | | | parameters.rb:42:3:42:18 | phi | parameters.rb:40:15:40:15 | e | parameters.rb:40:15:40:19 | ... = ... | -| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:54:9:57:3 | x | +| parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:54:9:57:3 | x | | parameters.rb:55:4:55:9 | phi | parameters.rb:53:1:53:1 | x | parameters.rb:54:19:54:23 | ... = ... | | ssa.rb:5:3:13:5 | phi | ssa.rb:2:3:2:3 | i | ssa.rb:6:5:6:9 | ... = ... | | ssa.rb:5:3:13:5 | phi | ssa.rb:2:3:2:3 | i | ssa.rb:10:5:10:9 | ... = ... |