Merge pull request #7084 from hvitved/ruby/self-flow

Ruby: Cleanup flow through `self`
This commit is contained in:
Tom Hvitved
2022-03-10 10:50:24 +01:00
committed by GitHub
25 changed files with 496 additions and 422 deletions

View File

@@ -24,21 +24,8 @@ class Expr extends Stmt, TExpr {
}
}
/**
* A reference to the current object. For example:
* - `self == other`
* - `self.method_name`
* - `def self.method_name ... end`
*
* This also includes implicit references to the current object in method
* calls. For example, the method call `foo(123)` has an implicit `self`
* receiver, and is equivalent to the explicit `self.foo(123)`.
*/
class Self extends Expr, TSelf {
final override string getAPrimaryQlClass() { result = "Self" }
final override string toString() { result = "self" }
}
/** DEPRECATED: Use `SelfVariableAccess` instead. */
deprecated class Self = SelfVariableAccess;
/**
* A sequence of expressions in the right-hand side of an assignment or

View File

@@ -201,7 +201,16 @@ class ClassVariableWriteAccess extends ClassVariableAccess, VariableWriteAccess
/** An access to a class variable where the value is read. */
class ClassVariableReadAccess extends ClassVariableAccess, VariableReadAccess { }
/** An access to the `self` variable */
/**
* An access to the `self` variable. For example:
* - `self == other`
* - `self.method_name`
* - `def self.method_name ... end`
*
* This also includes implicit references to the current object in method
* calls. For example, the method call `foo(123)` has an implicit `self`
* receiver, and is equivalent to the explicit `self.foo(123)`.
*/
class SelfVariableAccess extends LocalVariableAccess instanceof SelfVariableAccessImpl {
final override string getAPrimaryQlClass() { result = "SelfVariableAccess" }
}

View File

@@ -73,7 +73,7 @@ private module Cached {
m = resolveConstantReadAccess(c.getReceiver())
or
m = enclosingModule(c).getModule() and
c.getReceiver() instanceof Self
c.getReceiver() instanceof SelfVariableAccess
) and
result = resolveConstantReadAccess(c.getAnArgument())
}
@@ -437,7 +437,7 @@ private module ResolveImpl {
encl = enclosingModule(this) and
result = [qualifiedModuleNameNonRec(encl, _, _), qualifiedModuleNameRec(encl, _, _)]
|
this.getReceiver() instanceof Self
this.getReceiver() instanceof SelfVariableAccess
or
not exists(this.getReceiver())
)

View File

@@ -366,7 +366,23 @@ private module Cached {
cached
predicate isCapturedAccess(LocalVariableAccess access) {
access.getVariable().getDeclaringScope() != access.getCfgScope()
exists(Scope scope1, Scope scope2 |
scope1 = access.getVariable().getDeclaringScope() and
scope2 = access.getCfgScope() and
scope1 != scope2
|
if access instanceof SelfVariableAccess
then
// ```
// class C
// def self.m // not a captured access
// end
// end
// ```
not scope2 instanceof Toplevel or
not access = any(SingletonMethod m).getObject()
else any()
)
}
cached

View File

@@ -14,7 +14,7 @@ class EntryNode extends CfgNode, TEntryNode {
EntryNode() { this = TEntryNode(scope) }
final override EntryBasicBlock getBasicBlock() { result = CfgNode.super.getBasicBlock() }
final override EntryBasicBlock getBasicBlock() { result = super.getBasicBlock() }
final override Location getLocation() { result = scope.getLocation() }
@@ -31,7 +31,7 @@ class AnnotatedExitNode extends CfgNode, TAnnotatedExitNode {
/** Holds if this node represent a normal exit. */
final predicate isNormal() { normal = true }
final override AnnotatedExitBasicBlock getBasicBlock() { result = CfgNode.super.getBasicBlock() }
final override AnnotatedExitBasicBlock getBasicBlock() { result = super.getBasicBlock() }
final override Location getLocation() { result = scope.getLocation() }

View File

@@ -233,6 +233,8 @@ module Ssa {
)
}
override SelfVariable getSourceVariable() { result = v }
final override string toString() { result = "self (" + v.getDeclaringScope() + ")" }
final override Location getLocation() { result = this.getControlFlowNode().getLocation() }
@@ -314,7 +316,7 @@ module Ssa {
CapturedCallDefinition() {
exists(Variable v, BasicBlock bb, int i |
this.definesAt(v, bb, i) and
SsaImpl::capturedCallWrite(bb, i, v)
SsaImpl::capturedCallWrite(_, bb, i, v)
)
}

View File

@@ -203,7 +203,7 @@ private module Cached {
result = lookupMethod(tp, method) and
if result.(Method).isPrivate()
then
exists(Self self |
exists(SelfVariableAccess self |
self = call.getReceiver().getExpr() and
pragma[only_bind_out](self.getEnclosingModule().getModule().getSuperClass*()) =
pragma[only_bind_out](result.getEnclosingModule().getModule())
@@ -232,6 +232,18 @@ private module Cached {
)
}
/** Gets a viable run-time target for the call `call`. */
cached
DataFlowCallable viableCallable(DataFlowCall call) {
result = TCfgScope(getTarget(call.asCall())) and
not call.asCall().getExpr() instanceof YieldCall // handled by `lambdaCreation`/`lambdaCall`
or
exists(LibraryCallable callable |
result = TLibraryCallable(callable) and
call.asCall().getExpr() = callable.getACall()
)
}
cached
newtype TArgumentPosition =
TSelfArgumentPosition() or
@@ -300,28 +312,14 @@ private DataFlow::LocalSourceNode trackInstance(Module tp, TypeTracker t) {
)
or
// `self` in method
exists(Self self, Method enclosing |
self = result.asExpr().getExpr() and
enclosing = self.getEnclosingMethod() and
tp = enclosing.getEnclosingModule().getModule() and
not self.getEnclosingModule().getEnclosingMethod() = enclosing
)
tp = result.(SsaSelfDefinitionNode).getSelfScope().(Method).getEnclosingModule().getModule()
or
// `self` in singleton method
exists(Self self, MethodBase enclosing |
self = result.asExpr().getExpr() and
flowsToSingletonMethodObject(trackInstance(tp), enclosing) and
enclosing = self.getEnclosingMethod() and
not self.getEnclosingModule().getEnclosingMethod() = enclosing
)
flowsToSingletonMethodObject(trackInstance(tp), result.(SsaSelfDefinitionNode).getSelfScope())
or
// `self` in top-level
exists(Self self, Toplevel enclosing |
self = result.asExpr().getExpr() and
enclosing = self.getEnclosingModule() and
tp = TResolved("Object") and
not self.getEnclosingMethod().getEnclosingModule() = enclosing
)
result.(SsaSelfDefinitionNode).getSelfScope() instanceof Toplevel and
tp = TResolved("Object")
or
// a module or class
exists(Module m |
@@ -371,7 +369,7 @@ private predicate singletonMethod(MethodBase method, Expr object) {
pragma[nomagic]
private predicate flowsToSingletonMethodObject(DataFlow::LocalSourceNode nodeFrom, MethodBase method) {
exists(DataFlow::LocalSourceNode nodeTo |
exists(DataFlow::Node nodeTo |
nodeFrom.flowsTo(nodeTo) and
singletonMethod(method, nodeTo.asExpr().getExpr())
)
@@ -409,13 +407,8 @@ private DataFlow::LocalSourceNode trackSingletonMethod(MethodBase m, string name
name = m.getName()
}
private DataFlow::Node selfInModule(Module tp) {
exists(Self self, ModuleBase enclosing |
self = result.asExpr().getExpr() and
enclosing = self.getEnclosingModule() and
tp = enclosing.getModule() and
not self.getEnclosingMethod().getEnclosingModule() = enclosing
)
private SsaSelfDefinitionNode selfInModule(Module tp) {
tp = result.getSelfScope().(ModuleBase).getModule()
}
private DataFlow::LocalSourceNode trackModule(Module tp, TypeTracker t) {
@@ -442,17 +435,6 @@ private DataFlow::LocalSourceNode trackModule(Module tp) {
result = trackModule(tp, TypeTracker::end())
}
/** Gets a viable run-time target for the call `call`. */
DataFlowCallable viableCallable(DataFlowCall call) {
result = TCfgScope(getTarget(call.asCall())) and
not call.asCall().getExpr() instanceof YieldCall // handled by `lambdaCreation`/`lambdaCall`
or
exists(LibraryCallable callable |
result = TLibraryCallable(callable) and
call.asCall().getExpr() = callable.getACall()
)
}
/**
* Holds if the set of viable implementations that can be called by `call`
* might be improved by knowing the call context. This is the case if the

View File

@@ -70,6 +70,20 @@ module LocalFlow {
)
}
/** Gets the SSA definition node corresponding to the implicit `self` parameter for `m`. */
private SsaDefinitionNode getSelfParameterDefNode(MethodBase m) {
result.getDefinition().(Ssa::SelfDefinition).getSourceVariable().getDeclaringScope() = m
}
/**
* Holds if `nodeFrom` is a parameter node, and `nodeTo` is a corresponding SSA node.
*/
predicate localFlowSsaParamInput(Node nodeFrom, Node nodeTo) {
nodeTo = getParameterDefNode(nodeFrom.(ParameterNode).getParameter())
or
nodeTo = getSelfParameterDefNode(nodeFrom.(SelfParameterNode).getMethod())
}
/**
* Holds if there is a local use-use flow step from `nodeFrom` to `nodeTo`
* involving SSA definition `def`.
@@ -115,9 +129,6 @@ module LocalFlow {
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
localSsaFlowStep(nodeFrom, nodeTo)
or
nodeFrom.(SelfParameterNode).getMethod() = nodeTo.asExpr().getExpr().getEnclosingCallable() and
nodeTo.asExpr().getExpr() instanceof Self
or
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::AssignExprCfgNode).getRhs()
or
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::BlockArgumentCfgNode).getValue()
@@ -236,7 +247,7 @@ private module Cached {
or
defaultValueFlow(nodeTo.(ParameterNode).getParameter(), nodeFrom)
or
nodeTo = LocalFlow::getParameterDefNode(nodeFrom.(ParameterNode).getParameter())
LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
or
nodeTo.(SynthReturnNode).getAnInput() = nodeFrom
or
@@ -253,7 +264,7 @@ private module Cached {
or
defaultValueFlow(nodeTo.(ParameterNode).getParameter(), nodeFrom)
or
nodeTo = LocalFlow::getParameterDefNode(nodeFrom.(ParameterNode).getParameter())
LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
or
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
or
@@ -275,27 +286,34 @@ private module Cached {
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
}
private predicate entrySsaDefinition(SsaDefinitionNode n) {
n = LocalFlow::getParameterDefNode(_)
or
exists(Ssa::Definition def | def = n.getDefinition() |
def instanceof Ssa::SelfDefinition
or
def instanceof Ssa::CapturedEntryDefinition
)
}
cached
predicate isLocalSourceNode(Node n) {
n instanceof ParameterNode
or
// This case should not be needed once we have proper use-use flow
// for `self`. At that point, the `self`s returned by `trackInstance`
// in `DataFlowDispatch.qll` should refer to the post-update node,
// and we can remove this case.
n.asExpr().getExpr() instanceof Self
n instanceof PostUpdateNodes::ExprPostUpdateNode
or
// Nodes that can't be reached from another parameter or expression.
not localFlowStepTypeTracker+(any(Node e |
e instanceof ExprNode
// Expressions that can't be reached from another entry definition or expression.
not localFlowStepTypeTracker+(any(Node n0 |
n0 instanceof ExprNode
or
e instanceof ParameterNode
), n)
entrySsaDefinition(n0)
), n.(ExprNode))
or
// Ensure all parameter SSA nodes are local sources -- this is needed by type tracking.
// Note that when the parameter has a default value, it will be reachable from an
// expression (the default value) and therefore won't be caught by the rule above.
n = LocalFlow::getParameterDefNode(_)
// Ensure all entry SSA definitions are local sources -- for parameters, this
// is needed by type tracking. Note that when the parameter has a default value,
// it will be reachable from an expression (the default value) and therefore
// won't be caught by the rule above.
entrySsaDefinition(n)
}
cached
@@ -358,6 +376,16 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
override string toStringImpl() { result = def.toString() }
}
/** An SSA definition for a `self` variable. */
class SsaSelfDefinitionNode extends LocalSourceNode, SsaDefinitionNode {
private SelfVariable self;
SsaSelfDefinitionNode() { self = def.getSourceVariable() }
/** Gets the scope in which the `self` variable is declared. */
Scope getSelfScope() { result = self.getDeclaringScope() }
}
/**
* A value returning statement, viewed as a node in a data flow graph.
*
@@ -745,13 +773,6 @@ predicate jumpStep(Node pred, Node succ) {
SsaImpl::captureFlowOut(pred.(SsaDefinitionNode).getDefinition(),
succ.(SsaDefinitionNode).getDefinition())
or
exists(Self s, Method m |
s = succ.asExpr().getExpr() and
pred.(SelfParameterNode).getMethod() = m and
m = s.getEnclosingMethod() and
m != s.getEnclosingCallable()
)
or
succ.asExpr().getExpr().(ConstantReadAccess).getValue() = pred.asExpr().getExpr()
}

View File

@@ -1,4 +1,5 @@
private import SsaImplCommon
private import SsaImplSpecific as SsaImplSpecific
private import codeql.ruby.AST
private import codeql.ruby.CFG
private import codeql.ruby.ast.Variable
@@ -40,58 +41,50 @@ private predicate capturedExitRead(AnnotatedExitBasicBlock bb, int i, LocalVaria
i = bb.length()
}
private CfgScope getCaptureOuterCfgScope(CfgScope scope) {
result = scope.getOuterCfgScope() and
(
scope instanceof Block
or
scope instanceof Lambda
)
}
/** Holds if captured variable `v` is read inside `scope`. */
/**
* Holds if captured variable `v` is read directly inside `scope`,
* or inside a (transitively) nested scope of `scope`.
*/
pragma[noinline]
private predicate hasCapturedRead(Variable v, CfgScope scope) {
any(LocalVariableReadAccess read |
read.getVariable() = v and scope = getCaptureOuterCfgScope*(read.getCfgScope())
read.getVariable() = v and scope = read.getCfgScope().getOuterCfgScope*()
).isCapturedAccess()
}
/**
* Holds if `v` is written inside basic block `bb`, which is in the immediate
* outer scope of `scope`.
*/
pragma[noinline]
private predicate variableWriteInOuterScope(BasicBlock bb, LocalVariable v, CfgScope scope) {
SsaImplSpecific::variableWrite(bb, _, v, _) and
scope.getOuterCfgScope() = bb.getScope()
}
pragma[noinline]
private predicate hasVariableWriteWithCapturedRead(BasicBlock bb, LocalVariable v, CfgScope scope) {
hasCapturedRead(v, scope) and
exists(VariableWriteAccess write |
write = bb.getANode().getNode() and
write.getVariable() = v and
bb.getScope() = scope.getOuterCfgScope()
)
variableWriteInOuterScope(bb, v, scope)
}
/**
* Holds if the call at index `i` in basic block `bb` may reach a callable
* that reads captured variable `v`.
* Holds if the call `call` at index `i` in basic block `bb` may reach
* a callable that reads captured variable `v`.
*/
private predicate capturedCallRead(BasicBlock bb, int i, LocalVariable v) {
private predicate capturedCallRead(Call call, BasicBlock bb, int i, LocalVariable v) {
exists(CfgScope scope |
hasVariableWriteWithCapturedRead(bb.getAPredecessor*(), v, scope) and
bb.getNode(i).getNode() instanceof Call
call = bb.getNode(i).getNode()
|
not scope instanceof Block
or
// If the read happens inside a block, we restrict to the call that
// contains the block
scope = any(MethodCall c | bb.getNode(i) = c.getAControlFlowNode()).getBlock()
not scope instanceof Block
or
scope = call.(MethodCall).getBlock()
)
}
/** Holds if captured variable `v` is written inside `scope`. */
pragma[noinline]
private predicate hasCapturedWrite(Variable v, CfgScope scope) {
any(LocalVariableWriteAccess write |
write.getVariable() = v and scope = getCaptureOuterCfgScope*(write.getCfgScope())
).isCapturedAccess()
}
/** Holds if `v` is read at index `i` in basic block `bb`. */
private predicate variableReadActual(BasicBlock bb, int i, LocalVariable v) {
exists(VariableReadAccess read |
@@ -104,21 +97,38 @@ predicate variableRead(BasicBlock bb, int i, LocalVariable v, boolean certain) {
variableReadActual(bb, i, v) and
certain = true
or
capturedCallRead(bb, i, v) and
capturedCallRead(_, bb, i, v) and
certain = false
or
capturedExitRead(bb, i, v) and
certain = false
}
/**
* Holds if captured variable `v` is written directly inside `scope`,
* or inside a (transitively) nested scope of `scope`.
*/
pragma[noinline]
private predicate hasCapturedWrite(Variable v, CfgScope scope) {
any(LocalVariableWriteAccess write |
write.getVariable() = v and scope = write.getCfgScope().getOuterCfgScope*()
).isCapturedAccess()
}
/**
* Holds if `v` is read inside basic block `bb`, which is in the immediate
* outer scope of `scope`.
*/
pragma[noinline]
private predicate variableReadActualInOuterScope(BasicBlock bb, LocalVariable v, CfgScope scope) {
variableReadActual(bb, _, v) and
bb.getScope() = scope.getOuterCfgScope()
}
pragma[noinline]
private predicate hasVariableReadWithCapturedWrite(BasicBlock bb, LocalVariable v, CfgScope scope) {
hasCapturedWrite(v, scope) and
exists(VariableReadAccess read |
read = bb.getANode().getNode() and
read.getVariable() = v and
bb.getScope() = scope.getOuterCfgScope()
)
variableReadActualInOuterScope(bb, v, scope)
}
cached
@@ -134,20 +144,20 @@ private module Cached {
}
/**
* Holds if the call at index `i` in basic block `bb` may reach a callable
* Holds if the call `call` at index `i` in basic block `bb` may reach a callable
* that writes captured variable `v`.
*/
cached
predicate capturedCallWrite(BasicBlock bb, int i, LocalVariable v) {
predicate capturedCallWrite(Call call, BasicBlock bb, int i, LocalVariable v) {
exists(CfgScope scope |
hasVariableReadWithCapturedWrite(bb.getASuccessor*(), v, scope) and
bb.getNode(i).getNode() instanceof Call
call = bb.getNode(i).getNode()
|
not scope instanceof Block
or
// If the write happens inside a block, we restrict to the call that
// contains the block
scope = any(MethodCall c | bb.getNode(i) = c.getAControlFlowNode()).getBlock()
not scope instanceof Block
or
scope = call.(MethodCall).getBlock()
)
}
@@ -177,6 +187,26 @@ private module Cached {
)
}
pragma[noinline]
private predicate defReachesCallReadInOuterScope(
Definition def, Call call, LocalVariable v, CfgScope scope
) {
exists(BasicBlock bb, int i |
ssaDefReachesRead(v, def, bb, i) and
capturedCallRead(call, bb, i, v) and
scope.getOuterCfgScope() = bb.getScope()
)
}
pragma[noinline]
private predicate hasCapturedEntryWrite(Definition entry, LocalVariable v, CfgScope scope) {
exists(BasicBlock bb, int i |
capturedEntryWrite(bb, i, v) and
entry.definesAt(v, bb, i) and
bb.getScope().getOuterCfgScope*() = scope
)
}
/**
* Holds if there is flow for a captured variable from the enclosing scope into a block.
* ```rb
@@ -188,13 +218,35 @@ private module Cached {
*/
cached
predicate captureFlowIn(Definition def, Definition entry) {
exists(LocalVariable v, BasicBlock bb, int i |
exists(Call call, LocalVariable v, CfgScope scope |
defReachesCallReadInOuterScope(def, call, v, scope) and
hasCapturedEntryWrite(entry, v, scope)
|
// If the read happens inside a block, we restrict to the call that
// contains the block
not scope instanceof Block
or
scope = call.(MethodCall).getBlock()
)
}
private import codeql.ruby.dataflow.SSA
pragma[noinline]
private predicate defReachesExitReadInInnerScope(Definition def, LocalVariable v, CfgScope scope) {
exists(BasicBlock bb, int i |
ssaDefReachesRead(v, def, bb, i) and
capturedCallRead(bb, i, v) and
exists(BasicBlock bb2, int i2 |
capturedEntryWrite(bb2, i2, v) and
entry.definesAt(v, bb2, i2)
)
capturedExitRead(bb, i, v) and
scope = bb.getScope().getOuterCfgScope*()
)
}
pragma[noinline]
private predicate hasCapturedExitRead(Definition exit, Call call, LocalVariable v, CfgScope scope) {
exists(BasicBlock bb, int i |
capturedCallWrite(call, bb, i, v) and
exit.definesAt(v, bb, i) and
bb.getScope() = scope.getOuterCfgScope()
)
}
@@ -210,13 +262,15 @@ private module Cached {
*/
cached
predicate captureFlowOut(Definition def, Definition exit) {
exists(LocalVariable v, BasicBlock bb, int i |
ssaDefReachesRead(v, def, bb, i) and
capturedExitRead(bb, i, v) and
exists(BasicBlock bb2, int i2 |
capturedCallWrite(bb2, i2, v) and
exit.definesAt(v, bb2, i2)
)
exists(Call call, LocalVariable v, CfgScope scope |
defReachesExitReadInInnerScope(def, v, scope) and
hasCapturedExitRead(exit, call, v, _)
|
// If the read happens inside a block, we restrict to the call that
// contains the block
not scope instanceof Block
or
scope = call.(MethodCall).getBlock()
)
}

View File

@@ -40,7 +40,7 @@ predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain)
) and
certain = true
or
SsaImpl::capturedCallWrite(bb, i, v) and
SsaImpl::capturedCallWrite(_, bb, i, v) and
certain = false
}

View File

@@ -66,35 +66,53 @@ private CfgNodes::ExprNodes::VariableWriteAccessCfgNode variablesInPattern(
)
}
/**
* Holds if the additional step from `nodeFrom` to `nodeTo` should be included
* in all global taint flow configurations.
*/
cached
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// value of `case` expression into variables in patterns
exists(CfgNodes::ExprNodes::CaseExprCfgNode case, CfgNodes::ExprNodes::InClauseCfgNode clause |
nodeFrom.asExpr() = case.getValue() and
clause = case.getBranch(_) and
nodeTo.(SsaDefinitionNode).getDefinition().getControlFlowNode() =
variablesInPattern(clause.getPattern())
)
or
// operation involving `nodeFrom`
exists(CfgNodes::ExprNodes::OperationCfgNode op |
op = nodeTo.asExpr() and
op.getAnOperand() = nodeFrom.asExpr() and
not op.getExpr() instanceof AssignExpr
)
or
// string interpolation of `nodeFrom` into `nodeTo`
nodeFrom.asExpr() =
nodeTo.asExpr().(CfgNodes::ExprNodes::StringlikeLiteralCfgNode).getAComponent()
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, false)
or
// Although flow through arrays is modelled precisely using stores/reads, we still
// allow flow out of a _tainted_ array. This is needed in order to support taint-
// tracking configurations where the source is an array.
readStep(nodeFrom, any(DataFlow::Content::ArrayElementContent c), nodeTo)
private module Cached {
/**
* Holds if the additional step from `nodeFrom` to `nodeTo` should be included
* in all global taint flow configurations.
*/
cached
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// value of `case` expression into variables in patterns
exists(CfgNodes::ExprNodes::CaseExprCfgNode case, CfgNodes::ExprNodes::InClauseCfgNode clause |
nodeFrom.asExpr() = case.getValue() and
clause = case.getBranch(_) and
nodeTo.(SsaDefinitionNode).getDefinition().getControlFlowNode() =
variablesInPattern(clause.getPattern())
)
or
// operation involving `nodeFrom`
exists(CfgNodes::ExprNodes::OperationCfgNode op |
op = nodeTo.asExpr() and
op.getAnOperand() = nodeFrom.asExpr() and
not op.getExpr() instanceof AssignExpr
)
or
// string interpolation of `nodeFrom` into `nodeTo`
nodeFrom.asExpr() =
nodeTo.asExpr().(CfgNodes::ExprNodes::StringlikeLiteralCfgNode).getAComponent()
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, false)
or
// Although flow through arrays is modelled precisely using stores/reads, we still
// allow flow out of a _tainted_ array. This is needed in order to support taint-
// tracking configurations where the source is an array.
readStep(nodeFrom, any(DataFlow::Content::ArrayElementContent c), nodeTo)
}
/**
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step.
*/
cached
predicate localTaintStepCached(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
defaultAdditionalTaintStep(nodeFrom, nodeTo)
or
// Simple flow through library code is included in the exposed local
// step relation, even though flow is technically inter-procedural
FlowSummaryImpl::Private::Steps::summaryThroughStep(nodeFrom, nodeTo, false)
}
}
import Cached

View File

@@ -20,14 +20,4 @@ predicate localExprTaint(CfgNodes::ExprCfgNode e1, CfgNodes::ExprCfgNode e2) {
localTaint(DataFlow::exprNode(e1), DataFlow::exprNode(e2))
}
/**
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
* (intra-procedural) step.
*/
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
defaultAdditionalTaintStep(nodeFrom, nodeTo)
or
// Simple flow through library code is included in the exposed local
// step relation, even though flow is technically inter-procedural
FlowSummaryImpl::Private::Steps::summaryThroughStep(nodeFrom, nodeTo, false)
}
predicate localTaintStep = localTaintStepCached/2;

View File

@@ -105,7 +105,7 @@ private class ActionControllerContextCall extends MethodCall {
private ActionControllerControllerClass controllerClass;
ActionControllerContextCall() {
this.getReceiver() instanceof Self and
this.getReceiver() instanceof SelfVariableAccess and
this.getEnclosingModule() = controllerClass
}

View File

@@ -61,7 +61,7 @@ private class ActionViewHtmlEscapeCall extends HtmlEscapeCall {
// A call in a context where some commonly used `ActionView` methods are available.
private class ActionViewContextCall extends MethodCall {
ActionViewContextCall() {
this.getReceiver() instanceof Self and
this.getReceiver() instanceof SelfVariableAccess and
inActionViewContext(this)
}

View File

@@ -7,6 +7,7 @@ private import codeql.ruby.Concepts
private import codeql.ruby.controlflow.CfgNodes
private import codeql.ruby.DataFlow
private import codeql.ruby.dataflow.internal.DataFlowDispatch
private import codeql.ruby.dataflow.internal.DataFlowPrivate
private import codeql.ruby.ast.internal.Module
private import codeql.ruby.ApiGraphs
private import codeql.ruby.frameworks.Stdlib
@@ -100,7 +101,7 @@ class ActiveRecordModelClassMethodCall extends MethodCall {
recvCls = this.getReceiver().(ActiveRecordModelClassMethodCall).getReceiverClass()
or
// e.g. self.where(...) within an ActiveRecordModelClass
this.getReceiver() instanceof Self and
this.getReceiver() instanceof SelfVariableAccess and
this.getEnclosingModule() = recvCls
}
@@ -283,14 +284,15 @@ private class ActiveRecordModelFinderCall extends ActiveRecordModelInstantiation
}
// A `self` reference that may resolve to an active record model object
private class ActiveRecordModelClassSelfReference extends ActiveRecordModelInstantiation {
private class ActiveRecordModelClassSelfReference extends ActiveRecordModelInstantiation,
SsaSelfDefinitionNode {
private ActiveRecordModelClass cls;
ActiveRecordModelClassSelfReference() {
exists(Self s |
s.getEnclosingModule() = cls and
s.getEnclosingMethod() = cls.getAMethod() and
s = this.asExpr().getExpr()
exists(MethodBase m |
m = this.getCfgScope() and
m.getEnclosingModule() = cls and
m = cls.getAMethod()
)
}

View File

@@ -221,7 +221,7 @@ private class GraphqlSchemaObjectClassMethodCall extends MethodCall {
recvCls.getModule() = resolveConstantReadAccess(this.getReceiver())
or
// e.g. self.some_method(...) within a graphql Object or Interface
this.getReceiver() instanceof Self and
this.getReceiver() instanceof SelfVariableAccess and
this.getEnclosingModule() = recvCls
}

View File

@@ -27,7 +27,7 @@ module Kernel {
or
methodCall instanceof UnknownMethodCall and
(
this.getReceiver().asExpr().getExpr() instanceof Self and
this.getReceiver().asExpr().getExpr() instanceof SelfVariableAccess and
isPrivateKernelMethod(methodCall.getMethodName())
or
isPublicKernelMethod(methodCall.getMethodName())

View File

@@ -88,10 +88,7 @@ predicate callStep(Node nodeFrom, Node nodeTo) {
// we model it as a call step, in order to avoid computing a potential
// self-cross product of all calls to a function that returns one of its parameters
// (only to later filter that flow out using `TypeTracker::append`).
nodeTo =
DataFlowPrivate::LocalFlow::getParameterDefNode(nodeFrom
.(DataFlowPublic::ParameterNode)
.getParameter())
DataFlowPrivate::LocalFlow::localFlowSsaParamInput(nodeFrom, nodeTo)
}
/**

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@ calls/calls.rb:
# 58| getDesugared: [MethodCall] call to []
# 58| getReceiver: [ConstantReadAccess] Array
# 58| getArgument: [MethodCall] call to foo
# 58| getReceiver: [Self, SelfVariableAccess] self
# 58| getReceiver: [SelfVariableAccess] self
# 59| [ArrayLiteral] [...]
# 59| getDesugared: [MethodCall] call to []
# 59| getReceiver: [ConstantReadAccess] Array
@@ -15,7 +15,7 @@ calls/calls.rb:
# 66| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 66| getAnOperand/getLeftOperand/getReceiver: [LocalVariableAccess] var1
# 66| getAnOperand/getArgument/getRightOperand: [MethodCall] call to bar
# 66| getReceiver: [Self, SelfVariableAccess] self
# 66| getReceiver: [SelfVariableAccess] self
# 67| [AssignAddExpr] ... += ...
# 67| getDesugared: [AssignExpr] ... = ...
# 67| getAnOperand/getLeftOperand: [LocalVariableAccess] var1
@@ -32,9 +32,9 @@ calls/calls.rb:
# 226| getAnOperand/getRightOperand: [LocalVariableAccess] __synth__0__1
# 226| getAnOperand/getLeftOperand: [LocalVariableAccess] x
# 227| getStmt: [MethodCall] call to baz
# 227| getReceiver: [Self, SelfVariableAccess] self
# 227| getReceiver: [SelfVariableAccess] self
# 226| getReceiver: [MethodCall] call to bar
# 226| getReceiver: [Self, SelfVariableAccess] self
# 226| getReceiver: [SelfVariableAccess] self
# 229| [ForExpr] for ... in ...
# 229| getDesugared: [MethodCall] call to each
# 229| getBlock: [BraceBlock] { ... }
@@ -52,9 +52,9 @@ calls/calls.rb:
# 249| getReceiver: [ConstantReadAccess] Hash
# 249| getArgument: [Pair] Pair
# 249| getKey: [MethodCall] call to foo
# 249| getReceiver: [Self, SelfVariableAccess] self
# 249| getReceiver: [SelfVariableAccess] self
# 249| getValue: [MethodCall] call to bar
# 249| getReceiver: [Self, SelfVariableAccess] self
# 249| getReceiver: [SelfVariableAccess] self
# 249| getArgument: [Pair] Pair
# 249| getKey: [MethodCall] call to foo
# 249| getReceiver: [ConstantReadAccess] X
@@ -63,7 +63,7 @@ calls/calls.rb:
# 314| [AssignExpr] ... = ...
# 314| getDesugared: [StmtSequence] ...
# 314| getStmt: [SetterMethodCall] call to foo=
# 314| getReceiver: [Self, SelfVariableAccess] self
# 314| getReceiver: [SelfVariableAccess] self
# 314| getArgument: [AssignExpr] ... = ...
# 314| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
# 314| getAnOperand/getRightOperand: [IntegerLiteral] 10
@@ -72,7 +72,7 @@ calls/calls.rb:
# 315| getDesugared: [StmtSequence] ...
# 315| getStmt: [SetterMethodCall] call to []=
# 315| getReceiver: [MethodCall] call to foo
# 315| getReceiver: [Self, SelfVariableAccess] self
# 315| getReceiver: [SelfVariableAccess] self
# 315| getArgument: [AssignExpr] ... = ...
# 315| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
# 315| getAnOperand/getRightOperand: [IntegerLiteral] 10
@@ -84,7 +84,7 @@ calls/calls.rb:
# 316| getAnOperand/getLeftOperand: [MethodCall] call to foo
# 316| getDesugared: [StmtSequence] ...
# 316| getStmt: [SetterMethodCall] call to foo=
# 316| getReceiver: [Self, SelfVariableAccess] self
# 316| getReceiver: [SelfVariableAccess] self
# 316| getArgument: [AssignExpr] ... = ...
# 316| getAnOperand/getRightOperand: [MethodCall] call to []
# 316| getArgument: [IntegerLiteral] 0
@@ -95,7 +95,7 @@ calls/calls.rb:
# 316| getAnOperand/getLeftOperand: [MethodCall] call to bar
# 316| getDesugared: [StmtSequence] ...
# 316| getStmt: [SetterMethodCall] call to bar=
# 316| getReceiver: [Self, SelfVariableAccess] self
# 316| getReceiver: [SelfVariableAccess] self
# 316| getArgument: [AssignExpr] ... = ...
# 316| getAnOperand/getRightOperand: [MethodCall] call to []
# 316| getArgument: [RangeLiteral] _ .. _
@@ -109,7 +109,7 @@ calls/calls.rb:
# 316| getDesugared: [StmtSequence] ...
# 316| getStmt: [SetterMethodCall] call to []=
# 316| getReceiver: [MethodCall] call to foo
# 316| getReceiver: [Self, SelfVariableAccess] self
# 316| getReceiver: [SelfVariableAccess] self
# 316| getArgument: [AssignExpr] ... = ...
# 316| getAnOperand/getRightOperand: [MethodCall] call to []
# 316| getArgument: [IntegerLiteral] -1
@@ -139,7 +139,7 @@ calls/calls.rb:
# 317| getDesugared: [StmtSequence] ...
# 317| getStmt: [SetterMethodCall] call to []=
# 317| getReceiver: [MethodCall] call to foo
# 317| getReceiver: [Self, SelfVariableAccess] self
# 317| getReceiver: [SelfVariableAccess] self
# 317| getArgument: [AssignExpr] ... = ...
# 317| getAnOperand/getRightOperand: [MethodCall] call to []
# 317| getArgument: [RangeLiteral] _ .. _
@@ -161,7 +161,7 @@ calls/calls.rb:
# 318| [AssignAddExpr] ... += ...
# 318| getDesugared: [StmtSequence] ...
# 318| getStmt: [AssignExpr] ... = ...
# 318| getAnOperand/getRightOperand: [Self, SelfVariableAccess] self
# 318| getAnOperand/getRightOperand: [SelfVariableAccess] self
# 318| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
# 318| getStmt: [SetterMethodCall] call to count=
# 318| getReceiver: [LocalVariableAccess] __synth__0
@@ -177,7 +177,7 @@ calls/calls.rb:
# 319| getDesugared: [StmtSequence] ...
# 319| getStmt: [AssignExpr] ... = ...
# 319| getAnOperand/getRightOperand: [MethodCall] call to foo
# 319| getReceiver: [Self, SelfVariableAccess] self
# 319| getReceiver: [SelfVariableAccess] self
# 319| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
# 319| getStmt: [SetterMethodCall] call to []=
# 319| getReceiver: [LocalVariableAccess] __synth__0
@@ -199,7 +199,7 @@ calls/calls.rb:
# 320| getStmt: [AssignExpr] ... = ...
# 320| getAnOperand/getRightOperand: [MethodCall] call to bar
# 320| getReceiver: [MethodCall] call to foo
# 320| getReceiver: [Self, SelfVariableAccess] self
# 320| getReceiver: [SelfVariableAccess] self
# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__0
# 320| getStmt: [SetterMethodCall] call to []=
# 320| getReceiver: [LocalVariableAccess] __synth__0
@@ -213,13 +213,13 @@ calls/calls.rb:
# 320| getStmt: [AssignExpr] ... = ...
# 320| getAnOperand/getRightOperand: [MethodCall] call to baz
# 320| getReceiver: [MethodCall] call to foo
# 320| getReceiver: [Self, SelfVariableAccess] self
# 320| getReceiver: [SelfVariableAccess] self
# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__2
# 320| getStmt: [AssignExpr] ... = ...
# 320| getAnOperand/getRightOperand: [AddExpr] ... + ...
# 320| getAnOperand/getLeftOperand/getReceiver: [MethodCall] call to boo
# 320| getReceiver: [MethodCall] call to foo
# 320| getReceiver: [Self, SelfVariableAccess] self
# 320| getReceiver: [SelfVariableAccess] self
# 320| getAnOperand/getArgument/getRightOperand: [IntegerLiteral] 1
# 320| getAnOperand/getLeftOperand: [LocalVariableAccess] __synth__3
# 320| getStmt: [AssignExpr] ... = ...
@@ -260,7 +260,7 @@ calls/calls.rb:
# 340| getReceiver: [LocalVariableAccess] __synth__0__1
# 340| getAnOperand/getLeftOperand: [DestructuredLhsExpr] (..., ...)
# 341| getStmt: [MethodCall] call to foo
# 341| getReceiver: [Self, SelfVariableAccess] self
# 341| getReceiver: [SelfVariableAccess] self
# 341| getArgument: [LocalVariableAccess] x
# 341| getArgument: [LocalVariableAccess] y
# 341| getArgument: [LocalVariableAccess] z
@@ -476,7 +476,7 @@ literals/literals.rb:
# 118| getValue: [IntegerLiteral] 7
# 118| getArgument: [HashSplatExpr] ** ...
# 118| getAnOperand/getOperand/getReceiver: [MethodCall] call to baz
# 118| getReceiver: [Self, SelfVariableAccess] self
# 118| getReceiver: [SelfVariableAccess] self
# 185| [HashLiteral] {...}
# 185| getDesugared: [MethodCall] call to []
# 185| getReceiver: [ConstantReadAccess] Hash

View File

@@ -1,6 +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 (local_dataflow.rb) | local_dataflow.rb:49:1:53:3 | self |
| local_dataflow.rb:1:1:7:3 | self in 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: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 |
| local_dataflow.rb:2:3:2:7 | ... = ... | local_dataflow.rb:3:13:3:13 | b |
@@ -71,16 +71,7 @@
| local_dataflow.rb:50:18:50:18 | x | local_dataflow.rb:51:20:51:20 | x |
| local_dataflow.rb:51:9:51:15 | "break" | local_dataflow.rb:51:3:51:15 | break |
| local_dataflow.rb:60:1:90:3 | self (test_case) | local_dataflow.rb:78:12:78:20 | self |
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:78:12:78:20 | self |
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:79:20:79:26 | self |
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:80:24:80:30 | self |
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:82:7:82:13 | self |
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:83:7:83:13 | self |
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:84:7:84:13 | self |
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:85:22:85:28 | self |
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:86:28:86:34 | self |
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:87:20:87:26 | self |
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:89:3:89:9 | self |
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:60:1:90:3 | self (test_case) |
| local_dataflow.rb:60:15:60:15 | x | local_dataflow.rb:60:15:60:15 | x |
| local_dataflow.rb:60:15:60:15 | x | local_dataflow.rb:61:12:61:12 | x |
| local_dataflow.rb:61:7:68:5 | case ... | local_dataflow.rb:61:3:68:5 | ... = ... |

View File

@@ -201,7 +201,6 @@ edges
| string_flow.rb:241:10:241:10 | b [array element] : | string_flow.rb:241:10:241:13 | ...[...] |
| string_flow.rb:242:10:242:10 | b [array 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:5:246:18 | ... = ... : | string_flow.rb:258:27:258:27 | 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 : |
@@ -215,7 +214,6 @@ edges
| string_flow.rb:250:26:250:26 | a : | string_flow.rb:250:10:250:28 | 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:250:26:250:26 | a : |
| 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 : |

View File

@@ -5,6 +5,7 @@ track
| type_tracker.rb:2:5:5:7 | return return in field= | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
| type_tracker.rb:2:5:5:7 | self (field=) | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:2:5:5:7 | self (field=) | type tracker without call steps | type_tracker.rb:2:5:5:7 | self (field=) |
| type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) |
| type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:2:5:5:7 | self in field= | type tracker without call steps | type_tracker.rb:2:5:5:7 | self in field= |
| type_tracker.rb:2:16:2:18 | val | type tracker with call steps | type_tracker.rb:2:16:2:18 | val |
@@ -16,17 +17,10 @@ track
| type_tracker.rb:3:9:3:23 | [post] self | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:3:9:3:23 | [post] self | type tracker without call steps | type_tracker.rb:3:9:3:23 | [post] self |
| type_tracker.rb:3:9:3:23 | call to puts | type tracker without call steps | type_tracker.rb:3:9:3:23 | call to puts |
| type_tracker.rb:3:9:3:23 | self | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:3:9:3:23 | self | type tracker without call steps | type_tracker.rb:3:9:3:23 | self |
| type_tracker.rb:3:14:3:17 | [post] self | type tracker without call steps | type_tracker.rb:3:14:3:17 | [post] self |
| type_tracker.rb:3:14:3:17 | self | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:3:14:3:17 | self | type tracker without call steps | type_tracker.rb:3:14:3:17 | self |
| type_tracker.rb:3:14:3:23 | [post] call to field | type tracker without call steps | type_tracker.rb:3:14:3:23 | [post] call to field |
| type_tracker.rb:3:14:3:23 | call to field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
| type_tracker.rb:4:9:4:14 | @field | type tracker without call steps | type_tracker.rb:4:9:4:14 | @field |
| type_tracker.rb:4:18:4:20 | val | type tracker without call steps | type_tracker.rb:2:5:5:7 | return return in field= |
| type_tracker.rb:4:18:4:20 | val | type tracker without call steps | type_tracker.rb:4:18:4:20 | val |
| type_tracker.rb:4:18:4:20 | val | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
| type_tracker.rb:7:5:9:7 | &block | type tracker without call steps | type_tracker.rb:7:5:9:7 | &block |
| type_tracker.rb:7:5:9:7 | field | type tracker without call steps | type_tracker.rb:7:5:9:7 | field |
| type_tracker.rb:7:5:9:7 | return return in field | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
@@ -41,15 +35,22 @@ track
| type_tracker.rb:12:1:16:3 | m | type tracker without call steps | type_tracker.rb:12:1:16:3 | m |
| type_tracker.rb:12:1:16:3 | return return in m | type tracker without call steps | type_tracker.rb:12:1:16:3 | return return in m |
| type_tracker.rb:12:1:16:3 | self (m) | type tracker without call steps | type_tracker.rb:12:1:16:3 | self (m) |
| type_tracker.rb:12:1:16:3 | self in m | type tracker with call steps | type_tracker.rb:12:1:16:3 | self (m) |
| type_tracker.rb:12:1:16:3 | self in m | type tracker without call steps | type_tracker.rb:12:1:16:3 | self in m |
| type_tracker.rb:13:5:13:7 | var | type tracker without call steps | type_tracker.rb:13:5:13:7 | var |
| type_tracker.rb:13:5:13:23 | ... = ... | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) |
| type_tracker.rb:13:5:13:23 | ... = ... | type tracker with call steps | type_tracker.rb:2:5:5:7 | self in field= |
| type_tracker.rb:13:5:13:23 | ... = ... | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:13:5:13:23 | ... = ... | type tracker without call steps | type_tracker.rb:13:5:13:23 | ... = ... |
| type_tracker.rb:13:11:13:19 | Container | type tracker without call steps | type_tracker.rb:13:11:13:19 | Container |
| type_tracker.rb:13:11:13:19 | [post] Container | type tracker without call steps | type_tracker.rb:13:11:13:19 | [post] Container |
| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:2:5:5:7 | self (field=) |
| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:2:5:5:7 | self in field= |
| type_tracker.rb:13:11:13:23 | call to new | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:13:11:13:23 | call to new | type tracker without call steps | type_tracker.rb:13:11:13:23 | call to new |
| type_tracker.rb:14:5:14:7 | [post] var | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:14:5:14:7 | [post] var | type tracker without call steps | type_tracker.rb:14:5:14:7 | [post] var |
| type_tracker.rb:14:5:14:13 | ... = ... | type tracker without call steps | type_tracker.rb:14:5:14:13 | ... = ... |
| type_tracker.rb:14:5:14:13 | [post] ... = ... | type tracker without call steps | type_tracker.rb:14:5:14:13 | [post] ... = ... |
| type_tracker.rb:14:5:14:13 | __synth__0 | type tracker without call steps | type_tracker.rb:14:5:14:13 | __synth__0 |
| type_tracker.rb:14:5:14:13 | call to field= | type tracker without call steps | type_tracker.rb:14:5:14:13 | call to field= |
@@ -63,7 +64,6 @@ track
| type_tracker.rb:15:5:15:18 | [post] self | type tracker without call steps | type_tracker.rb:15:5:15:18 | [post] self |
| type_tracker.rb:15:5:15:18 | call to puts | type tracker without call steps | type_tracker.rb:12:1:16:3 | return return in m |
| type_tracker.rb:15:5:15:18 | call to puts | type tracker without call steps | type_tracker.rb:15:5:15:18 | call to puts |
| type_tracker.rb:15:5:15:18 | self | type tracker without call steps | type_tracker.rb:15:5:15:18 | self |
| type_tracker.rb:15:10:15:12 | [post] var | type tracker without call steps | type_tracker.rb:15:10:15:12 | [post] var |
| type_tracker.rb:15:10:15:18 | [post] call to field | type tracker without call steps | type_tracker.rb:15:10:15:18 | [post] call to field |
| type_tracker.rb:15:10:15:18 | call to field | type tracker without call steps | type_tracker.rb:15:10:15:18 | call to field |
@@ -76,6 +76,7 @@ trackEnd
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:9:3:23 | self |
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:3:14:3:17 | self |
| type_tracker.rb:2:5:5:7 | self (field=) | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:2:5:5:7 | self (field=) |
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:2:5:5:7 | self in field= |
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:3:9:3:23 | self |
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:3:14:3:17 | self |
@@ -94,19 +95,10 @@ trackEnd
| type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:3:14:3:17 | self |
| type_tracker.rb:3:9:3:23 | [post] self | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:3:9:3:23 | call to puts | type_tracker.rb:3:9:3:23 | call to puts |
| type_tracker.rb:3:9:3:23 | self | type_tracker.rb:3:9:3:23 | self |
| type_tracker.rb:3:9:3:23 | self | type_tracker.rb:3:14:3:17 | self |
| type_tracker.rb:3:9:3:23 | self | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:3:14:3:17 | [post] self | type_tracker.rb:3:14:3:17 | [post] self |
| type_tracker.rb:3:14:3:17 | self | type_tracker.rb:3:14:3:17 | self |
| type_tracker.rb:3:14:3:17 | self | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:3:14:3:23 | [post] call to field | type_tracker.rb:3:14:3:23 | [post] call to field |
| type_tracker.rb:3:14:3:23 | call to field | type_tracker.rb:3:14:3:23 | call to field |
| type_tracker.rb:4:9:4:14 | @field | type_tracker.rb:4:9:4:14 | @field |
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:2:5:5:7 | return return in field= |
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:4:9:4:20 | ... = ... |
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:4:18:4:20 | val |
| type_tracker.rb:4:18:4:20 | val | type_tracker.rb:14:5:14:13 | call to field= |
| type_tracker.rb:7:5:9:7 | &block | type_tracker.rb:7:5:9:7 | &block |
| type_tracker.rb:7:5:9:7 | field | type_tracker.rb:1:1:10:3 | Container |
| type_tracker.rb:7:5:9:7 | field | type_tracker.rb:7:5:9:7 | field |
@@ -123,11 +115,21 @@ trackEnd
| type_tracker.rb:12:1:16:3 | return return in m | type_tracker.rb:12:1:16:3 | return return in m |
| type_tracker.rb:12:1:16:3 | self (m) | type_tracker.rb:12:1:16:3 | self (m) |
| type_tracker.rb:12:1:16:3 | self (m) | type_tracker.rb:15:5:15:18 | self |
| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:12:1:16:3 | self (m) |
| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:12:1:16:3 | self in m |
| type_tracker.rb:12:1:16:3 | self in m | type_tracker.rb:15:5:15:18 | self |
| type_tracker.rb:13:5:13:7 | var | type_tracker.rb:13:5:13:7 | var |
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:2:5:5:7 | self (field=) |
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:2:5:5:7 | self in field= |
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:3:9:3:23 | self |
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:3:14:3:17 | self |
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:13:5:13:23 | ... = ... |
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:14:5:14:7 | var |
| type_tracker.rb:13:5:13:23 | ... = ... | type_tracker.rb:15:10:15:12 | var |
| type_tracker.rb:13:11:13:19 | Container | type_tracker.rb:13:11:13:19 | Container |
| type_tracker.rb:13:11:13:19 | [post] Container | type_tracker.rb:13:11:13:19 | [post] Container |
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:2:5:5:7 | self (field=) |
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:2:5:5:7 | self in field= |
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:3:9:3:23 | self |
| type_tracker.rb:13:11:13:23 | call to new | type_tracker.rb:3:14:3:17 | self |
@@ -140,6 +142,9 @@ trackEnd
| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:14:5:14:7 | [post] var |
| type_tracker.rb:14:5:14:7 | [post] var | type_tracker.rb:15:10:15:12 | var |
| type_tracker.rb:14:5:14:13 | ... = ... | type_tracker.rb:14:5:14:13 | ... = ... |
| type_tracker.rb:14:5:14:13 | ... = ... | type_tracker.rb:14:5:14:13 | __synth__0 |
| type_tracker.rb:14:5:14:13 | ... = ... | type_tracker.rb:14:5:14:23 | ... |
| type_tracker.rb:14:5:14:13 | [post] ... = ... | type_tracker.rb:14:5:14:13 | [post] ... = ... |
| type_tracker.rb:14:5:14:13 | __synth__0 | type_tracker.rb:14:5:14:13 | __synth__0 |
| type_tracker.rb:14:5:14:13 | call to field= | type_tracker.rb:14:5:14:13 | call to field= |
@@ -157,7 +162,6 @@ trackEnd
| type_tracker.rb:15:5:15:18 | [post] self | type_tracker.rb:15:5:15:18 | [post] self |
| type_tracker.rb:15:5:15:18 | call to puts | type_tracker.rb:12:1:16:3 | return return in m |
| type_tracker.rb:15:5:15:18 | call to puts | type_tracker.rb:15:5:15:18 | call to puts |
| type_tracker.rb:15:5:15:18 | self | type_tracker.rb:15:5:15:18 | self |
| type_tracker.rb:15:10:15:12 | [post] var | type_tracker.rb:15:10:15:12 | [post] var |
| type_tracker.rb:15:10:15:18 | [post] call to field | type_tracker.rb:15:10:15:18 | [post] call to field |
| type_tracker.rb:15:10:15:18 | call to field | type_tracker.rb:15:10:15:18 | call to field |

View File

@@ -45,9 +45,9 @@ potentiallyUnsafeSqlExecutingMethodCall
| ActiveRecordInjection.rb:75:5:75:29 | call to order |
| ActiveRecordInjection.rb:80:7:80:40 | call to find_by |
activeRecordModelInstantiations
| ActiveRecordInjection.rb:10:5:10:68 | self | ActiveRecordInjection.rb:5:1:17:3 | User |
| ActiveRecordInjection.rb:8:3:11:5 | self (authenticate) | ActiveRecordInjection.rb:5:1:17:3 | User |
| ActiveRecordInjection.rb:15:5:15:40 | call to find_by | ActiveRecordInjection.rb:1:1:3:3 | UserGroup |
| ActiveRecordInjection.rb:23:5:23:25 | self | ActiveRecordInjection.rb:19:1:25:3 | Admin |
| ActiveRecordInjection.rb:20:3:24:5 | self (delete_by) | ActiveRecordInjection.rb:19:1:25:3 | Admin |
| ActiveRecordInjection.rb:80:7:80:40 | call to find_by | ActiveRecordInjection.rb:5:1:17:3 | User |
| ActiveRecordInjection.rb:85:5:85:33 | call to find_by | ActiveRecordInjection.rb:5:1:17:3 | User |
| ActiveRecordInjection.rb:88:5:88:34 | call to find | ActiveRecordInjection.rb:5:1:17:3 | User |

View File

@@ -29,12 +29,14 @@ definition
| nested_scopes.rb:30:16:30:19 | self (class << ...) | nested_scopes.rb:30:7:33:9 | self |
| 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:1:1 | self (parameters.rb) | parameters.rb:1:1:62:1 | self |
| parameters.rb:1:9:5:3 | <captured> | 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 |
| parameters.rb:7:17:7:22 | client | parameters.rb:7:17:7:22 | client |
| 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 | <captured> | parameters.rb:15:1:19:3 | self |
| parameters.rb:16:16:16:18 | key | parameters.rb:16:16:16:18 | key |
@@ -110,6 +112,7 @@ definition
| ssa.rb:26:3:28:5 | <captured> | ssa.rb:25:1:30:3 | self |
| 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 | <captured> | 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 |