mirror of
https://github.com/github/codeql.git
synced 2026-05-04 21:25:44 +02:00
Ruby: Model flow through initialize constructors
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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 : |
|
||||
|
||||
@@ -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 |
|
||||
|
||||
Reference in New Issue
Block a user