Ruby: Model flow through initialize constructors

This commit is contained in:
Tom Hvitved
2022-10-06 20:43:50 +02:00
parent 9a7628c988
commit 5d9c64ba6f
8 changed files with 393 additions and 156 deletions

View File

@@ -53,9 +53,12 @@ class Call extends Expr instanceof CallImpl {
/** Gets a potential target of this call, if any. */
final Callable getATarget() {
exists(DataFlowCall c | this = c.asCall().getExpr() |
TCfgScope(result) = [viableCallable(c), viableCallableLambda(c, _)]
exists(DataFlowCall c |
this = c.asCall().getExpr() and
TCfgScope(result) = viableCallableLambda(c, _)
)
or
result = getTarget(this.getAControlFlowNode())
}
override AstNode getAChild(string pred) {

View File

@@ -11,7 +11,8 @@ private import codeql.ruby.dataflow.SSA
newtype TReturnKind =
TNormalReturnKind() or
TBreakReturnKind()
TBreakReturnKind() or
TNewReturnKind()
/**
* Gets a node that can read the value returned from `call` with return kind
@@ -43,6 +44,15 @@ class BreakReturnKind extends ReturnKind, TBreakReturnKind {
override string toString() { result = "break" }
}
/**
* A special return kind that is used to represent the value returned
* from user-defined `new` methods as well as the effect on `self` in
* `initialize` methods.
*/
class NewReturnKind extends ReturnKind, TNewReturnKind {
override string toString() { result = "new" }
}
/** A callable defined in library code, identified by a unique string. */
abstract class LibraryCallable extends string {
bindingset[this]
@@ -275,14 +285,33 @@ private predicate hasAdjacentTypeCheckedReads(
)
}
/** Holds if `new` is a user-defined `self.new` method. */
predicate isUserDefinedNew(SingletonMethod new) {
exists(Expr object | singletonMethod(new, "new", object) |
selfInModule(object.(SelfVariableReadAccess).getVariable(), _)
or
exists(resolveConstantReadAccess(object))
)
}
private Callable viableSourceCallableNonInit(RelevantCall call) {
result = getTarget(call) and
not call.getExpr() instanceof YieldCall // handled by `lambdaCreation`/`lambdaCall`
}
private Callable viableSourceCallableInit(RelevantCall call) {
result = getInitializeTarget(call) and
not isUserDefinedNew(getTarget(call))
}
/** Holds if `call` may resolve to the returned source-code method. */
private DataFlowCallable viableSourceCallable(DataFlowCall call) {
result = TCfgScope(getTarget(call.asCall())) and
not call.asCall().getExpr() instanceof YieldCall // handled by `lambdaCreation`/`lambdaCall`
private Callable viableSourceCallable(RelevantCall call) {
result = viableSourceCallableNonInit(call) or
result = viableSourceCallableInit(call)
}
/** Holds if `call` may resolve to the returned summarized library method. */
private DataFlowCallable viableLibraryCallable(DataFlowCall call) {
DataFlowCallable viableLibraryCallable(DataFlowCall call) {
exists(LibraryCallable callable |
result = TLibraryCallable(callable) and
call.asCall().getExpr() = [callable.getACall(), callable.getACallSimple()]
@@ -340,126 +369,22 @@ private module Cached {
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
}
pragma[nomagic]
private Method lookupInstanceMethodCall(RelevantCall call, string method, boolean exact) {
exists(Module tp, DataFlow::Node receiver |
methodCall(call, pragma[only_bind_into](receiver), pragma[only_bind_into](method)) and
receiver = trackInstance(tp, exact) and
result = lookupMethod(tp, pragma[only_bind_into](method), exact)
)
}
pragma[nomagic]
private predicate isToplevelMethodInFile(Method m, File f) {
m.getEnclosingModule() instanceof Toplevel and
f = m.getFile()
}
/** Holds if a `self` access may be the receiver of `call` directly inside module `m`. */
pragma[nomagic]
private predicate selfInModuleFlowsToMethodCallReceiver(RelevantCall call, Module m, string method) {
exists(SsaSelfDefinitionNode self |
flowsToMethodCallReceiver(call, self, method) and
selfInModule(self.getVariable(), m)
)
}
/**
* Holds if a `self` access may be the receiver of `call` inside some singleton method, where
* that method belongs to `m` or one of `m`'s transitive super classes.
* Gets the relevant `initialize` method for the `new` call, if any.
*/
pragma[nomagic]
private predicate selfInSingletonMethodFlowsToMethodCallReceiver(
RelevantCall call, Module m, string method
) {
exists(SsaSelfDefinitionNode self, MethodBase caller |
flowsToMethodCallReceiver(call, self, method) and
selfInMethod(self.getVariable(), caller, m) and
singletonMethod(caller, _, _)
cached
Method getInitializeTarget(RelevantCall new) {
exists(Module m |
moduleFlowsToMethodCallReceiver(new, m, "new") and
result = lookupMethod(m, "initialize")
)
}
cached
CfgScope getTarget(RelevantCall call) {
exists(string method |
exists(boolean exact |
result = lookupInstanceMethodCall(call, method, exact) and
(
if result.(Method).isPrivate()
then
call.getReceiver().getExpr() instanceof SelfVariableAccess and
// For now, we restrict the scope of top-level declarations to their file.
// This may remove some plausible targets, but also removes a lot of
// implausible targets
(
isToplevelMethodInFile(result, call.getFile()) or
not isToplevelMethodInFile(result, _)
)
else any()
) and
if result.(Method).isProtected()
then result = lookupMethod(call.getExpr().getEnclosingModule().getModule(), method, exact)
else any()
)
or
// singleton method defined on an instance, e.g.
// ```rb
// c = C.new
// def c.singleton; end # <- result
// c.singleton # <- call
// ```
// or an `extend`ed instance, e.g.
// ```rb
// c = C.new
// module M
// def instance; end # <- result
// end
// c.extend M
// c.instance # <- call
// ```
exists(DataFlow::Node receiver |
methodCall(call, receiver, method) and
receiver = trackSingletonMethodOnInstance(result, method)
)
or
// singleton method defined on a module
// or an `extend`ed module, e.g.
// ```rb
// module M
// def instance; end # <- result
// end
// M.extend(M)
// M.instance # <- call
// ```
exists(Module m, boolean exact | result = lookupSingletonMethod(m, method, exact) |
// ```rb
// def C.singleton; end # <- result
// C.singleton # <- call
// ```
moduleFlowsToMethodCallReceiver(call, m, method) and
exact = true
or
// ```rb
// class C
// def self.singleton; end # <- result
// self.singleton # <- call
// end
// ```
selfInModuleFlowsToMethodCallReceiver(call, m, method) and
exact = true
or
// ```rb
// class C
// def self.singleton; end # <- result
// def self.other
// self.singleton # <- call
// end
// end
// ```
selfInSingletonMethodFlowsToMethodCallReceiver(call, m, method) and
exact = false
)
)
result = getTargetInstance(call, _)
or
result = getTargetSingleton(call, _)
or
exists(Module cls, string method |
superCall(call, cls, method) and
@@ -472,7 +397,7 @@ private module Cached {
/** Gets a viable run-time target for the call `call`. */
cached
DataFlowCallable viableCallable(DataFlowCall call) {
result = viableSourceCallable(call)
result.asCallable() = viableSourceCallable(call.asCall())
or
result = viableLibraryCallable(call)
}
@@ -547,6 +472,12 @@ private DataFlow::LocalSourceNode trackModuleAccess(Module m) {
result = trackModuleAccess(m, TypeTracker::end())
}
pragma[nomagic]
private predicate hasUserDefinedSelf(Module m) {
// cannot use `lookupSingletonMethod` due to negative recursion
singletonMethodOnModule(_, "new", m.getSuperClass*()) // not `getAnAncestor` because singleton methods cannot be included
}
/** Holds if `n` is an instance of type `tp`. */
private predicate isInstance(DataFlow::Node n, Module tp, boolean exact) {
n.asExpr().getExpr() instanceof NilLiteral and
@@ -603,7 +534,9 @@ private predicate isInstance(DataFlow::Node n, Module tp, boolean exact) {
or
exists(RelevantCall call, DataFlow::LocalSourceNode sourceNode |
flowsToMethodCallReceiver(call, sourceNode, "new") and
n.asExpr() = call
n.asExpr() = call and
// `tp` should not have a user-defined `self.new` method
not hasUserDefinedSelf(tp)
|
// `C.new`
sourceNode = trackModuleAccess(tp) and
@@ -702,6 +635,44 @@ private DataFlow::Node trackInstance(Module tp, boolean exact) {
result = trackInstance(tp, exact, TypeTracker::end())
}
pragma[nomagic]
private Method lookupInstanceMethodCall(RelevantCall call, string method, boolean exact) {
exists(Module tp, DataFlow::Node receiver |
methodCall(call, pragma[only_bind_into](receiver), pragma[only_bind_into](method)) and
receiver = trackInstance(tp, exact) and
result = lookupMethod(tp, pragma[only_bind_into](method), exact)
)
}
pragma[nomagic]
private predicate isToplevelMethodInFile(Method m, File f) {
m.getEnclosingModule() instanceof Toplevel and
f = m.getFile()
}
pragma[nomagic]
private CfgScope getTargetInstance(RelevantCall call, string method) {
exists(boolean exact |
result = lookupInstanceMethodCall(call, method, exact) and
(
if result.(Method).isPrivate()
then
call.getReceiver().getExpr() instanceof SelfVariableAccess and
// For now, we restrict the scope of top-level declarations to their file.
// This may remove some plausible targets, but also removes a lot of
// implausible targets
(
isToplevelMethodInFile(result, call.getFile()) or
not isToplevelMethodInFile(result, _)
)
else any()
) and
if result.(Method).isProtected()
then result = lookupMethod(call.getExpr().getEnclosingModule().getModule(), method, exact)
else any()
)
}
pragma[nomagic]
private DataFlow::LocalSourceNode trackBlock(Block block, TypeTracker t) {
t.start() and result.asExpr().getExpr() = block
@@ -813,7 +784,7 @@ private MethodBase lookupSingletonMethod(Module m, string name) {
// cannot use `lookupSingletonMethodDirect` because it would introduce
// negative recursion
not singletonMethodOnModule(_, name, m) and
result = lookupSingletonMethod(m.getSuperClass(), name)
result = lookupSingletonMethod(m.getSuperClass(), name) // not `getAnImmediateAncestor` because singleton methods cannot be included
}
pragma[nomagic]
@@ -824,7 +795,9 @@ private MethodBase lookupSingletonMethodInSubClasses(Module m, string name) {
// being resolved to arbitrary singleton methods.
// To remedy this, we do not allow following super-classes all the way to Object.
not m = TResolved("Object") and
exists(Module sub | sub.getSuperClass() = m |
exists(Module sub |
sub.getSuperClass() = m // not `getAnImmediateAncestor` because singleton methods cannot be included
|
result = lookupSingletonMethodDirect(sub, name) or
result = lookupSingletonMethodInSubClasses(sub, name)
)
@@ -972,6 +945,91 @@ private DataFlow::Node trackSingletonMethodOnInstance(MethodBase method, string
result = trackSingletonMethodOnInstance(method, name, TypeTracker::end())
}
/** Holds if a `self` access may be the receiver of `call` directly inside module `m`. */
pragma[nomagic]
private predicate selfInModuleFlowsToMethodCallReceiver(RelevantCall call, Module m, string method) {
exists(SsaSelfDefinitionNode self |
flowsToMethodCallReceiver(call, self, method) and
selfInModule(self.getVariable(), m)
)
}
/**
* Holds if a `self` access may be the receiver of `call` inside some singleton method, where
* that method belongs to `m` or one of `m`'s transitive super classes.
*/
pragma[nomagic]
private predicate selfInSingletonMethodFlowsToMethodCallReceiver(
RelevantCall call, Module m, string method
) {
exists(SsaSelfDefinitionNode self, MethodBase caller |
flowsToMethodCallReceiver(call, self, method) and
selfInMethod(self.getVariable(), caller, m) and
singletonMethod(caller, _, _)
)
}
pragma[nomagic]
private CfgScope getTargetSingleton(RelevantCall call, string method) {
// singleton method defined on an instance, e.g.
// ```rb
// c = C.new
// def c.singleton; end # <- result
// c.singleton # <- call
// ```
// or an `extend`ed instance, e.g.
// ```rb
// c = C.new
// module M
// def instance; end # <- result
// end
// c.extend M
// c.instance # <- call
// ```
exists(DataFlow::Node receiver |
methodCall(call, receiver, method) and
receiver = trackSingletonMethodOnInstance(result, method)
)
or
// singleton method defined on a module
// or an `extend`ed module, e.g.
// ```rb
// module M
// def instance; end # <- result
// end
// M.extend(M)
// M.instance # <- call
// ```
exists(Module m, boolean exact | result = lookupSingletonMethod(m, method, exact) |
// ```rb
// def C.singleton; end # <- result
// C.singleton # <- call
// ```
moduleFlowsToMethodCallReceiver(call, m, method) and
exact = true
or
// ```rb
// class C
// def self.singleton; end # <- result
// self.singleton # <- call
// end
// ```
selfInModuleFlowsToMethodCallReceiver(call, m, method) and
exact = true
or
// ```rb
// class C
// def self.singleton; end # <- result
// def self.other
// self.singleton # <- call
// end
// end
// ```
selfInSingletonMethodFlowsToMethodCallReceiver(call, m, method) and
exact = false
)
}
/**
* Holds if `ctx` targets `encl`, which is the enclosing callable of `call`, the receiver
* of `call` is a parameter access, where the corresponding argument of `ctx` is `arg`.
@@ -982,25 +1040,54 @@ private DataFlow::Node trackSingletonMethodOnInstance(MethodBase method, string
*/
pragma[nomagic]
private predicate argMustFlowToReceiver(
RelevantCall ctx, DataFlow::LocalSourceNode source, ArgumentNode arg,
RelevantCall ctx, DataFlow::LocalSourceNode source, DataFlow::Node arg,
SsaDefinitionExtNode paramDef, RelevantCall call, Callable encl, string name
) {
exists(ParameterNodeImpl p, ParameterPosition ppos, ArgumentPosition apos |
// the receiver of `call` references `p`
exists(DataFlow::Node receiver |
LocalFlow::localFlowSsaParamInput(p, paramDef) and
methodCall(pragma[only_bind_into](call), receiver, pragma[only_bind_into](name)) and
methodCall(pragma[only_bind_into](call), pragma[only_bind_into](receiver),
pragma[only_bind_into](name)) and
receiver.asExpr() = paramDef.getDefinitionExt().(Ssa::Definition).getARead()
) and
// `p` is a parameter of `encl`,
encl = call.getScope() and
p.isParameterOf(TCfgScope(encl), ppos) and
// `ctx` targets `encl`
getTarget(ctx) = encl and
// `arg` is the argument for `p` in the call `ctx`
arg.sourceArgumentOf(ctx, apos) and
parameterMatch(ppos, apos) and
source.flowsTo(arg)
|
encl = viableSourceCallableNonInit(ctx) and
arg.(ArgumentNode).sourceArgumentOf(ctx, apos)
or
encl = viableSourceCallableInit(ctx) and
if apos.isSelf()
then
// when we are targeting an initializer, the type of `self` inside the
// initializer will be the type of the `new` call itself, not the receiver
// of the `new` call
arg.asExpr() = ctx
else arg.(ArgumentNode).sourceArgumentOf(ctx, apos)
)
}
/**
* Holds if `ctx` targets `encl`, which is the enclosing callable of `new`, and
* the receiver of `new` is a parameter access, where the corresponding argument
* `arg` of `ctx` has type `tp`.
*
* `new` calls the object creation `new` method.
*/
pragma[nomagic]
private predicate mayBenefitFromCallContextInitialize(
RelevantCall ctx, RelevantCall new, DataFlow::Node arg, Callable encl, Module tp, string name
) {
exists(DataFlow::LocalSourceNode source |
argMustFlowToReceiver(ctx, pragma[only_bind_into](source), arg, _, new, encl, "new") and
source = trackModuleAccess(tp) and
name = "initialize" and
exists(lookupMethod(tp, name))
)
}
@@ -1014,7 +1101,7 @@ private predicate argMustFlowToReceiver(
*/
pragma[nomagic]
private predicate mayBenefitFromCallContextInstance(
RelevantCall ctx, RelevantCall call, ArgumentNode arg, Callable encl, Module tp, boolean exact,
RelevantCall ctx, RelevantCall call, DataFlow::Node arg, Callable encl, Module tp, boolean exact,
string name
) {
exists(DataFlow::LocalSourceNode source |
@@ -1035,7 +1122,7 @@ private predicate mayBenefitFromCallContextInstance(
*/
pragma[nomagic]
private predicate mayBenefitFromCallContextSingleton(
RelevantCall ctx, RelevantCall call, ArgumentNode arg, Callable encl, Module tp, boolean exact,
RelevantCall ctx, RelevantCall call, DataFlow::Node arg, Callable encl, Module tp, boolean exact,
string name
) {
exists(DataFlow::LocalSourceNode source |
@@ -1066,6 +1153,8 @@ private predicate mayBenefitFromCallContextSingleton(
* the implicit `self` parameter).
*/
predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) {
mayBenefitFromCallContextInitialize(_, call.asCall(), _, c.asCallable(), _, _)
or
mayBenefitFromCallContextInstance(_, call.asCall(), _, c.asCallable(), _, _, _)
or
mayBenefitFromCallContextSingleton(_, call.asCall(), _, c.asCallable(), _, _, _)
@@ -1083,30 +1172,39 @@ DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
exists(RelevantCall call0, Callable res |
call0 = call.asCall() and
res = result.asCallable() and
result = viableSourceCallable(call) and // make sure to not include e.g. private methods
exists(Module m, boolean exact, string name |
mayBenefitFromCallContextInstance(ctx.asCall(), pragma[only_bind_into](call0), _, _,
pragma[only_bind_into](m), exact, pragma[only_bind_into](name)) and
res = lookupMethod(m, name, exact)
exists(Module m, string name |
mayBenefitFromCallContextInitialize(ctx.asCall(), pragma[only_bind_into](call0), _, _,
pragma[only_bind_into](m), pragma[only_bind_into](name)) and
res = getTargetInstance(call0, name) and
res = lookupMethod(m, name)
or
mayBenefitFromCallContextSingleton(ctx.asCall(), pragma[only_bind_into](call0), _, _,
pragma[only_bind_into](m), exact, pragma[only_bind_into](name)) and
res = lookupSingletonMethod(m, name, exact)
exists(boolean exact |
mayBenefitFromCallContextInstance(ctx.asCall(), pragma[only_bind_into](call0), _, _,
pragma[only_bind_into](m), pragma[only_bind_into](exact), pragma[only_bind_into](name)) and
res = getTargetInstance(call0, name) and
res = lookupMethod(m, name, exact)
or
mayBenefitFromCallContextSingleton(ctx.asCall(), pragma[only_bind_into](call0), _, _,
pragma[only_bind_into](m), pragma[only_bind_into](exact), pragma[only_bind_into](name)) and
res = getTargetSingleton(call0, name) and
res = lookupSingletonMethod(m, name, exact)
)
)
)
or
// `ctx` cannot provide a type bound, and the receiver of the call is `self`;
// in this case, still apply an open-world assumption
exists(
RelevantCall call0, RelevantCall ctx0, ArgumentNode arg, SsaSelfDefinitionNode self,
RelevantCall call0, RelevantCall ctx0, DataFlow::Node arg, SsaSelfDefinitionNode self,
string name
|
call0 = call.asCall() and
ctx0 = ctx.asCall() and
argMustFlowToReceiver(ctx0, _, arg, self, call0, _, name) and
not mayBenefitFromCallContextInitialize(ctx0, call0, arg, _, _, _) and
not mayBenefitFromCallContextInstance(ctx0, call0, arg, _, _, _, name) and
not mayBenefitFromCallContextSingleton(ctx0, call0, arg, _, _, _, name) and
result = viableSourceCallable(call)
result.asCallable() = viableSourceCallable(call0)
)
or
// library calls should always be able to resolve

View File

@@ -828,8 +828,8 @@ import ParameterNodes
/** A data-flow node used to model flow summaries. */
class SummaryNode extends NodeImpl, TSummaryNode {
private FlowSummaryImpl::Public::SummarizedCallable c;
private FlowSummaryImpl::Private::SummaryNodeState state;
FlowSummaryImpl::Public::SummarizedCallable c;
FlowSummaryImpl::Private::SummaryNodeState state;
SummaryNode() { this = TSummaryNode(c, state) }
@@ -951,6 +951,11 @@ private module ArgumentNodes {
import ArgumentNodes
/** A call to `new`. */
private class NewCall extends DataFlowCall {
NewCall() { this.asCall().getExpr().(MethodCall).getMethodName() = "new" }
}
/** A data-flow node that represents a value syntactically returned by a callable. */
abstract class ReturningNode extends Node {
/** Gets the kind of this return node. */
@@ -994,7 +999,12 @@ private module ReturnNodes {
override ReturnKind getKind() {
if n.getNode() instanceof BreakStmt
then result instanceof BreakReturnKind
else result instanceof NormalReturnKind
else
exists(CfgScope scope | scope = this.getCfgScope() |
if isUserDefinedNew(scope)
then result instanceof NewReturnKind
else result instanceof NormalReturnKind
)
}
}
@@ -1018,7 +1028,42 @@ private module ReturnNodes {
class ExprReturnNode extends ReturningNode, ExprNode {
ExprReturnNode() { exists(Callable c | implicitReturn(c, this) = c.getAStmt()) }
override ReturnKind getKind() { result instanceof NormalReturnKind }
override ReturnKind getKind() {
exists(CfgScope scope | scope = this.(NodeImpl).getCfgScope() |
if isUserDefinedNew(scope)
then result instanceof NewReturnKind
else result instanceof NormalReturnKind
)
}
}
/**
* A `self` node inside an `initialize` method through which data may return.
*
* For example, in
*
* ```rb
* class C
* def initialize(x)
* @x = x
* end
* end
* ```
*
* the implicit `self` reference in `@x` will return data stored in the field
* `x` out to the call `C.new`.
*/
class InitializeReturnNode extends ExprPostUpdateNode, ReturningNode {
InitializeReturnNode() {
exists(Method initialize |
this.getCfgScope() = initialize and
initialize.getName() = "initialize" and
initialize = any(ClassDeclaration c).getAMethod() and
this.getPreUpdateNode().asExpr().getExpr() instanceof SelfVariableReadAccess
)
}
override ReturnKind getKind() { result instanceof NewReturnKind }
}
/**
@@ -1054,7 +1099,14 @@ private module ReturnNodes {
SummaryReturnNode() { FlowSummaryImpl::Private::summaryReturnNode(this, rk) }
override ReturnKind getKind() { result = rk }
override ReturnKind getKind() {
result = rk
or
exists(NewCall new |
TLibraryCallable(c) = viableLibraryCallable(new) and
result instanceof NewReturnKind
)
}
}
}
@@ -1078,7 +1130,9 @@ private module OutNodes {
override DataFlowCall getCall(ReturnKind kind) {
result = call and
kind instanceof NormalReturnKind
if call instanceof NewCall
then kind instanceof NewReturnKind
else kind instanceof NormalReturnKind
}
}

View File

@@ -79,10 +79,15 @@ predicate jumpStep = DataFlowPrivate::jumpStep/2;
/** Holds if there is direct flow from `param` to a return. */
pragma[nomagic]
private predicate flowThrough(DataFlowPublic::ParameterNode param) {
exists(DataFlowPrivate::ReturningNode returnNode |
exists(DataFlowPrivate::ReturningNode returnNode, DataFlowDispatch::ReturnKind rk |
DataFlowPrivate::LocalFlow::getParameterDefNode(param.getParameter())
.(TypeTrackingNode)
.flowsTo(returnNode)
.flowsTo(returnNode) and
rk = returnNode.getKind()
|
rk instanceof DataFlowDispatch::NormalReturnKind
or
rk instanceof DataFlowDispatch::BreakReturnKind
)
}
@@ -184,7 +189,9 @@ private predicate viableParam(
DataFlowDispatch::ParameterPosition ppos
) {
exists(Cfg::CfgScope callable |
DataFlowDispatch::getTarget(call) = callable and
DataFlowDispatch::getTarget(call) = callable or
DataFlowDispatch::getInitializeTarget(call) = callable
|
p.isSourceParameterOf(callable, ppos)
)
}
@@ -226,6 +233,9 @@ predicate returnStep(Node nodeFrom, Node nodeTo) {
exists(ExprNodes::CallCfgNode call |
nodeFrom instanceof DataFlowPrivate::ReturnNode and
nodeFrom.(DataFlowPrivate::NodeImpl).getCfgScope() = DataFlowDispatch::getTarget(call) and
// deliberately do not include `getInitializeTarget`, since there is no direct
// flow out (only side-effects on `self`). Any fields being set in the initializer
// will reach all reads via `callStep` and `localFieldStep`.
nodeTo.asExpr().getNode() = call.getNode()
)
or
@@ -233,7 +243,8 @@ predicate returnStep(Node nodeFrom, Node nodeTo) {
// we model it as a returning flow 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::SynthReturnNode).getAnInput() = nodeFrom
nodeTo.(DataFlowPrivate::SynthReturnNode).getAnInput() = nodeFrom and
not nodeFrom instanceof DataFlowPrivate::InitializeReturnNode
}
/**

View File

@@ -12,6 +12,7 @@
import codeql.ruby.AST
import codeql.ruby.dataflow.SSA
import codeql.ruby.dataflow.internal.DataFlowDispatch
from DefLoc loc, Expr src, Expr target, string kind
where
@@ -38,7 +39,12 @@ newtype DefLoc =
write = definitionOf(read.getAQualifiedName())
} or
/** A method call. */
MethodLoc(MethodCall call, Method meth) { meth = call.getATarget() } or
MethodLoc(MethodCall call, Method meth) {
meth = call.getATarget()
or
// include implicit `initialize` calls
meth = getInitializeTarget(call.getAControlFlowNode())
} or
/** A local variable. */
LocalVariableLoc(VariableReadAccess read, VariableWriteAccess write) {
exists(Ssa::WriteDefinition w |

View File

@@ -1,8 +1,5 @@
failures
| call_sensitivity.rb:51:12:51:148 | # $ hasValueFlow=10 $ hasValueFlow=11 $ hasValueFlow=12 $ hasValueFlow=13 $ hasValueFlow=26 $ hasValueFlow=30 $ SPURIOUS: hasValueFlow=27 | Missing result:hasValueFlow=30 |
| call_sensitivity.rb:97:12:97:66 | # $ hasValueFlow=26 $ hasValueFlow=30 $ hasValueFlow=32 | Missing result:hasValueFlow=26 |
| call_sensitivity.rb:97:12:97:66 | # $ hasValueFlow=26 $ hasValueFlow=30 $ hasValueFlow=32 | Missing result:hasValueFlow=30 |
| call_sensitivity.rb:97:12:97:66 | # $ hasValueFlow=26 $ hasValueFlow=30 $ hasValueFlow=32 | Missing result:hasValueFlow=32 |
edges
| call_sensitivity.rb:9:7:9:13 | call to taint : | call_sensitivity.rb:9:6:9:14 | ( ... ) |
| call_sensitivity.rb:9:7:9:13 | call to taint : | call_sensitivity.rb:9:6:9:14 | ( ... ) |
@@ -96,6 +93,18 @@ edges
| call_sensitivity.rb:92:35:92:35 | x : | call_sensitivity.rb:93:34:93:34 | x : |
| call_sensitivity.rb:93:34:93:34 | x : | call_sensitivity.rb:88:33:88:33 | y : |
| call_sensitivity.rb:93:34:93:34 | x : | call_sensitivity.rb:88:33:88:33 | y : |
| call_sensitivity.rb:96:18:96:18 | x : | call_sensitivity.rb:97:10:97:10 | x |
| call_sensitivity.rb:96:18:96:18 | x : | call_sensitivity.rb:97:10:97:10 | x |
| call_sensitivity.rb:96:18:96:18 | x : | call_sensitivity.rb:97:10:97:10 | x |
| call_sensitivity.rb:96:18:96:18 | x : | call_sensitivity.rb:97:10:97:10 | x |
| call_sensitivity.rb:96:18:96:18 | x : | call_sensitivity.rb:98:13:98:13 | x : |
| call_sensitivity.rb:96:18:96:18 | x : | call_sensitivity.rb:98:13:98:13 | x : |
| call_sensitivity.rb:98:13:98:13 | x : | call_sensitivity.rb:50:15:50:15 | x : |
| call_sensitivity.rb:98:13:98:13 | x : | call_sensitivity.rb:50:15:50:15 | x : |
| call_sensitivity.rb:102:11:102:20 | ( ... ) : | call_sensitivity.rb:96:18:96:18 | x : |
| call_sensitivity.rb:102:11:102:20 | ( ... ) : | call_sensitivity.rb:96:18:96:18 | x : |
| call_sensitivity.rb:102:12:102:19 | call to taint : | call_sensitivity.rb:102:11:102:20 | ( ... ) : |
| call_sensitivity.rb:102:12:102:19 | call to taint : | call_sensitivity.rb:102:11:102:20 | ( ... ) : |
| call_sensitivity.rb:103:11:103:18 | call to taint : | call_sensitivity.rb:54:15:54:15 | x : |
| call_sensitivity.rb:103:11:103:18 | call to taint : | call_sensitivity.rb:54:15:54:15 | x : |
| call_sensitivity.rb:104:16:104:23 | call to taint : | call_sensitivity.rb:58:20:58:20 | x : |
@@ -116,6 +125,10 @@ edges
| call_sensitivity.rb:112:26:112:33 | call to taint : | call_sensitivity.rb:92:35:92:35 | x : |
| call_sensitivity.rb:149:14:149:22 | call to taint : | call_sensitivity.rb:74:18:74:18 | y : |
| call_sensitivity.rb:149:14:149:22 | call to taint : | call_sensitivity.rb:74:18:74:18 | y : |
| call_sensitivity.rb:169:11:169:20 | ( ... ) : | call_sensitivity.rb:96:18:96:18 | x : |
| call_sensitivity.rb:169:11:169:20 | ( ... ) : | call_sensitivity.rb:96:18:96:18 | x : |
| call_sensitivity.rb:169:12:169:19 | call to taint : | call_sensitivity.rb:169:11:169:20 | ( ... ) : |
| call_sensitivity.rb:169:12:169:19 | call to taint : | call_sensitivity.rb:169:11:169:20 | ( ... ) : |
nodes
| call_sensitivity.rb:9:6:9:14 | ( ... ) | semmle.label | ( ... ) |
| call_sensitivity.rb:9:6:9:14 | ( ... ) | semmle.label | ( ... ) |
@@ -223,6 +236,18 @@ nodes
| call_sensitivity.rb:92:35:92:35 | x : | semmle.label | x : |
| call_sensitivity.rb:93:34:93:34 | x : | semmle.label | x : |
| call_sensitivity.rb:93:34:93:34 | x : | semmle.label | x : |
| call_sensitivity.rb:96:18:96:18 | x : | semmle.label | x : |
| call_sensitivity.rb:96:18:96:18 | x : | semmle.label | x : |
| call_sensitivity.rb:96:18:96:18 | x : | semmle.label | x : |
| call_sensitivity.rb:96:18:96:18 | x : | semmle.label | x : |
| call_sensitivity.rb:97:10:97:10 | x | semmle.label | x |
| call_sensitivity.rb:97:10:97:10 | x | semmle.label | x |
| call_sensitivity.rb:98:13:98:13 | x : | semmle.label | x : |
| call_sensitivity.rb:98:13:98:13 | x : | semmle.label | x : |
| call_sensitivity.rb:102:11:102:20 | ( ... ) : | semmle.label | ( ... ) : |
| call_sensitivity.rb:102:11:102:20 | ( ... ) : | semmle.label | ( ... ) : |
| call_sensitivity.rb:102:12:102:19 | call to taint : | semmle.label | call to taint : |
| call_sensitivity.rb:102:12:102:19 | call to taint : | semmle.label | call to taint : |
| call_sensitivity.rb:103:11:103:18 | call to taint : | semmle.label | call to taint : |
| call_sensitivity.rb:103:11:103:18 | call to taint : | semmle.label | call to taint : |
| call_sensitivity.rb:104:16:104:23 | call to taint : | semmle.label | call to taint : |
@@ -243,6 +268,10 @@ nodes
| call_sensitivity.rb:112:26:112:33 | call to taint : | semmle.label | call to taint : |
| call_sensitivity.rb:149:14:149:22 | call to taint : | semmle.label | call to taint : |
| call_sensitivity.rb:149:14:149:22 | call to taint : | semmle.label | call to taint : |
| call_sensitivity.rb:169:11:169:20 | ( ... ) : | semmle.label | ( ... ) : |
| call_sensitivity.rb:169:11:169:20 | ( ... ) : | semmle.label | ( ... ) : |
| call_sensitivity.rb:169:12:169:19 | call to taint : | semmle.label | call to taint : |
| call_sensitivity.rb:169:12:169:19 | call to taint : | semmle.label | call to taint : |
subpaths
#select
| call_sensitivity.rb:9:6:9:14 | ( ... ) | call_sensitivity.rb:9:7:9:13 | call to taint : | call_sensitivity.rb:9:6:9:14 | ( ... ) | $@ | call_sensitivity.rb:9:7:9:13 | call to taint : | call to taint : |
@@ -250,6 +279,7 @@ subpaths
| call_sensitivity.rb:31:27:31:27 | x | call_sensitivity.rb:32:25:32:32 | call to taint : | call_sensitivity.rb:31:27:31:27 | x | $@ | call_sensitivity.rb:32:25:32:32 | call to taint : | call to taint : |
| call_sensitivity.rb:40:31:40:31 | x | call_sensitivity.rb:41:25:41:32 | call to taint : | call_sensitivity.rb:40:31:40:31 | x | $@ | call_sensitivity.rb:41:25:41:32 | call to taint : | call to taint : |
| call_sensitivity.rb:43:32:43:32 | x | call_sensitivity.rb:44:26:44:33 | call to taint : | call_sensitivity.rb:43:32:43:32 | x | $@ | call_sensitivity.rb:44:26:44:33 | call to taint : | call to taint : |
| call_sensitivity.rb:51:10:51:10 | x | call_sensitivity.rb:102:12:102:19 | call to taint : | call_sensitivity.rb:51:10:51:10 | x | $@ | call_sensitivity.rb:102:12:102:19 | call to taint : | call to taint : |
| call_sensitivity.rb:51:10:51:10 | x | call_sensitivity.rb:103:11:103:18 | call to taint : | call_sensitivity.rb:51:10:51:10 | x | $@ | call_sensitivity.rb:103:11:103:18 | call to taint : | call to taint : |
| call_sensitivity.rb:51:10:51:10 | x | call_sensitivity.rb:104:16:104:23 | call to taint : | call_sensitivity.rb:51:10:51:10 | x | $@ | call_sensitivity.rb:104:16:104:23 | call to taint : | call to taint : |
| call_sensitivity.rb:51:10:51:10 | x | call_sensitivity.rb:105:14:105:22 | call to taint : | call_sensitivity.rb:51:10:51:10 | x | $@ | call_sensitivity.rb:105:14:105:22 | call to taint : | call to taint : |
@@ -260,6 +290,8 @@ subpaths
| call_sensitivity.rb:71:10:71:10 | x | call_sensitivity.rb:110:26:110:33 | call to taint : | call_sensitivity.rb:71:10:71:10 | x | $@ | call_sensitivity.rb:110:26:110:33 | call to taint : | call to taint : |
| call_sensitivity.rb:71:10:71:10 | x | call_sensitivity.rb:111:24:111:32 | call to taint : | call_sensitivity.rb:71:10:71:10 | x | $@ | call_sensitivity.rb:111:24:111:32 | call to taint : | call to taint : |
| call_sensitivity.rb:71:10:71:10 | x | call_sensitivity.rb:112:26:112:33 | call to taint : | call_sensitivity.rb:71:10:71:10 | x | $@ | call_sensitivity.rb:112:26:112:33 | call to taint : | call to taint : |
| call_sensitivity.rb:97:10:97:10 | x | call_sensitivity.rb:102:12:102:19 | call to taint : | call_sensitivity.rb:97:10:97:10 | x | $@ | call_sensitivity.rb:102:12:102:19 | call to taint : | call to taint : |
| call_sensitivity.rb:97:10:97:10 | x | call_sensitivity.rb:169:12:169:19 | call to taint : | call_sensitivity.rb:97:10:97:10 | x | $@ | call_sensitivity.rb:169:12:169:19 | call to taint : | call to taint : |
mayBenefitFromCallContext
| call_sensitivity.rb:51:5:51:10 | call to sink | call_sensitivity.rb:50:3:52:5 | method1 |
| call_sensitivity.rb:55:5:55:13 | call to method1 | call_sensitivity.rb:54:3:56:5 | method2 |
@@ -270,10 +302,13 @@ mayBenefitFromCallContext
| call_sensitivity.rb:85:5:85:28 | call to singleton_method2 | call_sensitivity.rb:84:3:86:5 | call_singleton_method2 |
| call_sensitivity.rb:89:5:89:26 | call to singleton_method1 | call_sensitivity.rb:88:3:90:5 | singleton_method3 |
| call_sensitivity.rb:93:5:93:35 | call to singleton_method3 | call_sensitivity.rb:92:3:94:5 | call_singleton_method3 |
| call_sensitivity.rb:97:5:97:10 | call to sink | call_sensitivity.rb:96:3:99:5 | initialize |
| call_sensitivity.rb:98:5:98:13 | call to method1 | call_sensitivity.rb:96:3:99:5 | initialize |
| call_sensitivity.rb:124:5:124:18 | call to method2 | call_sensitivity.rb:123:3:125:5 | call_method2 |
| call_sensitivity.rb:128:5:128:25 | call to method3 | call_sensitivity.rb:127:3:129:5 | call_method3 |
| call_sensitivity.rb:132:5:132:28 | call to singleton_method2 | call_sensitivity.rb:131:3:133:5 | call_singleton_method2 |
| call_sensitivity.rb:136:5:136:35 | call to singleton_method3 | call_sensitivity.rb:135:3:137:5 | call_singleton_method3 |
| call_sensitivity.rb:157:3:157:12 | call to new | call_sensitivity.rb:156:1:158:3 | create |
viableImplInCallContext
| call_sensitivity.rb:51:5:51:10 | call to sink | call_sensitivity.rb:55:5:55:13 | call to method1 | call_sensitivity.rb:5:1:7:3 | sink |
| call_sensitivity.rb:51:5:51:10 | call to sink | call_sensitivity.rb:63:5:63:16 | call to method1 | call_sensitivity.rb:5:1:7:3 | sink |
@@ -305,6 +340,13 @@ viableImplInCallContext
| call_sensitivity.rb:89:5:89:26 | call to singleton_method1 | call_sensitivity.rb:136:5:136:35 | call to singleton_method3 | call_sensitivity.rb:119:3:121:5 | singleton_method1 |
| call_sensitivity.rb:89:5:89:26 | call to singleton_method1 | call_sensitivity.rb:153:1:153:33 | call to singleton_method3 | call_sensitivity.rb:119:3:121:5 | singleton_method1 |
| call_sensitivity.rb:93:5:93:35 | call to singleton_method3 | call_sensitivity.rb:112:1:112:34 | call to call_singleton_method3 | call_sensitivity.rb:88:3:90:5 | singleton_method3 |
| call_sensitivity.rb:97:5:97:10 | call to sink | call_sensitivity.rb:102:5:102:20 | call to new | call_sensitivity.rb:5:1:7:3 | sink |
| call_sensitivity.rb:97:5:97:10 | call to sink | call_sensitivity.rb:157:3:157:12 | call to new | call_sensitivity.rb:5:1:7:3 | sink |
| call_sensitivity.rb:97:5:97:10 | call to sink | call_sensitivity.rb:169:5:169:20 | call to new | call_sensitivity.rb:5:1:7:3 | sink |
| call_sensitivity.rb:98:5:98:13 | call to method1 | call_sensitivity.rb:102:5:102:20 | call to new | call_sensitivity.rb:50:3:52:5 | method1 |
| call_sensitivity.rb:98:5:98:13 | call to method1 | call_sensitivity.rb:157:3:157:12 | call to new | call_sensitivity.rb:50:3:52:5 | method1 |
| call_sensitivity.rb:98:5:98:13 | call to method1 | call_sensitivity.rb:157:3:157:12 | call to new | call_sensitivity.rb:115:3:117:5 | method1 |
| call_sensitivity.rb:98:5:98:13 | call to method1 | call_sensitivity.rb:169:5:169:20 | call to new | call_sensitivity.rb:164:3:166:5 | method1 |
| call_sensitivity.rb:124:5:124:18 | call to method2 | call_sensitivity.rb:146:1:146:24 | call to call_method2 | call_sensitivity.rb:54:3:56:5 | method2 |
| call_sensitivity.rb:128:5:128:25 | call to method3 | call_sensitivity.rb:148:1:148:25 | call to call_method3 | call_sensitivity.rb:62:3:64:5 | method3 |
| call_sensitivity.rb:132:5:132:28 | call to singleton_method2 | call_sensitivity.rb:152:1:152:34 | call to call_singleton_method2 | call_sensitivity.rb:80:3:82:5 | singleton_method2 |

View File

@@ -1,5 +1,4 @@
failures
| instance_variables.rb:102:23:102:41 | # $ hasValueFlow=29 | Missing result:hasValueFlow=29 |
edges
| captured_variables.rb:1:24:1:24 | x : | captured_variables.rb:2:20:2:20 | x |
| captured_variables.rb:1:24:1:24 | x : | captured_variables.rb:2:20:2:20 | x |
@@ -180,6 +179,16 @@ edges
| instance_variables.rb:99:6:99:10 | foo13 [@field] : | instance_variables.rb:13:5:15:7 | self in get_field [@field] : |
| instance_variables.rb:99:6:99:10 | foo13 [@field] : | instance_variables.rb:99:6:99:20 | call to get_field |
| instance_variables.rb:99:6:99:10 | foo13 [@field] : | instance_variables.rb:99:6:99:20 | call to get_field |
| instance_variables.rb:101:9:101:26 | call to new [@field] : | instance_variables.rb:102:6:102:10 | foo15 [@field] : |
| instance_variables.rb:101:9:101:26 | call to new [@field] : | instance_variables.rb:102:6:102:10 | foo15 [@field] : |
| instance_variables.rb:101:17:101:25 | call to taint : | instance_variables.rb:22:20:22:24 | field : |
| instance_variables.rb:101:17:101:25 | call to taint : | instance_variables.rb:22:20:22:24 | field : |
| instance_variables.rb:101:17:101:25 | call to taint : | instance_variables.rb:101:9:101:26 | call to new [@field] : |
| instance_variables.rb:101:17:101:25 | call to taint : | instance_variables.rb:101:9:101:26 | call to new [@field] : |
| instance_variables.rb:102:6:102:10 | foo15 [@field] : | instance_variables.rb:13:5:15:7 | self in get_field [@field] : |
| instance_variables.rb:102:6:102:10 | foo15 [@field] : | instance_variables.rb:13:5:15:7 | self in get_field [@field] : |
| instance_variables.rb:102:6:102:10 | foo15 [@field] : | instance_variables.rb:102:6:102:20 | call to get_field |
| instance_variables.rb:102:6:102:10 | foo15 [@field] : | instance_variables.rb:102:6:102:20 | call to get_field |
| instance_variables.rb:104:6:104:10 | [post] foo16 [@field] : | instance_variables.rb:105:6:105:10 | foo16 [@field] : |
| instance_variables.rb:104:6:104:10 | [post] foo16 [@field] : | instance_variables.rb:105:6:105:10 | foo16 [@field] : |
| instance_variables.rb:104:28:104:36 | call to taint : | instance_variables.rb:27:25:27:29 | field : |
@@ -363,6 +372,14 @@ nodes
| instance_variables.rb:99:6:99:10 | foo13 [@field] : | semmle.label | foo13 [@field] : |
| instance_variables.rb:99:6:99:20 | call to get_field | semmle.label | call to get_field |
| instance_variables.rb:99:6:99:20 | call to get_field | semmle.label | call to get_field |
| instance_variables.rb:101:9:101:26 | call to new [@field] : | semmle.label | call to new [@field] : |
| instance_variables.rb:101:9:101:26 | call to new [@field] : | semmle.label | call to new [@field] : |
| instance_variables.rb:101:17:101:25 | call to taint : | semmle.label | call to taint : |
| instance_variables.rb:101:17:101:25 | call to taint : | semmle.label | call to taint : |
| instance_variables.rb:102:6:102:10 | foo15 [@field] : | semmle.label | foo15 [@field] : |
| instance_variables.rb:102:6:102:10 | foo15 [@field] : | semmle.label | foo15 [@field] : |
| instance_variables.rb:102:6:102:20 | call to get_field | semmle.label | call to get_field |
| instance_variables.rb:102:6:102:20 | call to get_field | semmle.label | call to get_field |
| instance_variables.rb:104:6:104:10 | [post] foo16 [@field] : | semmle.label | [post] foo16 [@field] : |
| instance_variables.rb:104:6:104:10 | [post] foo16 [@field] : | semmle.label | [post] foo16 [@field] : |
| instance_variables.rb:104:6:104:37 | call to call_initialize | semmle.label | call to call_initialize |
@@ -427,6 +444,10 @@ subpaths
| instance_variables.rb:94:6:94:10 | foo12 [@field] : | instance_variables.rb:13:5:15:7 | self in get_field [@field] : | instance_variables.rb:14:9:14:21 | return : | instance_variables.rb:94:6:94:20 | call to get_field |
| instance_variables.rb:99:6:99:10 | foo13 [@field] : | instance_variables.rb:13:5:15:7 | self in get_field [@field] : | instance_variables.rb:14:9:14:21 | return : | instance_variables.rb:99:6:99:20 | call to get_field |
| instance_variables.rb:99:6:99:10 | foo13 [@field] : | instance_variables.rb:13:5:15:7 | self in get_field [@field] : | instance_variables.rb:14:9:14:21 | return : | instance_variables.rb:99:6:99:20 | call to get_field |
| instance_variables.rb:101:17:101:25 | call to taint : | instance_variables.rb:22:20:22:24 | field : | instance_variables.rb:23:9:23:14 | [post] self [@field] : | instance_variables.rb:101:9:101:26 | call to new [@field] : |
| instance_variables.rb:101:17:101:25 | call to taint : | instance_variables.rb:22:20:22:24 | field : | instance_variables.rb:23:9:23:14 | [post] self [@field] : | instance_variables.rb:101:9:101:26 | call to new [@field] : |
| instance_variables.rb:102:6:102:10 | foo15 [@field] : | instance_variables.rb:13:5:15:7 | self in get_field [@field] : | instance_variables.rb:14:9:14:21 | return : | instance_variables.rb:102:6:102:20 | call to get_field |
| instance_variables.rb:102:6:102:10 | foo15 [@field] : | instance_variables.rb:13:5:15:7 | self in get_field [@field] : | instance_variables.rb:14:9:14:21 | return : | instance_variables.rb:102:6:102:20 | call to get_field |
| instance_variables.rb:104:28:104:36 | call to taint : | instance_variables.rb:27:25:27:29 | field : | instance_variables.rb:28:9:28:25 | [post] self [@field] : | instance_variables.rb:104:6:104:10 | [post] foo16 [@field] : |
| instance_variables.rb:104:28:104:36 | call to taint : | instance_variables.rb:27:25:27:29 | field : | instance_variables.rb:28:9:28:25 | [post] self [@field] : | instance_variables.rb:104:6:104:10 | [post] foo16 [@field] : |
| instance_variables.rb:105:6:105:10 | foo16 [@field] : | instance_variables.rb:13:5:15:7 | self in get_field [@field] : | instance_variables.rb:14:9:14:21 | return : | instance_variables.rb:105:6:105:20 | call to get_field |
@@ -452,6 +473,7 @@ subpaths
| instance_variables.rb:90:6:90:20 | call to get_field | instance_variables.rb:85:17:85:25 | call to taint : | instance_variables.rb:90:6:90:20 | call to get_field | $@ | instance_variables.rb:85:17:85:25 | call to taint : | call to taint : |
| instance_variables.rb:94:6:94:20 | call to get_field | instance_variables.rb:85:17:85:25 | call to taint : | instance_variables.rb:94:6:94:20 | call to get_field | $@ | instance_variables.rb:85:17:85:25 | call to taint : | call to taint : |
| instance_variables.rb:99:6:99:20 | call to get_field | instance_variables.rb:85:17:85:25 | call to taint : | instance_variables.rb:99:6:99:20 | call to get_field | $@ | instance_variables.rb:85:17:85:25 | call to taint : | call to taint : |
| instance_variables.rb:102:6:102:20 | call to get_field | instance_variables.rb:101:17:101:25 | call to taint : | instance_variables.rb:102:6:102:20 | call to get_field | $@ | instance_variables.rb:101:17:101:25 | call to taint : | call to taint : |
| instance_variables.rb:104:6:104:37 | call to call_initialize | instance_variables.rb:24:9:24:17 | call to taint : | instance_variables.rb:104:6:104:37 | call to call_initialize | $@ | instance_variables.rb:24:9:24:17 | call to taint : | call to taint : |
| instance_variables.rb:105:6:105:20 | call to get_field | instance_variables.rb:104:28:104:36 | call to taint : | instance_variables.rb:105:6:105:20 | call to get_field | $@ | instance_variables.rb:104:28:104:36 | call to taint : | call to taint : |
| instance_variables.rb:107:6:107:8 | bar | instance_variables.rb:34:9:34:17 | call to taint : | instance_variables.rb:107:6:107:8 | bar | $@ | instance_variables.rb:34:9:34:17 | call to taint : | call to taint : |

View File

@@ -12,3 +12,4 @@
| Definitions.rb:41:7:41:9 | @@b | Definitions.rb:27:5:27:7 | @@b | class variable |
| Definitions.rb:46:1:46:1 | C | Definitions.rb:19:1:44:3 | C | constant |
| Definitions.rb:46:1:46:4 | D | Definitions.rb:26:3:43:5 | D | constant |
| Definitions.rb:46:1:46:8 | call to new | Definitions.rb:29:5:33:7 | initialize | method |