Ruby: Reimplement flow through captured variables using field flow

This commit is contained in:
Tom Hvitved
2023-08-10 20:16:50 +02:00
parent 5d1c399371
commit 48e2dcfa35
24 changed files with 815 additions and 441 deletions

View File

@@ -11,8 +11,6 @@ private module Input implements InputSig<RubyDataFlow> {
predicate postWithInFlowExclude(Node n) { n instanceof FlowSummaryNode }
predicate argHasPostUpdateExclude(ArgumentNode n) {
n instanceof BlockArgumentNode
or
n instanceof FlowSummaryNode
or
n instanceof SynthHashSplatArgumentNode

View File

@@ -1,4 +1,5 @@
import codeql.ruby.ast.Variable
import codeql.ruby.dataflow.internal.DataFlowPrivate::VariableCapture::Flow::ConsistencyChecks
query predicate ambiguousVariable(VariableAccess access, Variable variable) {
access.getVariable() = variable and

View File

@@ -117,6 +117,17 @@ class MethodCall extends Call instanceof MethodCallImpl {
*/
final Block getBlock() { result = super.getBlockImpl() }
/**
* Gets the block argument of this method call, if any.
* ```rb
* foo(&block)
* ```
*/
final BlockArgument getBlockArgument() { result = this.getAnArgument() }
/** Holds if this method call has a block or block argument. */
final predicate hasBlock() { exists(this.getBlock()) or exists(this.getBlockArgument()) }
/**
* Holds if the safe navigation operator (`&.`) is used in this call.
* ```rb

View File

@@ -202,7 +202,10 @@ module ExprNodes {
override LhsExpr getExpr() { result = super.getExpr() }
/** Gets a variable used in (or introduced by) this LHS. */
Variable getAVariable() { result = e.(VariableAccess).getVariable() }
deprecated Variable getAVariable() { result = e.(VariableAccess).getVariable() }
/** Gets the variable used in (or introduced by) this LHS. */
Variable getVariable() { result = e.(VariableAccess).getVariable() }
}
private class AssignExprChildMapping extends ExprChildMapping, AssignExpr {

View File

@@ -1,6 +1,8 @@
/** Provides classes and predicates for defining flow summaries. */
import codeql.ruby.AST
private import codeql.ruby.CFG
private import codeql.ruby.typetracking.TypeTracker
import codeql.ruby.DataFlow
private import internal.FlowSummaryImpl as Impl
private import internal.DataFlowDispatch
@@ -158,3 +160,66 @@ abstract class SimpleSummarizedCallable extends SummarizedCallable {
}
class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack;
/**
* Provides a set of special flow summaries to ensure that callbacks passed into
* library methods will be passed as `self` arguments into themeselves. That is,
* we are assuming that callbacks passed into library methods will be called, which is
* needed for flow through captured variables.
*/
private module LibraryCallbackSummaries {
private predicate libraryCall(CfgNodes::ExprNodes::CallCfgNode call) {
not exists(getTarget(call))
}
private class LibraryBlockMethod extends SummarizedCallable {
LibraryBlockMethod() { this = "<library method accepting a block>" }
final override MethodCall getACall() {
libraryCall(result.getAControlFlowNode()) and
result.hasBlock()
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[block]" and
output = "Argument[block].Parameter[lambda-self]" and
preservesValue = true
}
}
private DataFlow::LocalSourceNode trackLambdaCreation(TypeTracker t) {
t.start() and
lambdaCreation(result, TLambdaCallKind(), _)
or
exists(TypeTracker t2 | result = trackLambdaCreation(t2).track(t2, t)) and
not result instanceof DataFlow::SelfParameterNode
}
private predicate libraryCallHasLambdaArg(CfgNodes::ExprNodes::CallCfgNode call, int i) {
exists(CfgNodes::ExprCfgNode arg |
arg = call.getArgument(i) and
arg = trackLambdaCreation(TypeTracker::end()).getALocalUse().asExpr() and
libraryCall(call) and
not arg instanceof CfgNodes::ExprNodes::BlockArgumentCfgNode
)
}
private class LibraryLambdaMethod extends SummarizedCallable {
private int i;
LibraryLambdaMethod() {
this = "<library method accepting a lambda at index " + i + ">" and
i in [0 .. 10]
}
final override MethodCall getACall() {
libraryCallHasLambdaArg(result.getAControlFlowNode(), i)
}
override predicate propagatesFlowExt(string input, string output, boolean preservesValue) {
input = "Argument[" + i + "]" and
output = "Argument[" + i + "].Parameter[lambda-self]" and
preservesValue = true
}
}
}

View File

@@ -21,8 +21,7 @@ private class SelfLocalSourceNode extends DataFlow::LocalSourceNode {
SelfLocalSourceNode() {
self = this.(SelfParameterNodeImpl).getSelfVariable()
or
self = this.(SsaSelfDefinitionNode).getVariable() and
not LocalFlow::localFlowSsaParamInput(_, this)
self = this.(SsaSelfDefinitionNode).getVariable()
}
/** Gets the `self` variable. */
@@ -424,6 +423,7 @@ private module Cached {
cached
newtype TArgumentPosition =
TSelfArgumentPosition() or
TLambdaSelfArgumentPosition() or
TBlockArgumentPosition() or
TPositionalArgumentPosition(int pos) {
exists(Call c | exists(c.getArgument(pos)))
@@ -446,6 +446,7 @@ private module Cached {
cached
newtype TParameterPosition =
TSelfParameterPosition() or
TLambdaSelfParameterPosition() or
TBlockParameterPosition() or
TPositionalParameterPosition(int pos) {
pos = any(Parameter p).getPosition()
@@ -941,20 +942,24 @@ private module TrackSingletonMethodOnInstanceInput implements CallGraphConstruct
private predicate paramReturnFlow(
DataFlow::Node nodeFrom, DataFlow::PostUpdateNode nodeTo, StepSummary summary
) {
exists(RelevantCall call, DataFlow::Node arg, DataFlow::ParameterNode p, Expr nodeFromPreExpr |
exists(
RelevantCall call, DataFlow::Node arg, DataFlow::ParameterNode p,
CfgNodes::ExprCfgNode nodeFromPreExpr
|
TypeTrackerSpecific::callStep(call, arg, p) and
nodeTo.getPreUpdateNode() = arg and
summary.toString() = "return" and
(
nodeFromPreExpr = nodeFrom.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr().getExpr()
nodeFromPreExpr = nodeFrom.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr()
or
nodeFromPreExpr = nodeFrom.asExpr().getExpr() and
singletonMethodOnInstance(_, _, nodeFromPreExpr)
nodeFromPreExpr = nodeFrom.asExpr() and
singletonMethodOnInstance(_, _, nodeFromPreExpr.getExpr())
)
|
nodeFromPreExpr = p.getParameter().(NamedParameter).getVariable().getAnAccess()
nodeFromPreExpr =
LocalFlow::getParameterDefNode(p.getParameter()).getDefinitionExt().getARead()
or
nodeFromPreExpr = p.(SelfParameterNodeImpl).getSelfVariable().getAnAccess()
nodeFromPreExpr = p.(SelfParameterNodeImpl).getSelfDefinition().getARead()
)
}
@@ -1276,6 +1281,9 @@ class ParameterPosition extends TParameterPosition {
/** Holds if this position represents a `self` parameter. */
predicate isSelf() { this = TSelfParameterPosition() }
/** Holds if this position represents a reference to a lambda itself. Only used for tracking flow through captured variables. */
predicate isLambdaSelf() { this = TLambdaSelfParameterPosition() }
/** Holds if this position represents a block parameter. */
predicate isBlock() { this = TBlockParameterPosition() }
@@ -1313,6 +1321,8 @@ class ParameterPosition extends TParameterPosition {
string toString() {
this.isSelf() and result = "self"
or
this.isLambdaSelf() and result = "lambda self"
or
this.isBlock() and result = "block"
or
exists(int pos | this.isPositional(pos) and result = "position " + pos)
@@ -1342,6 +1352,9 @@ class ArgumentPosition extends TArgumentPosition {
/** Holds if this position represents a `self` argument. */
predicate isSelf() { this = TSelfArgumentPosition() }
/** Holds if this position represents a lambda `self` argument. Only used for tracking flow through captured variables. */
predicate isLambdaSelf() { this = TLambdaSelfArgumentPosition() }
/** Holds if this position represents a block argument. */
predicate isBlock() { this = TBlockArgumentPosition() }
@@ -1374,6 +1387,8 @@ class ArgumentPosition extends TArgumentPosition {
string toString() {
this.isSelf() and result = "self"
or
this.isLambdaSelf() and result = "lambda self"
or
this.isBlock() and result = "block"
or
exists(int pos | this.isPositional(pos) and result = "position " + pos)
@@ -1393,16 +1408,24 @@ class ArgumentPosition extends TArgumentPosition {
}
pragma[nomagic]
private predicate parameterPositionIsNotSelf(ParameterPosition ppos) { not ppos.isSelf() }
private predicate parameterPositionIsNotSelf(ParameterPosition ppos) {
not ppos.isSelf() and
not ppos.isLambdaSelf()
}
pragma[nomagic]
private predicate argumentPositionIsNotSelf(ArgumentPosition apos) { not apos.isSelf() }
private predicate argumentPositionIsNotSelf(ArgumentPosition apos) {
not apos.isSelf() and
not apos.isLambdaSelf()
}
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
pragma[nomagic]
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
ppos.isSelf() and apos.isSelf()
or
ppos.isLambdaSelf() and apos.isLambdaSelf()
or
ppos.isBlock() and apos.isBlock()
or
exists(int pos | ppos.isPositional(pos) and apos.isPositional(pos))
@@ -1441,8 +1464,6 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
* This is a temporary hook to support technical debt in the Go language; do not use.
*/
pragma[inline]
predicate golangSpecificParamArgFilter(
DataFlowCall call, DataFlow::ParameterNode p, ArgumentNode arg
) {
predicate golangSpecificParamArgFilter(DataFlowCall call, ParameterNodeImpl p, ArgumentNode arg) {
any()
}

View File

@@ -17,6 +17,9 @@ module RubyDataFlow implements InputSig {
import Private
import Public
// includes `LambdaSelfParameterNode`, which is not part of the public API
class ParameterNode = Private::ParameterNodeImpl;
predicate isParameterNode(ParameterNode p, DataFlowCallable c, ParameterPosition pos) {
Private::isParameterNode(p, c, pos)
}

View File

@@ -83,13 +83,13 @@ module LocalFlow {
def instanceof Ssa::PhiNode
or
def instanceof SsaImpl::PhiReadNode
//TODO: or def instanceof LocalFlow::UncertainExplicitSsaDefinition
}
}
/**
* Holds if `nodeFrom` is a node for SSA definition `def`, which can reach `next`.
*/
pragma[nomagic]
private predicate localFlowSsaInputFromDef(
SsaDefinitionExtNode nodeFrom, SsaImpl::DefinitionExt def, SsaInputDefinitionExtNode next
) {
@@ -102,20 +102,23 @@ module LocalFlow {
}
/**
* Holds if `exprFrom` is a last read of SSA definition `def`, which
* Holds if `nodeFrom` is a last read of SSA definition `def`, which
* can reach `next`.
*/
pragma[nomagic]
predicate localFlowSsaInputFromRead(
CfgNodes::ExprCfgNode exprFrom, SsaImpl::DefinitionExt def, SsaInputDefinitionExtNode next
SsaImpl::DefinitionExt def, Node nodeFrom, SsaInputDefinitionExtNode next
) {
exists(BasicBlock bb, int i |
exists(BasicBlock bb, int i, CfgNodes::ExprCfgNode exprFrom |
SsaImpl::lastRefBeforeRedefExt(def, bb, i, next.getDefinitionExt()) and
exprFrom = bb.getNode(i) and
exprFrom.getExpr() instanceof VariableReadAccess
exprFrom.getExpr() instanceof VariableReadAccess and
exprFrom = [nodeFrom.asExpr(), nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr()]
)
}
/** Gets the SSA definition node corresponding to parameter `p`. */
pragma[nomagic]
SsaDefinitionExtNode getParameterDefNode(NamedParameter p) {
exists(BasicBlock bb, int i |
bb.getNode(i).getAstNode() = p.getDefiningAccess() and
@@ -123,18 +126,14 @@ module LocalFlow {
)
}
/** Gets the SSA definition node corresponding to the implicit `self` parameter for `m`. */
private SsaDefinitionExtNode getSelfParameterDefNode(MethodBase m) {
result.getDefinitionExt().(Ssa::SelfDefinition).getSourceVariable().getDeclaringScope() = m
}
/**
* Holds if `nodeFrom` is a parameter node, and `nodeTo` is a corresponding SSA node.
*/
predicate localFlowSsaParamInput(Node nodeFrom, SsaDefinitionExtNode nodeTo) {
nodeTo = getParameterDefNode(nodeFrom.(ParameterNodeImpl).getParameter())
pragma[nomagic]
predicate localFlowSsaParamInput(ParameterNodeImpl nodeFrom, SsaDefinitionExtNode nodeTo) {
nodeTo = getParameterDefNode(nodeFrom.getParameter())
or
nodeTo = getSelfParameterDefNode(nodeFrom.(SelfParameterNodeImpl).getMethod())
nodeTo.getDefinitionExt() = nodeFrom.(SelfParameterNodeImpl).getSelfDefinition()
}
/**
@@ -147,39 +146,30 @@ module LocalFlow {
/**
* Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
* some SSA definition.
* SSA definition `def`.
*/
private predicate localSsaFlowStep(Node nodeFrom, Node nodeTo) {
exists(SsaImpl::DefinitionExt def |
// Flow from assignment into SSA definition
def.(Ssa::WriteDefinition).assigns(nodeFrom.asExpr()) and
nodeTo.(SsaDefinitionExtNode).getDefinitionExt() = def
or
// Flow from SSA definition to first read
def = nodeFrom.(SsaDefinitionExtNode).getDefinitionExt() and
firstReadExt(def, nodeTo.asExpr())
or
// Flow from read to next read
localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
or
// Flow into phi (read) SSA definition node from def
localFlowSsaInputFromDef(nodeFrom, def, nodeTo)
)
pragma[nomagic]
predicate localSsaFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
// Flow from assignment into SSA definition
def.(Ssa::WriteDefinition).assigns(nodeFrom.asExpr()) and
nodeTo.(SsaDefinitionExtNode).getDefinitionExt() = def
or
localFlowSsaParamInput(nodeFrom, nodeTo)
// TODO
// or
// // Flow into uncertain SSA definition
// exists(LocalFlow::UncertainExplicitSsaDefinition uncertain |
// localFlowSsaInput(nodeFrom, def, uncertain) and
// uncertain = nodeTo.(SsaDefinitionNode).getDefinition() and
// def = uncertain.getPriorDefinition()
// )
// Flow from SSA definition to first read
def = nodeFrom.(SsaDefinitionExtNode).getDefinitionExt() and
firstReadExt(def, nodeTo.asExpr())
or
// Flow from post-update read to next read
localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
or
// Flow into phi (read) SSA definition node from def
localFlowSsaInputFromDef(nodeFrom, def, nodeTo)
or
localFlowSsaParamInput(nodeFrom, nodeTo) and
def = nodeTo.(SsaDefinitionExtNode).getDefinitionExt()
}
pragma[nomagic]
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
localSsaFlowStep(nodeFrom, nodeTo)
or
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::BlockArgumentCfgNode).getValue()
or
nodeFrom.asExpr() = getALastEvalNode(nodeTo.asExpr())
@@ -218,7 +208,7 @@ module LocalFlow {
}
}
/** An argument of a call (including qualifier arguments, excluding block arguments). */
/** An argument of a call (including qualifier arguments and block arguments). */
private class Argument extends CfgNodes::ExprCfgNode {
private CfgNodes::ExprNodes::CallCfgNode call;
private ArgumentPosition arg;
@@ -239,7 +229,11 @@ private class Argument extends CfgNodes::ExprCfgNode {
arg.isKeyword(p.getKey().getConstantValue().getSymbol())
)
or
this = call.getReceiver() and arg.isSelf()
this = call.getReceiver() and
arg.isSelf()
or
lambdaCallExpr(call, this) and
arg.isLambdaSelf()
or
this = call.getAnArgument() and
this.getExpr() instanceof HashSplatExpr and
@@ -250,6 +244,13 @@ private class Argument extends CfgNodes::ExprCfgNode {
this.getExpr() instanceof SplatExpr and
arg.isSplat(pos)
)
or
this = call.getAnArgument() and
this.getExpr() instanceof BlockArgument and
arg.isBlock()
or
this = call.getBlock() and
arg.isBlock()
}
/** Holds if this expression is the `i`th argument of `c`. */
@@ -266,16 +267,127 @@ predicate isNonConstantExpr(CfgNodes::ExprCfgNode n) {
/** Provides logic related to captured variables. */
module VariableCapture {
class CapturedVariable extends LocalVariable {
CapturedVariable() { this.isCaptured() }
private import codeql.dataflow.VariableCapture as Shared
CfgScope getCfgScope() {
exists(Scope scope | scope = this.getDeclaringScope() |
result = scope
or
result = scope.(ModuleBase).getCfgScope()
)
private predicate closureFlowStep(CfgNodes::ExprCfgNode e1, CfgNodes::ExprCfgNode e2) {
e1 = getALastEvalNode(e2)
or
exists(Ssa::Definition def |
def.getARead() = e2 and
def.getAnUltimateDefinition().(Ssa::WriteDefinition).assigns(e1)
)
}
private module CaptureInput implements Shared::InputSig {
private import ruby as R
private import codeql.ruby.controlflow.ControlFlowGraph
private import codeql.ruby.controlflow.BasicBlocks as BasicBlocks
class Location = R::Location;
class BasicBlock extends BasicBlocks::BasicBlock {
Callable getEnclosingCallable() { result = this.getScope() }
}
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
result = bb.getImmediateDominator()
}
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class CapturedVariable extends LocalVariable {
CapturedVariable() { this.isCaptured() }
Callable getCallable() {
exists(Scope scope | scope = this.getDeclaringScope() |
result = scope
or
result = scope.(ModuleBase).getCfgScope()
)
}
}
abstract class CapturedParameter extends CapturedVariable {
abstract ParameterNode getParameterNode();
}
private class CapturedNamedParameter extends CapturedParameter {
private NamedParameter p;
CapturedNamedParameter() { this = p.getVariable() }
override ParameterNode getParameterNode() { result.asParameter() = p }
}
private class CapturedSelfParameter extends CapturedParameter, SelfVariable {
override SelfParameterNode getParameterNode() { this = result.getSelfVariable() }
}
class Expr extends CfgNodes::ExprCfgNode {
predicate hasCfgNode(BasicBlock bb, int i) { this = bb.getNode(i) }
}
class VariableWrite extends Expr, CfgNodes::ExprNodes::AssignExprCfgNode {
CapturedVariable v;
VariableWrite() { v = this.getLhs().getVariable() }
CapturedVariable getVariable() { result = v }
}
class VariableRead extends Expr instanceof CfgNodes::ExprNodes::LocalVariableReadAccessCfgNode {
CapturedVariable v;
VariableRead() { v = super.getVariable() }
CapturedVariable getVariable() { result = v }
}
class ClosureExpr extends Expr {
Callable c;
ClosureExpr() { lambdaCreationExpr(this, _, c) }
predicate hasBody(Callable body) { body = c }
predicate hasAliasedAccess(Expr f) { closureFlowStep+(this, f) and not closureFlowStep(f, _) }
}
class Callable extends CfgScope {
predicate isConstructor() { none() }
}
}
class CapturedVariable = CaptureInput::CapturedVariable;
class ClosureExpr = CaptureInput::ClosureExpr;
module Flow = Shared::Flow<CaptureInput>;
private Flow::ClosureNode asClosureNode(Node n) {
result = n.(CaptureNode).getSynthesizedCaptureNode()
or
result.(Flow::ExprNode).getExpr() = n.asExpr()
or
result.(Flow::VariableWriteSourceNode).getVariableWrite().getRhs() = n.asExpr()
or
result.(Flow::ExprPostUpdateNode).getExpr() = n.(PostUpdateNode).getPreUpdateNode().asExpr()
or
result.(Flow::ParameterNode).getParameter().getParameterNode() = n
or
result.(Flow::ThisParameterNode).getCallable() = n.(LambdaSelfParameterNode).getCallable()
}
predicate storeStep(Node node1, Content::CapturedVariableContent c, Node node2) {
Flow::storeStep(asClosureNode(node1), c.getVariable(), asClosureNode(node2))
}
predicate readStep(Node node1, Content::CapturedVariableContent c, Node node2) {
Flow::readStep(asClosureNode(node1), c.getVariable(), asClosureNode(node2))
}
predicate valueStep(Node node1, Node node2) {
Flow::localFlowStep(asClosureNode(node1), asClosureNode(node2))
}
class CapturedSsaDefinitionExt extends SsaImpl::DefinitionExt {
@@ -331,6 +443,7 @@ private module Cached {
p instanceof SplatParameter
} or
TSelfParameterNode(MethodBase m) or
TLambdaSelfParameterNode(Callable c) { lambdaCreationExpr(_, _, c) } or
TBlockParameterNode(MethodBase m) or
TSynthHashSplatParameterNode(DataFlowCallable c) {
isParameterNode(_, c, any(ParameterPosition p | p.isKeyword(_)))
@@ -366,7 +479,8 @@ private module Cached {
TSynthSplatArgumentNode(CfgNodes::ExprNodes::CallCfgNode c) {
exists(Argument arg, ArgumentPosition pos | pos.isPositional(_) | arg.isArgumentOf(c, pos)) and
not exists(Argument arg, ArgumentPosition pos | pos.isSplat(_) | arg.isArgumentOf(c, pos))
}
} or
TCaptureNode(VariableCapture::Flow::SynthesizedCaptureNode cn)
class TSourceParameterNode =
TNormalParameterNode or TBlockParameterNode or TSelfParameterNode or
@@ -386,21 +500,23 @@ private module Cached {
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
or
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo) and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
or
// Flow into phi node from read
exists(CfgNodes::ExprCfgNode exprFrom |
LocalFlow::localFlowSsaInputFromRead(exprFrom, _, nodeTo)
exists(SsaImpl::DefinitionExt def |
// captured variables are handled by the shared `VariableCapture` library
not def instanceof VariableCapture::CapturedSsaDefinitionExt
|
exprFrom = nodeFrom.asExpr() and
LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo)
or
LocalFlow::localSsaFlowStepUseUse(def, nodeFrom, nodeTo) and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
or
exprFrom = nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr()
LocalFlow::localFlowSsaInputFromRead(def, nodeFrom, nodeTo) and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
)
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo.(FlowSummaryNode).getSummaryNode(), true)
or
VariableCapture::valueStep(nodeFrom, nodeTo)
}
/** This is the local flow predicate that is exposed. */
@@ -408,6 +524,8 @@ private module Cached {
predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) {
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
or
LocalFlow::localSsaFlowStep(_, nodeFrom, nodeTo)
or
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
or
// Simple flow through library code is included in the exposed local
@@ -422,13 +540,11 @@ private module Cached {
predicate localFlowStepTypeTracker(Node nodeFrom, Node nodeTo) {
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
or
LocalFlow::localSsaFlowStep(_, nodeFrom, nodeTo)
or
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
or
// Flow into phi node from read
exists(CfgNodes::ExprCfgNode exprFrom |
LocalFlow::localFlowSsaInputFromRead(exprFrom, _, nodeTo) and
exprFrom = [nodeFrom.asExpr(), nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr()]
)
LocalFlow::localFlowSsaInputFromRead(_, nodeFrom, nodeTo)
or
VariableCapture::flowInsensitiveStep(nodeFrom, nodeTo)
}
@@ -527,6 +643,7 @@ private module Cached {
name = [input, output].regexpFind("(?<=(^|\\.)Field\\[)[^\\]]+(?=\\])", _, _).trim()
)
} or
TCapturedVariableContent(VariableCapture::CapturedVariable v) or
// Only used by type-tracking
TAttributeName(string name) { name = any(SetterMethodCall c).getTargetName() }
@@ -549,7 +666,8 @@ private module Cached {
TUnknownElementContentApprox() or
TKnownIntegerElementContentApprox() or
TKnownElementContentApprox(string approx) { approx = approxKnownElementIndex(_) } or
TNonElementContentApprox(Content c) { not c instanceof Content::ElementContent }
TNonElementContentApprox(Content c) { not c instanceof Content::ElementContent } or
TCapturedVariableContentApprox(VariableCapture::CapturedVariable v)
}
class TElementContent = TKnownElementContent or TUnknownElementContent;
@@ -577,6 +695,10 @@ predicate nodeIsHidden(Node n) {
n instanceof SynthSplatArgParameterNode
or
n instanceof SynthSplatParameterElementNode
or
n instanceof LambdaSelfParameterNode
or
n instanceof CaptureNode
}
/** An SSA definition, viewed as a node in a data flow graph. */
@@ -624,7 +746,7 @@ class CapturedVariableNode extends NodeImpl, TCapturedVariableNode {
/** Gets the captured variable represented by this node. */
VariableCapture::CapturedVariable getVariable() { result = variable }
override CfgScope getCfgScope() { result = variable.getCfgScope() }
override CfgScope getCfgScope() { result = variable.getCallable() }
override Location getLocationImpl() { result = variable.getLocation() }
@@ -653,6 +775,24 @@ class ReturningStatementNode extends NodeImpl, TReturningNode {
override string toStringImpl() { result = n.toString() }
}
/**
* A synthesized data flow node representing a closure object that tracks
* captured variables.
*/
class CaptureNode extends NodeImpl, TCaptureNode {
private VariableCapture::Flow::SynthesizedCaptureNode cn;
CaptureNode() { this = TCaptureNode(cn) }
VariableCapture::Flow::SynthesizedCaptureNode getSynthesizedCaptureNode() { result = cn }
override CfgScope getCfgScope() { result = cn.getEnclosingCallable() }
override Location getLocationImpl() { result = cn.getLocation() }
override string toStringImpl() { result = cn.toString() }
}
private module ParameterNodes {
abstract class ParameterNodeImpl extends NodeImpl {
abstract Parameter getParameter();
@@ -722,6 +862,11 @@ private module ParameterNodes {
final MethodBase getMethod() { result = method }
/** Gets the corresponding SSA `self` definition, if any. */
Ssa::SelfDefinition getSelfDefinition() {
result.getSourceVariable().getDeclaringScope() = method
}
/** Gets the underlying `self` variable. */
final SelfVariable getSelfVariable() { result.getDeclaringScope() = method }
@@ -735,14 +880,43 @@ private module ParameterNodes {
override Location getLocationImpl() { result = method.getLocation() }
override string toStringImpl() { result = "self in " + method.toString() }
override string toStringImpl() { result = "self in " + method }
}
/**
* The value of a lambda itself at function entry, viewed as a node in a data
* flow graph.
*
* This is used for tracking flow through captured variables, and we use a
* separate node and parameter/argument positions in order to distinguish
* "lambda self" from "normal self", as lambdas may also access outer `self`
* variables (through variable capture).
*/
class LambdaSelfParameterNode extends ParameterNodeImpl, TLambdaSelfParameterNode {
private Callable callable;
LambdaSelfParameterNode() { this = TLambdaSelfParameterNode(callable) }
final Callable getCallable() { result = callable }
override Parameter getParameter() { none() }
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
callable = c.asCallable() and pos.isLambdaSelf()
}
override CfgScope getCfgScope() { result = callable }
override Location getLocationImpl() { result = callable.getLocation() }
override string toStringImpl() { result = "lambda self in " + callable }
}
/**
* The value of a block parameter at function entry, viewed as a node in a data
* flow graph.
*/
class BlockParameterNode extends ParameterNodeImpl, TBlockParameterNode {
class BlockParameterNode extends ParameterNodeImpl, ArgumentNode, TBlockParameterNode {
private MethodBase method;
BlockParameterNode() { this = TBlockParameterNode(method) }
@@ -757,6 +931,20 @@ private module ParameterNodes {
c.asCallable() = method and pos.isBlock()
}
CfgNodes::ExprNodes::CallCfgNode getAYieldCall() {
this.getMethod() = result.getExpr().(YieldCall).getEnclosingMethod()
}
// needed for variable capture flow
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) {
call = this.getAYieldCall() and
pos.isLambdaSelf()
}
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
this.sourceArgumentOf(call.asCall(), pos)
}
override CfgScope getCfgScope() { result = method }
override Location getLocationImpl() {
@@ -1027,36 +1215,6 @@ private module ArgumentNodes {
}
}
/** A data-flow node that represents the `self` argument of a call. */
class SelfArgumentNode extends ExplicitArgumentNode {
SelfArgumentNode() { arg.isArgumentOf(_, any(ArgumentPosition pos | pos.isSelf())) }
}
/** A data-flow node that represents a block argument. */
class BlockArgumentNode extends ArgumentNode {
BlockArgumentNode() {
this.asExpr().getExpr() instanceof BlockArgument or
exists(CfgNodes::ExprNodes::CallCfgNode c | c.getBlock() = this.asExpr())
}
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
this.sourceArgumentOf(call.asCall(), pos)
}
override predicate sourceArgumentOf(CfgNodes::ExprNodes::CallCfgNode call, ArgumentPosition pos) {
pos.isBlock() and
(
this.asExpr() = call.getBlock()
or
exists(CfgNodes::ExprCfgNode arg |
arg = call.getAnArgument() and
this.asExpr() = arg and
arg.getExpr() instanceof BlockArgument
)
)
}
}
private class SummaryArgumentNode extends FlowSummaryNode, ArgumentNode {
private DataFlowCall call_;
private ArgumentPosition pos_;
@@ -1335,7 +1493,7 @@ private module OutNodes {
import OutNodes
predicate jumpStepTypeTracker(Node pred, Node succ) {
predicate jumpStep(Node pred, Node succ) {
succ.asExpr().getExpr().(ConstantReadAccess).getValue() = pred.asExpr().getExpr()
or
FlowSummaryImpl::Private::Steps::summaryJumpStep(pred.(FlowSummaryNode).getSummaryNode(),
@@ -1344,16 +1502,6 @@ predicate jumpStepTypeTracker(Node pred, Node succ) {
any(AdditionalJumpStep s).step(pred, succ)
}
predicate jumpStep(Node pred, Node succ) {
jumpStepTypeTracker(pred, succ)
or
SsaImpl::captureFlowIn(_, pred.(SsaDefinitionExtNode).getDefinitionExt(),
succ.(SsaDefinitionExtNode).getDefinitionExt())
or
SsaImpl::captureFlowOut(_, pred.(SsaDefinitionExtNode).getDefinitionExt(),
succ.(SsaDefinitionExtNode).getDefinitionExt())
}
private ContentSet getKeywordContent(string name) {
exists(ConstantValue::ConstantSymbolValue key |
result.isSingleton(TKnownElementContent(key)) and
@@ -1439,6 +1587,9 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
)
or
storeStepCommon(node1, c, node2)
or
VariableCapture::storeStep(node1, any(Content::CapturedVariableContent v | c.isSingleton(v)),
node2)
}
/**
@@ -1487,6 +1638,8 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
c = getPositionalContent(e.getReadPosition())
)
or
VariableCapture::readStep(node1, any(Content::CapturedVariableContent v | c.isSingleton(v)), node2)
or
readStepCommon(node1, c, node2)
}
@@ -1521,27 +1674,60 @@ predicate expectsContent(Node n, ContentSet c) {
}
private newtype TDataFlowType =
TTodoDataFlowType() or
TTodoDataFlowType2() // Add a dummy value to prevent bad functionality-induced joins arising from a type of size 1.
TLambdaDataFlowType(Callable c) { c = any(LambdaSelfParameterNode n).getCallable() } or
TUnknownDataFlowType()
class DataFlowType extends TDataFlowType {
string toString() { result = "" }
}
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) {
t1 = TLambdaDataFlowType(_) and
t2 = TUnknownDataFlowType()
}
private predicate mustHaveLambdaType(CfgNodes::ExprCfgNode e, Callable c) {
exists(VariableCapture::ClosureExpr ce | ce.hasBody(c) |
e = ce or
ce.hasAliasedAccess(e)
)
}
/** Gets the type of `n` used for type pruning. */
DataFlowType getNodeType(Node n) { result = TTodoDataFlowType() and exists(n) }
DataFlowType getNodeType(Node n) {
result = TLambdaDataFlowType(n.(LambdaSelfParameterNode).getCallable())
or
exists(Callable c |
mustHaveLambdaType(n.asExpr(), c) and
result = TLambdaDataFlowType(c)
)
or
not n instanceof LambdaSelfParameterNode and
not mustHaveLambdaType(n.asExpr(), _) and
result = TUnknownDataFlowType()
}
/** Gets a string representation of a `DataFlowType`. */
string ppReprType(DataFlowType t) { none() }
pragma[inline]
private predicate compatibleTypesNonSymRefl(DataFlowType t1, DataFlowType t2) {
t1 = TLambdaDataFlowType(_) and
t2 = TUnknownDataFlowType()
}
/**
* Holds if `t1` and `t2` are compatible, that is, whether data can flow from
* a node of type `t1` to a node of type `t2`.
*/
pragma[inline]
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { any() }
predicate compatibleTypes(DataFlowType t1, DataFlowType t2) {
t1 = t2
or
compatibleTypesNonSymRefl(t1, t2)
or
compatibleTypesNonSymRefl(t2, t1)
}
abstract class PostUpdateNodeImpl extends Node {
/** Gets the node before the state update. */
@@ -1583,6 +1769,17 @@ private module PostUpdateNodes {
override Node getPreUpdateNode() { result = pre }
}
private class CapturePostUpdateNode extends PostUpdateNodeImpl, CaptureNode {
private CaptureNode pre;
CapturePostUpdateNode() {
VariableCapture::Flow::capturePostUpdateNode(this.getSynthesizedCaptureNode(),
pre.getSynthesizedCaptureNode())
}
override Node getPreUpdateNode() { result = pre }
}
}
private import PostUpdateNodes
@@ -1623,22 +1820,27 @@ newtype LambdaCallKind =
TLambdaCallKind()
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) {
private predicate lambdaCreationExpr(CfgNodes::ExprCfgNode creation, LambdaCallKind kind, Callable c) {
kind = TYieldCallKind() and
creation.asExpr().getExpr() = c.asCallable().(Block)
creation.getExpr() = c.(Block)
or
kind = TLambdaCallKind() and
(
creation.asExpr().getExpr() = c.asCallable().(Lambda)
creation.getExpr() = c.(Lambda)
or
creation.asExpr() =
creation =
any(CfgNodes::ExprNodes::MethodCallCfgNode mc |
c.asCallable() = mc.getBlock().getExpr() and
c = mc.getBlock().getExpr() and
isProcCreationCall(mc.getExpr())
)
)
}
/** Holds if `creation` is an expression that creates a lambda of kind `kind` for `c`. */
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) {
lambdaCreationExpr(creation.asExpr(), kind, c.asCallable())
}
/** Holds if `call` is a call to `lambda`, `proc`, or `Proc.new` */
pragma[nomagic]
private predicate isProcCreationCall(MethodCall call) {
@@ -1648,20 +1850,24 @@ private predicate isProcCreationCall(MethodCall call) {
call.getReceiver().(ConstantReadAccess).getAQualifiedName() = "Proc"
}
/** Holds if `mc` is a call to `receiver.call`. */
private predicate lambdaCallExpr(
CfgNodes::ExprNodes::MethodCallCfgNode mc, CfgNodes::ExprCfgNode receiver
) {
receiver = mc.getReceiver() and
mc.getExpr().getMethodName() = "call"
}
/**
* Holds if `call` is a from-source lambda call of kind `kind` where `receiver`
* is the lambda expression.
*/
predicate lambdaSourceCall(CfgNodes::ExprNodes::CallCfgNode call, LambdaCallKind kind, Node receiver) {
kind = TYieldCallKind() and
receiver.(BlockParameterNode).getMethod() = call.getExpr().(YieldCall).getEnclosingMethod()
call = receiver.(BlockParameterNode).getAYieldCall()
or
kind = TLambdaCallKind() and
call =
any(CfgNodes::ExprNodes::MethodCallCfgNode mc |
receiver.asExpr() = mc.getReceiver() and
mc.getExpr().getMethodName() = "call"
)
lambdaCallExpr(call, receiver.asExpr())
}
/**
@@ -1687,8 +1893,11 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
* One example would be to allow flow like `p.foo = p.bar;`, which is disallowed
* by default as a heuristic.
*/
predicate allowParameterReturnInSelf(ParameterNode p) {
predicate allowParameterReturnInSelf(ParameterNodeImpl p) {
FlowSummaryImpl::Private::summaryAllowParameterReturnInSelf(p)
or
VariableCapture::Flow::heuristicAllowInstanceParameterReturnInSelf(p.(SelfParameterNode)
.getCallable())
}
/** An approximated `Content`. */
@@ -1765,4 +1974,4 @@ class AdditionalJumpStep extends Unit {
*
* Argument `arg` is part of a path from a source to a sink, and `p` is the target parameter.
*/
int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) { none() }
int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNodeImpl p) { none() }

View File

@@ -568,6 +568,18 @@ module Content {
/** Gets `AttributeNameContent` of the given name. */
AttributeNameContent getAttributeName(string name) { result.getName() = name }
/** A captured variable. */
class CapturedVariableContent extends Content, TCapturedVariableContent {
private LocalVariable v;
CapturedVariableContent() { this = TCapturedVariableContent(v) }
/** Gets the captured variable. */
LocalVariable getVariable() { result = v }
override string toString() { result = "captured " + v }
}
}
/**
@@ -765,14 +777,14 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
* This is restricted to calls where the variable is captured inside a
* block.
*/
private Ssa::Definition getAMaybeGuardedCapturedDef() {
private Ssa::CapturedEntryDefinition getAMaybeGuardedCapturedDef() {
exists(
CfgNodes::ExprCfgNode g, boolean branch, CfgNodes::ExprCfgNode testedNode,
Ssa::Definition def, CfgNodes::ExprNodes::CallCfgNode call
|
def.getARead() = testedNode and
guardChecks(g, testedNode, branch) and
SsaImpl::captureFlowIn(call, def, result) and
def.getSourceVariable() = result.getSourceVariable() and
guardControlsBlock(g, call.getBasicBlock(), branch) and
result.getBasicBlock().getScope() = call.getExpr().(MethodCall).getBlock()
)
@@ -830,14 +842,14 @@ abstract deprecated class BarrierGuard extends CfgNodes::ExprCfgNode {
* This is restricted to calls where the variable is captured inside a
* block.
*/
private Ssa::Definition getAMaybeGuardedCapturedDef() {
private Ssa::CapturedEntryDefinition getAMaybeGuardedCapturedDef() {
exists(
boolean branch, CfgNodes::ExprCfgNode testedNode, Ssa::Definition def,
CfgNodes::ExprNodes::CallCfgNode call
|
def.getARead() = testedNode and
this.checks(testedNode, branch) and
SsaImpl::captureFlowIn(call, def, result) and
def.getSourceVariable() = result.getSourceVariable() and
this.controlsBlock(call.getBasicBlock(), branch) and
result.getBasicBlock().getScope() = call.getExpr().(MethodCall).getBlock()
)
@@ -1208,7 +1220,10 @@ class LhsExprNode extends ExprNode {
LhsExpr asLhsExprAstNode() { result = lhsExprCfgNode.getExpr() }
/** Gets a variable used in (or introduced by) this LHS. */
Variable getAVariable() { result = lhsExprCfgNode.getAVariable() }
deprecated Variable getAVariable() { result = lhsExprCfgNode.getAVariable() }
/** Gets the variable used in (or introduced by) this LHS. */
Variable getVariable() { result = lhsExprCfgNode.getVariable() }
}
/**

View File

@@ -24,7 +24,7 @@ class NeutralCallableBase = string;
DataFlowCallable inject(SummarizedCallable c) { result.asLibraryCallable() = c }
/** Gets the parameter position representing a callback itself, if any. */
ArgumentPosition callbackSelfParameterPosition() { none() } // disables implicit summary flow to `self` for callbacks
ArgumentPosition callbackSelfParameterPosition() { result.isLambdaSelf() }
/** Gets the synthesized data-flow call for `receiver`. */
SummaryCall summaryDataFlowCall(SummaryNode receiver) { receiver = result.getReceiver() }
@@ -215,6 +215,9 @@ string getParameterPosition(ParameterPosition pos) {
pos.isSelf() and
result = "self"
or
pos.isLambdaSelf() and
result = "lambda-self"
or
pos.isBlock() and
result = "block"
or
@@ -232,6 +235,8 @@ string getParameterPosition(ParameterPosition pos) {
string getArgumentPosition(ArgumentPosition pos) {
pos.isSelf() and result = "self"
or
pos.isLambdaSelf() and result = "lambda-self"
or
pos.isBlock() and result = "block"
or
exists(int i |
@@ -372,6 +377,9 @@ ArgumentPosition parseParamBody(string s) {
s = "self" and
result.isSelf()
or
s = "lambda-self" and
result.isLambdaSelf()
or
s = "block" and
result.isBlock()
or
@@ -402,6 +410,9 @@ ParameterPosition parseArgBody(string s) {
s = "self" and
result.isSelf()
or
s = "lambda-self" and
result.isLambdaSelf()
or
s = "block" and
result.isBlock()
or

View File

@@ -363,97 +363,8 @@ private module Cached {
)
}
pragma[noinline]
private predicate defReachesCallReadInOuterScope(
Definition def, CallCfgNode call, LocalVariable v, Cfg::CfgScope scope
) {
exists(Cfg::BasicBlock bb, int i |
Impl::ssaDefReachesRead(v, def, bb, i) and
capturedCallRead(call, bb, i, v) and
scope.getOuterCfgScope() = bb.getScope()
)
}
pragma[noinline]
private predicate hasCapturedEntryWrite(Definition entry, LocalVariable v, Cfg::CfgScope scope) {
exists(Cfg::BasicBlock bb, int i |
capturedEntryWrite(bb, i, v) and
entry.definesAt(v, bb, i) and
bb.getScope().getOuterCfgScope*() = scope
)
}
/**
* Holds if there is flow for a captured variable from the enclosing scope into a block.
* ```rb
* foo = 0
* bar {
* puts foo
* }
* ```
*/
cached
predicate captureFlowIn(CallCfgNode call, Definition def, Definition entry) {
exists(LocalVariable v, Cfg::CfgScope scope |
defReachesCallReadInOuterScope(def, call, v, scope) and
hasCapturedEntryWrite(entry, v, scope)
|
// If the read happens inside a block, we restrict to the call that
// contains the block
not scope instanceof Block
or
scope = call.getExpr().(MethodCall).getBlock()
)
}
private import codeql.ruby.dataflow.SSA
pragma[noinline]
private predicate defReachesExitReadInInnerScope(
Definition def, LocalVariable v, Cfg::CfgScope scope
) {
exists(Cfg::BasicBlock bb, int i |
Impl::ssaDefReachesRead(v, def, bb, i) and
capturedExitRead(bb, i, v) and
scope = bb.getScope().getOuterCfgScope*()
)
}
pragma[noinline]
private predicate hasCapturedExitRead(
Definition exit, CallCfgNode call, LocalVariable v, Cfg::CfgScope scope
) {
exists(Cfg::BasicBlock bb, int i |
capturedCallWrite(call, bb, i, v) and
exit.definesAt(v, bb, i) and
bb.getScope() = scope.getOuterCfgScope()
)
}
/**
* Holds if there is outgoing flow for a captured variable that is updated in a block.
* ```rb
* foo = 0
* bar {
* foo += 10
* }
* puts foo
* ```
*/
cached
predicate captureFlowOut(CallCfgNode call, Definition def, Definition exit) {
exists(LocalVariable v, Cfg::CfgScope scope |
defReachesExitReadInInnerScope(def, v, scope) and
hasCapturedExitRead(exit, call, v, _)
|
// If the read happens inside a block, we restrict to the call that
// contains the block
not scope instanceof Block
or
scope = call.getExpr().(MethodCall).getBlock()
)
}
cached
Definition phiHasInputFromBlock(PhiNode phi, Cfg::BasicBlock bb) {
Impl::phiHasInputFromBlock(phi, result, bb)
@@ -570,6 +481,8 @@ import Cached
* Only intended for internal use.
*/
class DefinitionExt extends Impl::DefinitionExt {
VariableReadAccessCfgNode getARead() { result = getARead(this) }
override string toString() { result = this.(Ssa::Definition).toString() }
/** Gets the location of this definition. */

View File

@@ -273,39 +273,19 @@ module Sinatra {
filter.getApp() = route.getApp() and
// the filter applies to all routes
not filter.hasPattern() and
selfPostUpdate(pred, filter.getApp(), filter.getBody().asExpr().getExpr()) and
blockCapturedSelfParameterNode(succ, route.getBody().asExpr().getExpr())
blockPostUpdate(pred, filter.getBody()) and
blockSelfParameterNode(succ, route.getBody().asExpr().getExpr())
)
}
}
/**
* Holds if `n` is a post-update node for the `self` parameter of `app` in block `b`.
*
* In this example, `n` is the post-update node for `@foo = 1`.
* ```rb
* class MyApp < Sinatra::Base
* before do
* @foo = 1
* end
* end
* ```
*/
private predicate selfPostUpdate(DataFlow::PostUpdateNode n, App app, Block b) {
n.getPreUpdateNode().asExpr().getExpr() =
any(SelfVariableAccess self |
pragma[only_bind_into](b) = self.getEnclosingCallable() and
self.getVariable().getDeclaringScope() = app.getADeclaration()
)
/** Holds if `n` is a post-update node for the block `b`. */
private predicate blockPostUpdate(DataFlow::PostUpdateNode n, DataFlow::BlockNode b) {
n.getPreUpdateNode() = b
}
/**
* Holds if `n` is a node representing the `self` parameter captured by block `b`.
*/
private predicate blockCapturedSelfParameterNode(DataFlow::Node n, Block b) {
exists(Ssa::CapturedSelfDefinition d |
n.(DataFlowPrivate::SsaDefinitionExtNode).getDefinitionExt() = d and
d.getBasicBlock().getScope() = b
)
/** Holds if `n` is a `self` parameter belonging to block `b`. */
private predicate blockSelfParameterNode(DataFlowPrivate::LambdaSelfParameterNode n, Block b) {
n.getCallable() = b
}
}

View File

@@ -243,7 +243,7 @@ predicate isExtraValidTokenArgumentInIdentifyingAccessPath(string name, string a
or
name = ["Argument", "Parameter"] and
(
argument = ["self", "block", "any", "any-named"]
argument = ["self", "lambda-self", "block", "any", "any-named"]
or
argument.regexpMatch("\\w+:") // keyword argument
)

View File

@@ -6,7 +6,6 @@ private import codeql.ruby.dataflow.internal.DataFlowImplCommon as DataFlowImplC
private import codeql.ruby.dataflow.internal.DataFlowPublic as DataFlowPublic
private import codeql.ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private import codeql.ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch
private import codeql.ruby.dataflow.internal.SsaImpl as SsaImpl
private import codeql.ruby.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import codeql.ruby.dataflow.internal.FlowSummaryImplSpecific as FlowSummaryImplSpecific
private import codeql.ruby.dataflow.internal.AccessPathSyntax
@@ -74,7 +73,7 @@ predicate simpleLocalFlowStep = DataFlowPrivate::localFlowStepTypeTracker/2;
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
predicate jumpStep = DataFlowPrivate::jumpStepTypeTracker/2;
predicate jumpStep = DataFlowPrivate::jumpStep/2;
/** Holds if there is direct flow from `param` to a return. */
pragma[nomagic]
@@ -180,6 +179,7 @@ private predicate argumentPositionMatch(
) {
exists(DataFlowDispatch::ArgumentPosition apos |
arg.sourceArgumentOf(call, apos) and
not apos.isLambdaSelf() and
DataFlowDispatch::parameterMatch(ppos, apos)
)
}

View File

@@ -450,10 +450,10 @@ edges
| array_flow.rb:403:5:403:5 | a [element 2] | array_flow.rb:404:18:404:18 | a [element 2] |
| array_flow.rb:403:16:403:25 | call to source | array_flow.rb:403:5:403:5 | a [element 2] |
| array_flow.rb:404:5:404:5 | b [element 2] | array_flow.rb:408:10:408:10 | b [element 2] |
| array_flow.rb:404:9:406:7 | __synth__0__1 | array_flow.rb:404:13:404:13 | x |
| array_flow.rb:404:13:404:13 | x | array_flow.rb:405:14:405:14 | x |
| array_flow.rb:404:13:404:13 | x | array_flow.rb:407:10:407:10 | x |
| array_flow.rb:404:9:406:7 | [post] { ... } [captured x] | array_flow.rb:407:10:407:10 | x |
| array_flow.rb:404:9:406:7 | __synth__0__1 | array_flow.rb:405:14:405:14 | x |
| array_flow.rb:404:18:404:18 | a [element 2] | array_flow.rb:404:5:404:5 | b [element 2] |
| array_flow.rb:404:18:404:18 | a [element 2] | array_flow.rb:404:9:406:7 | [post] { ... } [captured x] |
| array_flow.rb:404:18:404:18 | a [element 2] | array_flow.rb:404:9:406:7 | __synth__0__1 |
| array_flow.rb:408:10:408:10 | b [element 2] | array_flow.rb:408:10:408:13 | ...[...] |
| array_flow.rb:412:5:412:5 | a [element 2] | array_flow.rb:413:5:413:5 | a [element 2] |
@@ -2609,8 +2609,8 @@ nodes
| array_flow.rb:403:5:403:5 | a [element 2] | semmle.label | a [element 2] |
| array_flow.rb:403:16:403:25 | call to source | semmle.label | call to source |
| array_flow.rb:404:5:404:5 | b [element 2] | semmle.label | b [element 2] |
| array_flow.rb:404:9:406:7 | [post] { ... } [captured x] | semmle.label | [post] { ... } [captured x] |
| array_flow.rb:404:9:406:7 | __synth__0__1 | semmle.label | __synth__0__1 |
| array_flow.rb:404:13:404:13 | x | semmle.label | x |
| array_flow.rb:404:18:404:18 | a [element 2] | semmle.label | a [element 2] |
| array_flow.rb:405:14:405:14 | x | semmle.label | x |
| array_flow.rb:407:10:407:10 | x | semmle.label | x |

View File

@@ -32,7 +32,8 @@ edges
| call_sensitivity.rb:66:20:66:20 | x | call_sensitivity.rb:67:24:67:24 | x |
| call_sensitivity.rb:67:24:67:24 | x | call_sensitivity.rb:62:18:62:18 | y |
| call_sensitivity.rb:70:30:70:30 | x | call_sensitivity.rb:71:10:71:10 | x |
| call_sensitivity.rb:74:18:74:18 | y | call_sensitivity.rb:76:17:76:17 | y |
| call_sensitivity.rb:74:18:74:18 | y | call_sensitivity.rb:75:20:77:7 | do ... end [captured y] |
| call_sensitivity.rb:75:20:77:7 | do ... end [captured y] | call_sensitivity.rb:76:17:76:17 | y |
| call_sensitivity.rb:76:17:76:17 | y | call_sensitivity.rb:50:15:50:15 | x |
| call_sensitivity.rb:80:15:80:15 | x | call_sensitivity.rb:81:18:81:18 | x |
| call_sensitivity.rb:81:18:81:18 | x | call_sensitivity.rb:50:15:50:15 | x |
@@ -121,6 +122,7 @@ nodes
| call_sensitivity.rb:70:30:70:30 | x | semmle.label | x |
| call_sensitivity.rb:71:10:71:10 | x | semmle.label | x |
| call_sensitivity.rb:74:18:74:18 | y | semmle.label | y |
| call_sensitivity.rb:75:20:77:7 | do ... end [captured y] | semmle.label | do ... end [captured y] |
| call_sensitivity.rb:76:17:76:17 | y | semmle.label | y |
| call_sensitivity.rb:80:15:80:15 | x | semmle.label | x |
| call_sensitivity.rb:81:18:81:18 | x | semmle.label | x |

View File

@@ -1,49 +1,115 @@
testFailures
edges
| captured_variables.rb:9:24:9:24 | x | captured_variables.rb:10:20:10:20 | x |
| captured_variables.rb:9:24:9:24 | x | captured_variables.rb:10:10:10:23 | -> { ... } [captured x] |
| captured_variables.rb:9:24:9:24 | x | captured_variables.rb:11:5:11:6 | fn [captured x] |
| captured_variables.rb:10:5:10:6 | fn [captured x] | captured_variables.rb:11:5:11:6 | fn [captured x] |
| captured_variables.rb:10:10:10:23 | -> { ... } [captured x] | captured_variables.rb:10:5:10:6 | fn [captured x] |
| captured_variables.rb:11:5:11:6 | fn [captured x] | captured_variables.rb:10:20:10:20 | x |
| captured_variables.rb:13:20:13:29 | call to taint | captured_variables.rb:9:24:9:24 | x |
| captured_variables.rb:29:33:29:33 | x | captured_variables.rb:31:14:31:14 | x |
| captured_variables.rb:15:28:15:28 | x | captured_variables.rb:16:5:18:5 | -> { ... } [captured x] |
| captured_variables.rb:20:1:20:35 | ( ... ) [captured x] | captured_variables.rb:17:14:17:14 | x |
| captured_variables.rb:20:2:20:34 | call to capture_escape_return1 [captured x] | captured_variables.rb:20:1:20:35 | ( ... ) [captured x] |
| captured_variables.rb:20:25:20:34 | call to taint | captured_variables.rb:15:28:15:28 | x |
| captured_variables.rb:20:25:20:34 | call to taint | captured_variables.rb:20:2:20:34 | call to capture_escape_return1 [captured x] |
| captured_variables.rb:22:28:22:28 | x | captured_variables.rb:23:5:25:5 | -> { ... } [captured x] |
| captured_variables.rb:27:25:27:57 | call to capture_escape_return2 [captured x] | captured_variables.rb:24:14:24:14 | x |
| captured_variables.rb:27:48:27:57 | call to taint | captured_variables.rb:22:28:22:28 | x |
| captured_variables.rb:27:48:27:57 | call to taint | captured_variables.rb:27:25:27:57 | call to capture_escape_return2 [captured x] |
| captured_variables.rb:29:33:29:33 | x | captured_variables.rb:30:10:32:5 | -> { ... } [captured x] |
| captured_variables.rb:29:33:29:33 | x | captured_variables.rb:33:29:33:30 | fn [captured x] |
| captured_variables.rb:30:5:30:6 | fn [captured x] | captured_variables.rb:33:29:33:30 | fn [captured x] |
| captured_variables.rb:30:10:32:5 | -> { ... } [captured x] | captured_variables.rb:30:5:30:6 | fn [captured x] |
| captured_variables.rb:33:29:33:30 | fn [captured x] | captured_variables.rb:31:14:31:14 | x |
| captured_variables.rb:35:29:35:38 | call to taint | captured_variables.rb:29:33:29:33 | x |
| captured_variables.rb:40:31:40:31 | x | captured_variables.rb:42:14:42:14 | x |
| captured_variables.rb:37:13:37:14 | fn [captured x] | captured_variables.rb:38:5:38:6 | fn [captured x] |
| captured_variables.rb:38:5:38:6 | fn [captured x] | captured_variables.rb:42:14:42:14 | x |
| captured_variables.rb:40:31:40:31 | x | captured_variables.rb:41:10:43:5 | -> { ... } [captured x] |
| captured_variables.rb:40:31:40:31 | x | captured_variables.rb:44:13:44:14 | fn [captured x] |
| captured_variables.rb:41:5:41:6 | fn [captured x] | captured_variables.rb:44:13:44:14 | fn [captured x] |
| captured_variables.rb:41:10:43:5 | -> { ... } [captured x] | captured_variables.rb:41:5:41:6 | fn [captured x] |
| captured_variables.rb:44:13:44:14 | fn [captured x] | captured_variables.rb:37:13:37:14 | fn [captured x] |
| captured_variables.rb:46:27:46:36 | call to taint | captured_variables.rb:40:31:40:31 | x |
| captured_variables.rb:48:1:48:1 | x | captured_variables.rb:50:10:50:10 | x |
| captured_variables.rb:48:5:48:12 | call to taint | captured_variables.rb:48:1:48:1 | x |
| captured_variables.rb:51:5:51:5 | x | captured_variables.rb:54:6:54:6 | x |
| captured_variables.rb:51:9:51:16 | call to taint | captured_variables.rb:51:5:51:5 | x |
| captured_variables.rb:48:5:48:12 | call to taint | captured_variables.rb:49:16:52:3 | do ... end [captured x] |
| captured_variables.rb:48:5:48:12 | call to taint | captured_variables.rb:54:6:54:6 | x |
| captured_variables.rb:49:16:52:3 | [post] do ... end [captured x] | captured_variables.rb:54:6:54:6 | x |
| captured_variables.rb:49:16:52:3 | do ... end [captured x] | captured_variables.rb:50:10:50:10 | x |
| captured_variables.rb:51:9:51:16 | call to taint | captured_variables.rb:49:16:52:3 | [post] do ... end [captured x] |
| captured_variables.rb:57:19:57:19 | x | captured_variables.rb:58:18:58:18 | x |
| captured_variables.rb:58:18:58:18 | x | captured_variables.rb:58:9:58:14 | [post] self [@field] |
| captured_variables.rb:60:5:62:7 | self in get_field [@field] | captured_variables.rb:61:16:61:21 | self [@field] |
| captured_variables.rb:61:16:61:21 | @field | captured_variables.rb:61:9:61:21 | return |
| captured_variables.rb:61:16:61:21 | self [@field] | captured_variables.rb:61:16:61:21 | @field |
| captured_variables.rb:66:1:66:3 | [post] foo [@field] | captured_variables.rb:67:16:70:3 | do ... end [captured foo, @field] |
| captured_variables.rb:66:1:66:3 | [post] foo [@field] | captured_variables.rb:72:6:72:8 | foo [@field] |
| captured_variables.rb:66:15:66:22 | call to taint | captured_variables.rb:57:19:57:19 | x |
| captured_variables.rb:66:15:66:22 | call to taint | captured_variables.rb:66:1:66:3 | [post] foo [@field] |
| captured_variables.rb:66:15:66:22 | call to taint | instance_variables.rb:10:19:10:19 | x |
| captured_variables.rb:67:16:70:3 | [post] do ... end [captured foo, @field] | captured_variables.rb:72:6:72:8 | foo [@field] |
| captured_variables.rb:67:16:70:3 | do ... end [captured foo, @field] | captured_variables.rb:68:10:68:12 | foo [@field] |
| captured_variables.rb:68:10:68:12 | foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field [@field] |
| captured_variables.rb:68:10:68:12 | foo [@field] | captured_variables.rb:68:10:68:22 | call to get_field |
| captured_variables.rb:68:10:68:12 | foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field [@field] |
| captured_variables.rb:69:5:69:7 | [post] foo [@field] | captured_variables.rb:67:16:70:3 | [post] do ... end [captured foo, @field] |
| captured_variables.rb:69:19:69:26 | call to taint | captured_variables.rb:57:19:57:19 | x |
| captured_variables.rb:69:19:69:26 | call to taint | captured_variables.rb:69:5:69:7 | [post] foo [@field] |
| captured_variables.rb:69:19:69:26 | call to taint | instance_variables.rb:10:19:10:19 | x |
| captured_variables.rb:72:6:72:8 | foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field [@field] |
| captured_variables.rb:72:6:72:8 | foo [@field] | captured_variables.rb:72:6:72:18 | call to get_field |
| captured_variables.rb:72:6:72:8 | foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field [@field] |
| captured_variables.rb:85:1:85:1 | y | captured_variables.rb:87:10:87:10 | y |
| captured_variables.rb:85:5:85:12 | call to taint | captured_variables.rb:85:1:85:1 | y |
| captured_variables.rb:88:5:88:5 | y | captured_variables.rb:87:10:87:10 | y |
| captured_variables.rb:88:5:88:5 | y | captured_variables.rb:91:6:91:6 | y |
| captured_variables.rb:88:9:88:16 | call to taint | captured_variables.rb:88:5:88:5 | y |
| captured_variables.rb:78:20:80:7 | [post] do ... end [captured foo, @field] | captured_variables.rb:83:6:83:8 | foo [@field] |
| captured_variables.rb:79:9:79:11 | [post] foo [@field] | captured_variables.rb:78:20:80:7 | [post] do ... end [captured foo, @field] |
| captured_variables.rb:79:23:79:30 | call to taint | captured_variables.rb:57:19:57:19 | x |
| captured_variables.rb:79:23:79:30 | call to taint | captured_variables.rb:79:9:79:11 | [post] foo [@field] |
| captured_variables.rb:79:23:79:30 | call to taint | instance_variables.rb:10:19:10:19 | x |
| captured_variables.rb:83:6:83:8 | foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field [@field] |
| captured_variables.rb:83:6:83:8 | foo [@field] | captured_variables.rb:83:6:83:18 | call to get_field |
| captured_variables.rb:83:6:83:8 | foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field [@field] |
| captured_variables.rb:85:5:85:12 | call to taint | captured_variables.rb:86:6:89:1 | -> { ... } [captured y] |
| captured_variables.rb:85:5:85:12 | call to taint | captured_variables.rb:90:1:90:2 | fn [captured y] |
| captured_variables.rb:85:5:85:12 | call to taint | captured_variables.rb:91:6:91:6 | y |
| captured_variables.rb:86:1:86:2 | fn [captured y] | captured_variables.rb:90:1:90:2 | fn [captured y] |
| captured_variables.rb:86:6:89:1 | -> { ... } [captured y] | captured_variables.rb:86:1:86:2 | fn [captured y] |
| captured_variables.rb:88:9:88:16 | call to taint | captured_variables.rb:90:1:90:2 | [post] fn [captured y] |
| captured_variables.rb:90:1:90:2 | [post] fn [captured y] | captured_variables.rb:91:6:91:6 | y |
| captured_variables.rb:90:1:90:2 | fn [captured y] | captured_variables.rb:87:10:87:10 | y |
| captured_variables.rb:93:17:93:17 | x | captured_variables.rb:94:5:96:5 | -> { ... } [captured x] |
| captured_variables.rb:98:1:98:21 | call to capture_arg [captured x] | captured_variables.rb:95:14:95:14 | x |
| captured_variables.rb:98:13:98:20 | call to taint | captured_variables.rb:93:17:93:17 | x |
| captured_variables.rb:98:13:98:20 | call to taint | captured_variables.rb:98:1:98:21 | call to capture_arg [captured x] |
| captured_variables.rb:100:21:100:21 | x | captured_variables.rb:101:11:101:11 | x |
| captured_variables.rb:101:11:101:11 | x | captured_variables.rb:104:31:104:31 | x |
| captured_variables.rb:104:17:104:24 | call to taint | captured_variables.rb:100:21:100:21 | x |
| captured_variables.rb:104:31:104:31 | x | captured_variables.rb:105:10:105:10 | x |
| captured_variables.rb:109:5:109:5 | x | captured_variables.rb:112:18:112:18 | x |
| captured_variables.rb:109:9:109:17 | call to taint | captured_variables.rb:109:5:109:5 | x |
| captured_variables.rb:113:13:113:13 | x | captured_variables.rb:112:18:112:18 | x |
| captured_variables.rb:113:13:113:13 | x | captured_variables.rb:118:10:118:10 | x |
| captured_variables.rb:113:17:113:25 | call to taint | captured_variables.rb:113:13:113:13 | x |
| captured_variables.rb:109:9:109:17 | call to taint | captured_variables.rb:110:14:116:5 | -> { ... } [captured x] |
| captured_variables.rb:109:9:109:17 | call to taint | captured_variables.rb:117:5:117:10 | middle [captured x] |
| captured_variables.rb:109:9:109:17 | call to taint | captured_variables.rb:118:10:118:10 | x |
| captured_variables.rb:110:5:110:10 | middle [captured x] | captured_variables.rb:117:5:117:10 | middle [captured x] |
| captured_variables.rb:110:14:116:5 | -> { ... } [captured x] | captured_variables.rb:110:5:110:10 | middle [captured x] |
| captured_variables.rb:111:9:111:13 | inner [captured x] | captured_variables.rb:115:9:115:13 | inner [captured x] |
| captured_variables.rb:111:17:114:9 | -> { ... } [captured x] | captured_variables.rb:111:9:111:13 | inner [captured x] |
| captured_variables.rb:113:17:113:25 | call to taint | captured_variables.rb:115:9:115:13 | [post] inner [captured x] |
| captured_variables.rb:115:9:115:13 | [post] inner [captured x] | captured_variables.rb:117:5:117:10 | [post] middle [captured x] |
| captured_variables.rb:115:9:115:13 | inner [captured x] | captured_variables.rb:112:18:112:18 | x |
| captured_variables.rb:117:5:117:10 | [post] middle [captured x] | captured_variables.rb:118:10:118:10 | x |
| captured_variables.rb:117:5:117:10 | middle [captured x] | captured_variables.rb:111:17:114:9 | -> { ... } [captured x] |
| captured_variables.rb:117:5:117:10 | middle [captured x] | captured_variables.rb:115:9:115:13 | inner [captured x] |
| captured_variables.rb:147:5:147:6 | [post] self [@x] | captured_variables.rb:153:14:155:7 | do ... end [captured self, @x] |
| captured_variables.rb:147:10:147:18 | call to taint | captured_variables.rb:147:5:147:6 | [post] self [@x] |
| captured_variables.rb:149:5:151:7 | &block [captured self, @x] | captured_variables.rb:154:14:154:15 | self [@x] |
| captured_variables.rb:153:14:155:7 | do ... end [captured self, @x] | captured_variables.rb:149:5:151:7 | &block [captured self, @x] |
| captured_variables.rb:154:14:154:15 | self [@x] | captured_variables.rb:154:14:154:15 | @x |
| captured_variables.rb:160:9:160:10 | [post] self [@x] | captured_variables.rb:174:1:174:24 | call to new [@x] |
| captured_variables.rb:160:14:160:22 | call to taint | captured_variables.rb:160:9:160:10 | [post] self [@x] |
| captured_variables.rb:167:5:171:7 | self in baz [@x] | captured_variables.rb:169:18:169:19 | self [@x] |
| captured_variables.rb:163:5:165:7 | &block [captured self, @x] | captured_variables.rb:169:18:169:19 | self [@x] |
| captured_variables.rb:167:5:171:7 | self in baz [@x] | captured_variables.rb:168:18:170:11 | do ... end [captured self, @x] |
| captured_variables.rb:168:18:170:11 | do ... end [captured self, @x] | captured_variables.rb:163:5:165:7 | &block [captured self, @x] |
| captured_variables.rb:169:18:169:19 | self [@x] | captured_variables.rb:169:18:169:19 | @x |
| captured_variables.rb:174:1:174:24 | call to new [@x] | captured_variables.rb:167:5:171:7 | self in baz [@x] |
| captured_variables.rb:178:9:178:10 | [post] self [@x] | captured_variables.rb:193:1:193:1 | [post] c [@x] |
| captured_variables.rb:178:14:178:22 | call to taint | captured_variables.rb:178:9:178:10 | [post] self [@x] |
| captured_variables.rb:185:5:189:7 | self in baz [@x] | captured_variables.rb:187:18:187:19 | self [@x] |
| captured_variables.rb:181:5:183:7 | &block [captured self, @x] | captured_variables.rb:187:18:187:19 | self [@x] |
| captured_variables.rb:185:5:189:7 | self in baz [@x] | captured_variables.rb:186:18:188:11 | do ... end [captured self, @x] |
| captured_variables.rb:186:18:188:11 | do ... end [captured self, @x] | captured_variables.rb:181:5:183:7 | &block [captured self, @x] |
| captured_variables.rb:187:18:187:19 | self [@x] | captured_variables.rb:187:18:187:19 | @x |
| captured_variables.rb:193:1:193:1 | [post] c [@x] | captured_variables.rb:194:1:194:1 | c [@x] |
| captured_variables.rb:194:1:194:1 | c [@x] | captured_variables.rb:185:5:189:7 | self in baz [@x] |
@@ -188,18 +254,40 @@ edges
| instance_variables.rb:121:7:121:24 | call to new | instance_variables.rb:121:1:121:3 | bar |
nodes
| captured_variables.rb:9:24:9:24 | x | semmle.label | x |
| captured_variables.rb:10:5:10:6 | fn [captured x] | semmle.label | fn [captured x] |
| captured_variables.rb:10:10:10:23 | -> { ... } [captured x] | semmle.label | -> { ... } [captured x] |
| captured_variables.rb:10:20:10:20 | x | semmle.label | x |
| captured_variables.rb:11:5:11:6 | fn [captured x] | semmle.label | fn [captured x] |
| captured_variables.rb:13:20:13:29 | call to taint | semmle.label | call to taint |
| captured_variables.rb:15:28:15:28 | x | semmle.label | x |
| captured_variables.rb:16:5:18:5 | -> { ... } [captured x] | semmle.label | -> { ... } [captured x] |
| captured_variables.rb:17:14:17:14 | x | semmle.label | x |
| captured_variables.rb:20:1:20:35 | ( ... ) [captured x] | semmle.label | ( ... ) [captured x] |
| captured_variables.rb:20:2:20:34 | call to capture_escape_return1 [captured x] | semmle.label | call to capture_escape_return1 [captured x] |
| captured_variables.rb:20:25:20:34 | call to taint | semmle.label | call to taint |
| captured_variables.rb:22:28:22:28 | x | semmle.label | x |
| captured_variables.rb:23:5:25:5 | -> { ... } [captured x] | semmle.label | -> { ... } [captured x] |
| captured_variables.rb:24:14:24:14 | x | semmle.label | x |
| captured_variables.rb:27:25:27:57 | call to capture_escape_return2 [captured x] | semmle.label | call to capture_escape_return2 [captured x] |
| captured_variables.rb:27:48:27:57 | call to taint | semmle.label | call to taint |
| captured_variables.rb:29:33:29:33 | x | semmle.label | x |
| captured_variables.rb:30:5:30:6 | fn [captured x] | semmle.label | fn [captured x] |
| captured_variables.rb:30:10:32:5 | -> { ... } [captured x] | semmle.label | -> { ... } [captured x] |
| captured_variables.rb:31:14:31:14 | x | semmle.label | x |
| captured_variables.rb:33:29:33:30 | fn [captured x] | semmle.label | fn [captured x] |
| captured_variables.rb:35:29:35:38 | call to taint | semmle.label | call to taint |
| captured_variables.rb:37:13:37:14 | fn [captured x] | semmle.label | fn [captured x] |
| captured_variables.rb:38:5:38:6 | fn [captured x] | semmle.label | fn [captured x] |
| captured_variables.rb:40:31:40:31 | x | semmle.label | x |
| captured_variables.rb:41:5:41:6 | fn [captured x] | semmle.label | fn [captured x] |
| captured_variables.rb:41:10:43:5 | -> { ... } [captured x] | semmle.label | -> { ... } [captured x] |
| captured_variables.rb:42:14:42:14 | x | semmle.label | x |
| captured_variables.rb:44:13:44:14 | fn [captured x] | semmle.label | fn [captured x] |
| captured_variables.rb:46:27:46:36 | call to taint | semmle.label | call to taint |
| captured_variables.rb:48:1:48:1 | x | semmle.label | x |
| captured_variables.rb:48:5:48:12 | call to taint | semmle.label | call to taint |
| captured_variables.rb:49:16:52:3 | [post] do ... end [captured x] | semmle.label | [post] do ... end [captured x] |
| captured_variables.rb:49:16:52:3 | do ... end [captured x] | semmle.label | do ... end [captured x] |
| captured_variables.rb:50:10:50:10 | x | semmle.label | x |
| captured_variables.rb:51:5:51:5 | x | semmle.label | x |
| captured_variables.rb:51:9:51:16 | call to taint | semmle.label | call to taint |
| captured_variables.rb:54:6:54:6 | x | semmle.label | x |
| captured_variables.rb:57:19:57:19 | x | semmle.label | x |
@@ -211,34 +299,68 @@ nodes
| captured_variables.rb:61:16:61:21 | self [@field] | semmle.label | self [@field] |
| captured_variables.rb:66:1:66:3 | [post] foo [@field] | semmle.label | [post] foo [@field] |
| captured_variables.rb:66:15:66:22 | call to taint | semmle.label | call to taint |
| captured_variables.rb:67:16:70:3 | [post] do ... end [captured foo, @field] | semmle.label | [post] do ... end [captured foo, @field] |
| captured_variables.rb:67:16:70:3 | do ... end [captured foo, @field] | semmle.label | do ... end [captured foo, @field] |
| captured_variables.rb:68:10:68:12 | foo [@field] | semmle.label | foo [@field] |
| captured_variables.rb:68:10:68:22 | call to get_field | semmle.label | call to get_field |
| captured_variables.rb:69:5:69:7 | [post] foo [@field] | semmle.label | [post] foo [@field] |
| captured_variables.rb:69:19:69:26 | call to taint | semmle.label | call to taint |
| captured_variables.rb:72:6:72:8 | foo [@field] | semmle.label | foo [@field] |
| captured_variables.rb:72:6:72:18 | call to get_field | semmle.label | call to get_field |
| captured_variables.rb:85:1:85:1 | y | semmle.label | y |
| captured_variables.rb:78:20:80:7 | [post] do ... end [captured foo, @field] | semmle.label | [post] do ... end [captured foo, @field] |
| captured_variables.rb:79:9:79:11 | [post] foo [@field] | semmle.label | [post] foo [@field] |
| captured_variables.rb:79:23:79:30 | call to taint | semmle.label | call to taint |
| captured_variables.rb:83:6:83:8 | foo [@field] | semmle.label | foo [@field] |
| captured_variables.rb:83:6:83:18 | call to get_field | semmle.label | call to get_field |
| captured_variables.rb:85:5:85:12 | call to taint | semmle.label | call to taint |
| captured_variables.rb:86:1:86:2 | fn [captured y] | semmle.label | fn [captured y] |
| captured_variables.rb:86:6:89:1 | -> { ... } [captured y] | semmle.label | -> { ... } [captured y] |
| captured_variables.rb:87:10:87:10 | y | semmle.label | y |
| captured_variables.rb:88:5:88:5 | y | semmle.label | y |
| captured_variables.rb:88:9:88:16 | call to taint | semmle.label | call to taint |
| captured_variables.rb:90:1:90:2 | [post] fn [captured y] | semmle.label | [post] fn [captured y] |
| captured_variables.rb:90:1:90:2 | fn [captured y] | semmle.label | fn [captured y] |
| captured_variables.rb:91:6:91:6 | y | semmle.label | y |
| captured_variables.rb:93:17:93:17 | x | semmle.label | x |
| captured_variables.rb:94:5:96:5 | -> { ... } [captured x] | semmle.label | -> { ... } [captured x] |
| captured_variables.rb:95:14:95:14 | x | semmle.label | x |
| captured_variables.rb:98:1:98:21 | call to capture_arg [captured x] | semmle.label | call to capture_arg [captured x] |
| captured_variables.rb:98:13:98:20 | call to taint | semmle.label | call to taint |
| captured_variables.rb:100:21:100:21 | x | semmle.label | x |
| captured_variables.rb:101:11:101:11 | x | semmle.label | x |
| captured_variables.rb:104:17:104:24 | call to taint | semmle.label | call to taint |
| captured_variables.rb:104:31:104:31 | x | semmle.label | x |
| captured_variables.rb:105:10:105:10 | x | semmle.label | x |
| captured_variables.rb:109:5:109:5 | x | semmle.label | x |
| captured_variables.rb:109:9:109:17 | call to taint | semmle.label | call to taint |
| captured_variables.rb:110:5:110:10 | middle [captured x] | semmle.label | middle [captured x] |
| captured_variables.rb:110:14:116:5 | -> { ... } [captured x] | semmle.label | -> { ... } [captured x] |
| captured_variables.rb:111:9:111:13 | inner [captured x] | semmle.label | inner [captured x] |
| captured_variables.rb:111:17:114:9 | -> { ... } [captured x] | semmle.label | -> { ... } [captured x] |
| captured_variables.rb:112:18:112:18 | x | semmle.label | x |
| captured_variables.rb:113:13:113:13 | x | semmle.label | x |
| captured_variables.rb:113:17:113:25 | call to taint | semmle.label | call to taint |
| captured_variables.rb:115:9:115:13 | [post] inner [captured x] | semmle.label | [post] inner [captured x] |
| captured_variables.rb:115:9:115:13 | inner [captured x] | semmle.label | inner [captured x] |
| captured_variables.rb:117:5:117:10 | [post] middle [captured x] | semmle.label | [post] middle [captured x] |
| captured_variables.rb:117:5:117:10 | middle [captured x] | semmle.label | middle [captured x] |
| captured_variables.rb:118:10:118:10 | x | semmle.label | x |
| captured_variables.rb:147:5:147:6 | [post] self [@x] | semmle.label | [post] self [@x] |
| captured_variables.rb:147:10:147:18 | call to taint | semmle.label | call to taint |
| captured_variables.rb:149:5:151:7 | &block [captured self, @x] | semmle.label | &block [captured self, @x] |
| captured_variables.rb:153:14:155:7 | do ... end [captured self, @x] | semmle.label | do ... end [captured self, @x] |
| captured_variables.rb:154:14:154:15 | @x | semmle.label | @x |
| captured_variables.rb:154:14:154:15 | self [@x] | semmle.label | self [@x] |
| captured_variables.rb:160:9:160:10 | [post] self [@x] | semmle.label | [post] self [@x] |
| captured_variables.rb:160:14:160:22 | call to taint | semmle.label | call to taint |
| captured_variables.rb:163:5:165:7 | &block [captured self, @x] | semmle.label | &block [captured self, @x] |
| captured_variables.rb:167:5:171:7 | self in baz [@x] | semmle.label | self in baz [@x] |
| captured_variables.rb:168:18:170:11 | do ... end [captured self, @x] | semmle.label | do ... end [captured self, @x] |
| captured_variables.rb:169:18:169:19 | @x | semmle.label | @x |
| captured_variables.rb:169:18:169:19 | self [@x] | semmle.label | self [@x] |
| captured_variables.rb:174:1:174:24 | call to new [@x] | semmle.label | call to new [@x] |
| captured_variables.rb:178:9:178:10 | [post] self [@x] | semmle.label | [post] self [@x] |
| captured_variables.rb:178:14:178:22 | call to taint | semmle.label | call to taint |
| captured_variables.rb:181:5:183:7 | &block [captured self, @x] | semmle.label | &block [captured self, @x] |
| captured_variables.rb:185:5:189:7 | self in baz [@x] | semmle.label | self in baz [@x] |
| captured_variables.rb:186:18:188:11 | do ... end [captured self, @x] | semmle.label | do ... end [captured self, @x] |
| captured_variables.rb:187:18:187:19 | @x | semmle.label | @x |
| captured_variables.rb:187:18:187:19 | self [@x] | semmle.label | self [@x] |
| captured_variables.rb:193:1:193:1 | [post] c [@x] | semmle.label | [post] c [@x] |
@@ -348,10 +470,21 @@ nodes
| instance_variables.rb:121:7:121:24 | call to new | semmle.label | call to new |
| instance_variables.rb:122:6:122:8 | bar | semmle.label | bar |
subpaths
| captured_variables.rb:20:25:20:34 | call to taint | captured_variables.rb:15:28:15:28 | x | captured_variables.rb:16:5:18:5 | -> { ... } [captured x] | captured_variables.rb:20:2:20:34 | call to capture_escape_return1 [captured x] |
| captured_variables.rb:27:48:27:57 | call to taint | captured_variables.rb:22:28:22:28 | x | captured_variables.rb:23:5:25:5 | -> { ... } [captured x] | captured_variables.rb:27:25:27:57 | call to capture_escape_return2 [captured x] |
| captured_variables.rb:66:15:66:22 | call to taint | captured_variables.rb:57:19:57:19 | x | captured_variables.rb:58:9:58:14 | [post] self [@field] | captured_variables.rb:66:1:66:3 | [post] foo [@field] |
| captured_variables.rb:66:15:66:22 | call to taint | instance_variables.rb:10:19:10:19 | x | instance_variables.rb:11:9:11:14 | [post] self [@field] | captured_variables.rb:66:1:66:3 | [post] foo [@field] |
| captured_variables.rb:68:10:68:12 | foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field [@field] | captured_variables.rb:61:9:61:21 | return | captured_variables.rb:68:10:68:22 | call to get_field |
| captured_variables.rb:68:10:68:12 | foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field [@field] | instance_variables.rb:14:9:14:21 | return | captured_variables.rb:68:10:68:22 | call to get_field |
| captured_variables.rb:69:19:69:26 | call to taint | captured_variables.rb:57:19:57:19 | x | captured_variables.rb:58:9:58:14 | [post] self [@field] | captured_variables.rb:69:5:69:7 | [post] foo [@field] |
| captured_variables.rb:69:19:69:26 | call to taint | instance_variables.rb:10:19:10:19 | x | instance_variables.rb:11:9:11:14 | [post] self [@field] | captured_variables.rb:69:5:69:7 | [post] foo [@field] |
| captured_variables.rb:72:6:72:8 | foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field [@field] | captured_variables.rb:61:9:61:21 | return | captured_variables.rb:72:6:72:18 | call to get_field |
| captured_variables.rb:72:6:72:8 | foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field [@field] | instance_variables.rb:14:9:14:21 | return | captured_variables.rb:72:6:72:18 | call to get_field |
| captured_variables.rb:79:23:79:30 | call to taint | captured_variables.rb:57:19:57:19 | x | captured_variables.rb:58:9:58:14 | [post] self [@field] | captured_variables.rb:79:9:79:11 | [post] foo [@field] |
| captured_variables.rb:79:23:79:30 | call to taint | instance_variables.rb:10:19:10:19 | x | instance_variables.rb:11:9:11:14 | [post] self [@field] | captured_variables.rb:79:9:79:11 | [post] foo [@field] |
| captured_variables.rb:83:6:83:8 | foo [@field] | captured_variables.rb:60:5:62:7 | self in get_field [@field] | captured_variables.rb:61:9:61:21 | return | captured_variables.rb:83:6:83:18 | call to get_field |
| captured_variables.rb:83:6:83:8 | foo [@field] | instance_variables.rb:13:5:15:7 | self in get_field [@field] | instance_variables.rb:14:9:14:21 | return | captured_variables.rb:83:6:83:18 | call to get_field |
| captured_variables.rb:98:13:98:20 | call to taint | captured_variables.rb:93:17:93:17 | x | captured_variables.rb:94:5:96:5 | -> { ... } [captured x] | captured_variables.rb:98:1:98:21 | call to capture_arg [captured x] |
| instance_variables.rb:28:20:28:24 | field | instance_variables.rb:22:20:22:24 | field | instance_variables.rb:23:9:23:14 | [post] self [@field] | instance_variables.rb:28:9:28:25 | [post] self [@field] |
| instance_variables.rb:33:13:33:13 | x | instance_variables.rb:22:20:22:24 | field | instance_variables.rb:23:9:23:14 | [post] self [@field] | instance_variables.rb:33:9:33:14 | call to new [@field] |
| instance_variables.rb:36:10:36:23 | call to new [@field] | captured_variables.rb:60:5:62:7 | self in get_field [@field] | captured_variables.rb:61:9:61:21 | return | instance_variables.rb:36:10:36:33 | call to get_field |
@@ -416,18 +549,26 @@ subpaths
| instance_variables.rb:120:6:120: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:120:6:120:20 | call to get_field |
#select
| captured_variables.rb:10:20:10:20 | x | captured_variables.rb:13:20:13:29 | call to taint | captured_variables.rb:10:20:10:20 | x | $@ | captured_variables.rb:13:20:13:29 | call to taint | call to taint |
| captured_variables.rb:17:14:17:14 | x | captured_variables.rb:20:25:20:34 | call to taint | captured_variables.rb:17:14:17:14 | x | $@ | captured_variables.rb:20:25:20:34 | call to taint | call to taint |
| captured_variables.rb:24:14:24:14 | x | captured_variables.rb:27:48:27:57 | call to taint | captured_variables.rb:24:14:24:14 | x | $@ | captured_variables.rb:27:48:27:57 | call to taint | call to taint |
| captured_variables.rb:31:14:31:14 | x | captured_variables.rb:35:29:35:38 | call to taint | captured_variables.rb:31:14:31:14 | x | $@ | captured_variables.rb:35:29:35:38 | call to taint | call to taint |
| captured_variables.rb:42:14:42:14 | x | captured_variables.rb:46:27:46:36 | call to taint | captured_variables.rb:42:14:42:14 | x | $@ | captured_variables.rb:46:27:46:36 | call to taint | call to taint |
| captured_variables.rb:50:10:50:10 | x | captured_variables.rb:48:5:48:12 | call to taint | captured_variables.rb:50:10:50:10 | x | $@ | captured_variables.rb:48:5:48:12 | call to taint | call to taint |
| captured_variables.rb:54:6:54:6 | x | captured_variables.rb:48:5:48:12 | call to taint | captured_variables.rb:54:6:54:6 | x | $@ | captured_variables.rb:48:5:48:12 | call to taint | call to taint |
| captured_variables.rb:54:6:54:6 | x | captured_variables.rb:51:9:51:16 | call to taint | captured_variables.rb:54:6:54:6 | x | $@ | captured_variables.rb:51:9:51:16 | call to taint | call to taint |
| captured_variables.rb:68:10:68:22 | call to get_field | captured_variables.rb:66:15:66:22 | call to taint | captured_variables.rb:68:10:68:22 | call to get_field | $@ | captured_variables.rb:66:15:66:22 | call to taint | call to taint |
| captured_variables.rb:72:6:72:18 | call to get_field | captured_variables.rb:66:15:66:22 | call to taint | captured_variables.rb:72:6:72:18 | call to get_field | $@ | captured_variables.rb:66:15:66:22 | call to taint | call to taint |
| captured_variables.rb:72:6:72:18 | call to get_field | captured_variables.rb:69:19:69:26 | call to taint | captured_variables.rb:72:6:72:18 | call to get_field | $@ | captured_variables.rb:69:19:69:26 | call to taint | call to taint |
| captured_variables.rb:83:6:83:18 | call to get_field | captured_variables.rb:79:23:79:30 | call to taint | captured_variables.rb:83:6:83:18 | call to get_field | $@ | captured_variables.rb:79:23:79:30 | call to taint | call to taint |
| captured_variables.rb:87:10:87:10 | y | captured_variables.rb:85:5:85:12 | call to taint | captured_variables.rb:87:10:87:10 | y | $@ | captured_variables.rb:85:5:85:12 | call to taint | call to taint |
| captured_variables.rb:87:10:87:10 | y | captured_variables.rb:88:9:88:16 | call to taint | captured_variables.rb:87:10:87:10 | y | $@ | captured_variables.rb:88:9:88:16 | call to taint | call to taint |
| captured_variables.rb:91:6:91:6 | y | captured_variables.rb:85:5:85:12 | call to taint | captured_variables.rb:91:6:91:6 | y | $@ | captured_variables.rb:85:5:85:12 | call to taint | call to taint |
| captured_variables.rb:91:6:91:6 | y | captured_variables.rb:88:9:88:16 | call to taint | captured_variables.rb:91:6:91:6 | y | $@ | captured_variables.rb:88:9:88:16 | call to taint | call to taint |
| captured_variables.rb:95:14:95:14 | x | captured_variables.rb:98:13:98:20 | call to taint | captured_variables.rb:95:14:95:14 | x | $@ | captured_variables.rb:98:13:98:20 | call to taint | call to taint |
| captured_variables.rb:105:10:105:10 | x | captured_variables.rb:104:17:104:24 | call to taint | captured_variables.rb:105:10:105:10 | x | $@ | captured_variables.rb:104:17:104:24 | call to taint | call to taint |
| captured_variables.rb:112:18:112:18 | x | captured_variables.rb:109:9:109:17 | call to taint | captured_variables.rb:112:18:112:18 | x | $@ | captured_variables.rb:109:9:109:17 | call to taint | call to taint |
| captured_variables.rb:112:18:112:18 | x | captured_variables.rb:113:17:113:25 | call to taint | captured_variables.rb:112:18:112:18 | x | $@ | captured_variables.rb:113:17:113:25 | call to taint | call to taint |
| captured_variables.rb:118:10:118:10 | x | captured_variables.rb:109:9:109:17 | call to taint | captured_variables.rb:118:10:118:10 | x | $@ | captured_variables.rb:109:9:109:17 | call to taint | call to taint |
| captured_variables.rb:118:10:118:10 | x | captured_variables.rb:113:17:113:25 | call to taint | captured_variables.rb:118:10:118:10 | x | $@ | captured_variables.rb:113:17:113:25 | call to taint | call to taint |
| captured_variables.rb:154:14:154:15 | @x | captured_variables.rb:147:10:147:18 | call to taint | captured_variables.rb:154:14:154:15 | @x | $@ | captured_variables.rb:147:10:147:18 | call to taint | call to taint |
| captured_variables.rb:169:18:169:19 | @x | captured_variables.rb:160:14:160:22 | call to taint | captured_variables.rb:169:18:169:19 | @x | $@ | captured_variables.rb:160:14:160:22 | call to taint | call to taint |
| captured_variables.rb:187:18:187:19 | @x | captured_variables.rb:178:14:178:22 | call to taint | captured_variables.rb:187:18:187:19 | @x | $@ | captured_variables.rb:178:14:178:22 | call to taint | call to taint |
| instance_variables.rb:20:10:20:13 | @foo | instance_variables.rb:19:12:19:21 | call to taint | instance_variables.rb:20:10:20:13 | @foo | $@ | instance_variables.rb:19:12:19:21 | call to taint | call to taint |

View File

@@ -1,13 +1,13 @@
testFailures
| captured_variables.rb:17:14:17:14 | x | Fixed missing result:hasValueFlow=1.2 |
| captured_variables.rb:24:14:24:14 | x | Fixed missing result:hasValueFlow=1.3 |
| captured_variables.rb:50:10:50:10 | x | Fixed missing result:hasValueFlow=2 |
| captured_variables.rb:54:6:54:6 | x | Unexpected result: hasValueFlow=1 |
| captured_variables.rb:72:21:72:75 | # $ MISSING: hasValueFlow=4 $ SPURIOUS: hasValueFlow=3 | Fixed spurious result:hasValueFlow=3 |
| captured_variables.rb:91:6:91:6 | y | Unexpected result: hasValueFlow=6 |
| captured_variables.rb:95:14:95:14 | x | Fixed missing result:hasValueFlow=8 |
| captured_variables.rb:118:10:118:10 | x | Unexpected result: hasValueFlow=10 |
| captured_variables.rb:68:25:68:68 | # $ hasValueFlow=3 $ MISSING: hasValueFlow=4 | Missing result:hasValueFlow=3 |
| captured_variables.rb:72:21:72:66 | # $ hasValueFlow=4 $ SPURIOUS: hasValueFlow=3 | Fixed spurious result:hasValueFlow=3 |
| captured_variables.rb:72:21:72:66 | # $ hasValueFlow=4 $ SPURIOUS: hasValueFlow=3 | Missing result:hasValueFlow=4 |
| captured_variables.rb:83:21:83:38 | # $ hasValueFlow=5 | Missing result:hasValueFlow=5 |
| captured_variables.rb:87:10:87:10 | y | Unexpected result: hasValueFlow=7 |
| captured_variables.rb:112:18:112:18 | x | Unexpected result: hasValueFlow=11 |
| captured_variables.rb:126:14:126:14 | x | Fixed missing result:hasValueFlow=12 |
| captured_variables.rb:154:17:154:35 | # $ hasValueFlow=13 | Missing result:hasValueFlow=13 |
| instance_variables.rb:20:16:20:33 | # $ hasValueFlow=7 | Missing result:hasValueFlow=7 |
| instance_variables.rb:36:36:36:54 | # $ hasValueFlow=34 | Missing result:hasValueFlow=34 |
| instance_variables.rb:39:36:39:54 | # $ hasValueFlow=35 | Missing result:hasValueFlow=35 |

View File

@@ -14,14 +14,14 @@ capture_local_call taint(1.1)
def capture_escape_return1 x
-> {
sink(x) # $ MISSING: hasValueFlow=1.2
sink(x) # $ hasValueFlow=1.2
}
end
(capture_escape_return1 taint(1.2)).call
def capture_escape_return2 x
-> {
sink(x) # $ MISSING: hasValueFlow=1.3
sink(x) # $ hasValueFlow=1.3
}
end
Something.unknownMethod(capture_escape_return2 taint(1.3))
@@ -51,7 +51,7 @@ x = taint(1)
x = taint(2)
end
sink x # $ hasValueFlow=2
sink x # $ hasValueFlow=2 $ SPURIOUS: hasValueFlow=1
class Foo
def set_field x
@@ -65,11 +65,11 @@ end
foo = Foo.new
foo.set_field(taint(3))
[1, 2, 3].each do |i|
sink(foo.get_field) # $ MISSING: hasValueFlow=3 $ MISSING: hasValueFlow=4
sink(foo.get_field) # $ hasValueFlow=3 $ MISSING: hasValueFlow=4
foo.set_field(taint(4))
end
sink(foo.get_field) # $ MISSING: hasValueFlow=4 $ SPURIOUS: hasValueFlow=3
sink(foo.get_field) # $ hasValueFlow=4 $ SPURIOUS: hasValueFlow=3
foo = Foo.new
if (rand() < 0) then
@@ -80,19 +80,19 @@ else
end
end
sink(foo.get_field) # $ MISSING: hasValueFlow=5
sink(foo.get_field) # $ hasValueFlow=5
y = taint(6)
fn = -> {
sink(y) # $ hasValueFlow=6 $ SPURIOUS: hasValueFlow=7
sink(y) # $ hasValueFlow=6
y = taint(7)
}
fn.call
sink(y) # $ hasValueFlow=7
sink(y) # $ hasValueFlow=7 $ SPURIOUS: hasValueFlow=6
def capture_arg x
-> {
sink x # $ MISSING: hasValueFlow=8
sink x # $ hasValueFlow=8
}
end
capture_arg(taint(8)).call
@@ -109,13 +109,13 @@ def capture_nested
x = taint(10)
middle = -> {
inner = -> {
sink x # $ hasValueFlow=10 $ SPURIOUS: hasValueFlow=11
sink x # $ hasValueFlow=10
x = taint(11)
}
inner.call
}
middle.call
sink x # $ hasValueFlow=11
sink x # $ hasValueFlow=11 $ SPURIOUS: hasValueFlow=10
end
capture_nested
@@ -151,7 +151,7 @@ module CaptureModuleSelf
end
self.foo do
sink @x # $ MISSING: hasValueFlow=13
sink @x # $ hasValueFlow=13
end
end

View File

@@ -1,59 +1,57 @@
testFailures
edges
| summaries.rb:1:1:1:7 | tainted | summaries.rb:2:6:2:12 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:2:6:2:12 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:4:24:4:30 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:4:24:4:30 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:16:36:16:42 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:16:36:16:42 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:20:25:20:31 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:26:31:26:37 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:30:24:30:30 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:31:27:31:33 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:34:16:34:22 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:34:16:34:22 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:35:16:35:22 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:35:16:35:22 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:36:21:36:27 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:36:21:36:27 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:37:36:37:42 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:37:36:37:42 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:51:24:51:30 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:56:22:56:28 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:57:17:57:23 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:59:27:59:33 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:63:32:63:38 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:65:23:65:29 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:122:16:122:22 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:128:14:128:20 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:131:16:131:22 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:131:16:131:22 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:132:21:132:27 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:132:21:132:27 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:135:26:135:32 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:135:26:135:32 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:137:23:137:29 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:137:23:137:29 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:140:19:140:25 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:140:19:140:25 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:141:19:141:25 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:141:19:141:25 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:145:26:145:32 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:145:26:145:32 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:147:16:147:22 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:147:16:147:22 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:150:39:150:45 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:150:39:150:45 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:154:20:154:26 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:154:20:154:26 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:155:28:155:34 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:155:28:155:34 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:156:27:156:33 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:156:27:156:33 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:158:15:158:21 | tainted |
| summaries.rb:1:1:1:7 | tainted | summaries.rb:158:15:158:21 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:1:1:1:7 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:1:1:1:7 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:2:6:2:12 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:2:6:2:12 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:4:24:4:30 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:4:24:4:30 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:16:36:16:42 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:16:36:16:42 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:20:25:20:31 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:26:31:26:37 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:30:24:30:30 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:31:27:31:33 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:34:16:34:22 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:34:16:34:22 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:35:16:35:22 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:35:16:35:22 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:36:21:36:27 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:36:21:36:27 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:37:36:37:42 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:37:36:37:42 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:51:24:51:30 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:56:22:56:28 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:57:17:57:23 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:59:27:59:33 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:63:32:63:38 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:65:23:65:29 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:122:16:122:22 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:128:14:128:20 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:131:16:131:22 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:131:16:131:22 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:132:21:132:27 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:132:21:132:27 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:135:26:135:32 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:135:26:135:32 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:137:23:137:29 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:137:23:137:29 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:140:19:140:25 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:140:19:140:25 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:141:19:141:25 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:141:19:141:25 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:145:26:145:32 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:145:26:145:32 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:147:16:147:22 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:147:16:147:22 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:150:39:150:45 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:150:39:150:45 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:154:20:154:26 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:154:20:154:26 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:155:28:155:34 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:155:28:155:34 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:156:27:156:33 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:156:27:156:33 | tainted |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:157:14:160:3 | do ... end [captured tainted] |
| summaries.rb:1:11:1:36 | call to identity | summaries.rb:157:14:160:3 | do ... end [captured tainted] |
| summaries.rb:1:20:1:36 | call to source | summaries.rb:1:11:1:36 | call to identity |
| summaries.rb:1:20:1:36 | call to source | summaries.rb:1:11:1:36 | call to identity |
| summaries.rb:4:1:4:8 | tainted2 | summaries.rb:9:6:9:13 | tainted2 |
@@ -242,6 +240,7 @@ edges
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:154:20:154:26 | tainted |
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:155:28:155:34 | tainted |
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:156:27:156:33 | tainted |
| summaries.rb:122:16:122:22 | [post] tainted | summaries.rb:157:14:160:3 | do ... end [captured tainted] |
| summaries.rb:122:16:122:22 | tainted | summaries.rb:122:16:122:22 | [post] tainted |
| summaries.rb:122:16:122:22 | tainted | summaries.rb:122:25:122:25 | [post] y |
| summaries.rb:122:16:122:22 | tainted | summaries.rb:122:33:122:33 | [post] z |
@@ -249,9 +248,9 @@ edges
| summaries.rb:122:33:122:33 | [post] z | summaries.rb:125:6:125:6 | z |
| summaries.rb:128:1:128:1 | [post] x | summaries.rb:129:6:129:6 | x |
| summaries.rb:128:14:128:20 | tainted | summaries.rb:128:1:128:1 | [post] x |
| summaries.rb:157:14:160:3 | do ... end [captured tainted] | summaries.rb:158:15:158:21 | tainted |
| summaries.rb:157:14:160:3 | do ... end [captured tainted] | summaries.rb:158:15:158:21 | tainted |
nodes
| summaries.rb:1:1:1:7 | tainted | semmle.label | tainted |
| summaries.rb:1:1:1:7 | tainted | semmle.label | tainted |
| summaries.rb:1:11:1:36 | call to identity | semmle.label | call to identity |
| summaries.rb:1:11:1:36 | call to identity | semmle.label | call to identity |
| summaries.rb:1:20:1:36 | call to source | semmle.label | call to source |
@@ -491,6 +490,8 @@ nodes
| summaries.rb:155:28:155:34 | tainted | semmle.label | tainted |
| summaries.rb:156:27:156:33 | tainted | semmle.label | tainted |
| summaries.rb:156:27:156:33 | tainted | semmle.label | tainted |
| summaries.rb:157:14:160:3 | do ... end [captured tainted] | semmle.label | do ... end [captured tainted] |
| summaries.rb:157:14:160:3 | do ... end [captured tainted] | semmle.label | do ... end [captured tainted] |
| summaries.rb:158:15:158:21 | tainted | semmle.label | tainted |
| summaries.rb:158:15:158:21 | tainted | semmle.label | tainted |
| summaries.rb:163:20:163:36 | call to source | semmle.label | call to source |

View File

@@ -43,51 +43,43 @@ filterPatterns
| app.rb:106:3:108:5 | call to before | app.rb:106:10:106:23 | "/protected/*" |
| app.rb:111:3:113:5 | call to after | app.rb:111:9:111:23 | "/create/:slug" |
additionalFlowSteps
| app.rb:85:5:85:9 | [post] self | app.rb:2:22:4:5 | <captured entry> self |
| app.rb:85:5:85:9 | [post] self | app.rb:10:21:13:5 | <captured entry> self |
| app.rb:85:5:85:9 | [post] self | app.rb:15:23:18:5 | <captured entry> self |
| app.rb:85:5:85:9 | [post] self | app.rb:24:26:26:5 | <captured entry> self |
| app.rb:85:5:85:9 | [post] self | app.rb:37:16:42:5 | <captured entry> self |
| app.rb:85:5:85:9 | [post] self | app.rb:44:53:46:5 | <captured entry> self |
| app.rb:85:5:85:9 | [post] self | app.rb:56:32:58:5 | <captured entry> self |
| app.rb:85:5:85:9 | [post] self | app.rb:60:48:62:5 | <captured entry> self |
| app.rb:85:5:85:9 | [post] self | app.rb:74:11:77:5 | <captured entry> self |
| app.rb:85:5:85:9 | [post] self | app.rb:79:11:82:5 | <captured entry> self |
| app.rb:85:5:85:9 | [post] self | app.rb:89:16:92:5 | <captured entry> self |
| app.rb:85:5:85:9 | [post] self | app.rb:94:15:96:5 | <captured entry> self |
| app.rb:86:5:86:11 | [post] self | app.rb:2:22:4:5 | <captured entry> self |
| app.rb:86:5:86:11 | [post] self | app.rb:10:21:13:5 | <captured entry> self |
| app.rb:86:5:86:11 | [post] self | app.rb:15:23:18:5 | <captured entry> self |
| app.rb:86:5:86:11 | [post] self | app.rb:24:26:26:5 | <captured entry> self |
| app.rb:86:5:86:11 | [post] self | app.rb:37:16:42:5 | <captured entry> self |
| app.rb:86:5:86:11 | [post] self | app.rb:44:53:46:5 | <captured entry> self |
| app.rb:86:5:86:11 | [post] self | app.rb:56:32:58:5 | <captured entry> self |
| app.rb:86:5:86:11 | [post] self | app.rb:60:48:62:5 | <captured entry> self |
| app.rb:86:5:86:11 | [post] self | app.rb:74:11:77:5 | <captured entry> self |
| app.rb:86:5:86:11 | [post] self | app.rb:79:11:82:5 | <captured entry> self |
| app.rb:86:5:86:11 | [post] self | app.rb:89:16:92:5 | <captured entry> self |
| app.rb:86:5:86:11 | [post] self | app.rb:94:15:96:5 | <captured entry> self |
| app.rb:103:5:103:9 | [post] self | app.rb:2:22:4:5 | <captured entry> self |
| app.rb:103:5:103:9 | [post] self | app.rb:10:21:13:5 | <captured entry> self |
| app.rb:103:5:103:9 | [post] self | app.rb:15:23:18:5 | <captured entry> self |
| app.rb:103:5:103:9 | [post] self | app.rb:24:26:26:5 | <captured entry> self |
| app.rb:103:5:103:9 | [post] self | app.rb:37:16:42:5 | <captured entry> self |
| app.rb:103:5:103:9 | [post] self | app.rb:44:53:46:5 | <captured entry> self |
| app.rb:103:5:103:9 | [post] self | app.rb:56:32:58:5 | <captured entry> self |
| app.rb:103:5:103:9 | [post] self | app.rb:60:48:62:5 | <captured entry> self |
| app.rb:103:5:103:9 | [post] self | app.rb:74:11:77:5 | <captured entry> self |
| app.rb:103:5:103:9 | [post] self | app.rb:79:11:82:5 | <captured entry> self |
| app.rb:103:5:103:9 | [post] self | app.rb:89:16:92:5 | <captured entry> self |
| app.rb:103:5:103:9 | [post] self | app.rb:94:15:96:5 | <captured entry> self |
| app.rb:103:13:103:22 | [post] self | app.rb:2:22:4:5 | <captured entry> self |
| app.rb:103:13:103:22 | [post] self | app.rb:10:21:13:5 | <captured entry> self |
| app.rb:103:13:103:22 | [post] self | app.rb:15:23:18:5 | <captured entry> self |
| app.rb:103:13:103:22 | [post] self | app.rb:24:26:26:5 | <captured entry> self |
| app.rb:103:13:103:22 | [post] self | app.rb:37:16:42:5 | <captured entry> self |
| app.rb:103:13:103:22 | [post] self | app.rb:44:53:46:5 | <captured entry> self |
| app.rb:103:13:103:22 | [post] self | app.rb:56:32:58:5 | <captured entry> self |
| app.rb:103:13:103:22 | [post] self | app.rb:60:48:62:5 | <captured entry> self |
| app.rb:103:13:103:22 | [post] self | app.rb:74:11:77:5 | <captured entry> self |
| app.rb:103:13:103:22 | [post] self | app.rb:79:11:82:5 | <captured entry> self |
| app.rb:103:13:103:22 | [post] self | app.rb:89:16:92:5 | <captured entry> self |
| app.rb:103:13:103:22 | [post] self | app.rb:94:15:96:5 | <captured entry> self |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:2:22:4:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:6:24:8:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:10:21:13:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:15:23:18:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:20:23:22:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:24:26:26:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:28:26:31:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:33:25:35:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:37:16:42:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:44:53:46:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:48:14:50:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:52:37:54:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:56:32:58:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:60:48:62:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:66:41:68:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:70:20:72:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:74:11:77:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:79:11:82:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:89:16:92:5 | lambda self in do ... end |
| app.rb:84:10:87:5 | [post] do ... end | app.rb:94:15:96:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:2:22:4:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:6:24:8:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:10:21:13:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:15:23:18:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:20:23:22:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:24:26:26:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:28:26:31:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:33:25:35:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:37:16:42:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:44:53:46:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:48:14:50:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:52:37:54:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:56:32:58:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:60:48:62:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:66:41:68:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:70:20:72:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:74:11:77:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:79:11:82:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:89:16:92:5 | lambda self in do ... end |
| app.rb:102:10:104:5 | [post] do ... end | app.rb:94:15:96:5 | lambda self in do ... end |

View File

@@ -7,15 +7,15 @@ edges
| ErbInjection.rb:8:5:8:12 | bad_text | ErbInjection.rb:19:20:19:27 | bad_text |
| ErbInjection.rb:8:16:11:14 | ... % ... | ErbInjection.rb:8:5:8:12 | bad_text |
| ErbInjection.rb:11:11:11:14 | name | ErbInjection.rb:8:16:11:14 | ... % ... |
| SlimInjection.rb:5:5:5:8 | name | SlimInjection.rb:8:5:8:12 | bad_text |
| SlimInjection.rb:5:5:5:8 | name | SlimInjection.rb:11:11:11:14 | name |
| SlimInjection.rb:5:5:5:8 | name | SlimInjection.rb:17:5:17:13 | bad2_text |
| SlimInjection.rb:5:5:5:8 | name | SlimInjection.rb:14:23:14:34 | { ... } [captured bad_text] |
| SlimInjection.rb:5:5:5:8 | name | SlimInjection.rb:23:23:23:35 | { ... } [captured bad2_text] |
| SlimInjection.rb:5:12:5:17 | call to params | SlimInjection.rb:5:12:5:24 | ...[...] |
| SlimInjection.rb:5:12:5:24 | ...[...] | SlimInjection.rb:5:5:5:8 | name |
| SlimInjection.rb:8:5:8:12 | bad_text | SlimInjection.rb:14:25:14:32 | bad_text |
| SlimInjection.rb:8:16:11:14 | ... % ... | SlimInjection.rb:8:5:8:12 | bad_text |
| SlimInjection.rb:8:16:11:14 | ... % ... | SlimInjection.rb:14:23:14:34 | { ... } [captured bad_text] |
| SlimInjection.rb:11:11:11:14 | name | SlimInjection.rb:8:16:11:14 | ... % ... |
| SlimInjection.rb:17:5:17:13 | bad2_text | SlimInjection.rb:23:25:23:33 | bad2_text |
| SlimInjection.rb:14:23:14:34 | { ... } [captured bad_text] | SlimInjection.rb:14:25:14:32 | bad_text |
| SlimInjection.rb:23:23:23:35 | { ... } [captured bad2_text] | SlimInjection.rb:23:25:23:33 | bad2_text |
nodes
| ErbInjection.rb:5:5:5:8 | name | semmle.label | name |
| ErbInjection.rb:5:12:5:17 | call to params | semmle.label | call to params |
@@ -28,11 +28,11 @@ nodes
| SlimInjection.rb:5:5:5:8 | name | semmle.label | name |
| SlimInjection.rb:5:12:5:17 | call to params | semmle.label | call to params |
| SlimInjection.rb:5:12:5:24 | ...[...] | semmle.label | ...[...] |
| SlimInjection.rb:8:5:8:12 | bad_text | semmle.label | bad_text |
| SlimInjection.rb:8:16:11:14 | ... % ... | semmle.label | ... % ... |
| SlimInjection.rb:11:11:11:14 | name | semmle.label | name |
| SlimInjection.rb:14:23:14:34 | { ... } [captured bad_text] | semmle.label | { ... } [captured bad_text] |
| SlimInjection.rb:14:25:14:32 | bad_text | semmle.label | bad_text |
| SlimInjection.rb:17:5:17:13 | bad2_text | semmle.label | bad2_text |
| SlimInjection.rb:23:23:23:35 | { ... } [captured bad2_text] | semmle.label | { ... } [captured bad2_text] |
| SlimInjection.rb:23:25:23:33 | bad2_text | semmle.label | bad2_text |
subpaths
#select

View File

@@ -5,7 +5,9 @@ edges
| ArchiveApiPathTraversal.rb:10:11:10:23 | ...[...] | ArchiveApiPathTraversal.rb:67:13:67:16 | file |
| ArchiveApiPathTraversal.rb:15:9:15:14 | call to params | ArchiveApiPathTraversal.rb:15:9:15:25 | ...[...] |
| ArchiveApiPathTraversal.rb:15:9:15:25 | ...[...] | ArchiveApiPathTraversal.rb:75:11:75:18 | filename |
| ArchiveApiPathTraversal.rb:49:17:49:27 | destination | ArchiveApiPathTraversal.rb:52:38:52:48 | destination |
| ArchiveApiPathTraversal.rb:49:17:49:27 | destination | ArchiveApiPathTraversal.rb:50:36:64:7 | do ... end [captured destination] |
| ArchiveApiPathTraversal.rb:50:36:64:7 | do ... end [captured destination] | ArchiveApiPathTraversal.rb:51:16:63:9 | do ... end [captured destination] |
| ArchiveApiPathTraversal.rb:51:16:63:9 | do ... end [captured destination] | ArchiveApiPathTraversal.rb:52:38:52:48 | destination |
| ArchiveApiPathTraversal.rb:52:9:52:24 | destination_file | ArchiveApiPathTraversal.rb:59:21:59:36 | destination_file |
| ArchiveApiPathTraversal.rb:52:28:52:67 | call to join | ArchiveApiPathTraversal.rb:52:9:52:24 | destination_file |
| ArchiveApiPathTraversal.rb:52:38:52:48 | destination | ArchiveApiPathTraversal.rb:52:28:52:67 | call to join |
@@ -72,6 +74,8 @@ nodes
| ArchiveApiPathTraversal.rb:15:9:15:14 | call to params | semmle.label | call to params |
| ArchiveApiPathTraversal.rb:15:9:15:25 | ...[...] | semmle.label | ...[...] |
| ArchiveApiPathTraversal.rb:49:17:49:27 | destination | semmle.label | destination |
| ArchiveApiPathTraversal.rb:50:36:64:7 | do ... end [captured destination] | semmle.label | do ... end [captured destination] |
| ArchiveApiPathTraversal.rb:51:16:63:9 | do ... end [captured destination] | semmle.label | do ... end [captured destination] |
| ArchiveApiPathTraversal.rb:52:9:52:24 | destination_file | semmle.label | destination_file |
| ArchiveApiPathTraversal.rb:52:28:52:67 | call to join | semmle.label | call to join |
| ArchiveApiPathTraversal.rb:52:38:52:48 | destination | semmle.label | destination |

View File

@@ -4,14 +4,16 @@ edges
| app/controllers/users_controller.rb:15:5:15:15 | unsanitized | app/controllers/users_controller.rb:23:20:23:30 | unsanitized |
| app/controllers/users_controller.rb:15:19:15:24 | call to params | app/controllers/users_controller.rb:15:19:15:30 | ...[...] |
| app/controllers/users_controller.rb:15:19:15:30 | ...[...] | app/controllers/users_controller.rb:15:5:15:15 | unsanitized |
| app/controllers/users_controller.rb:23:5:23:16 | unsanitized2 | app/controllers/users_controller.rb:25:7:25:18 | unsanitized2 |
| app/controllers/users_controller.rb:23:5:23:16 | unsanitized2 | app/controllers/users_controller.rb:27:16:27:39 | ... + ... |
| app/controllers/users_controller.rb:23:20:23:30 | unsanitized | app/controllers/users_controller.rb:23:20:23:44 | call to sub |
| app/controllers/users_controller.rb:23:20:23:44 | call to sub | app/controllers/users_controller.rb:23:5:23:16 | unsanitized2 |
| app/controllers/users_controller.rb:33:5:33:15 | unsanitized | app/controllers/users_controller.rb:34:33:34:43 | unsanitized |
| app/controllers/users_controller.rb:33:5:33:15 | unsanitized | app/controllers/users_controller.rb:35:33:35:55 | ... + ... |
| app/controllers/users_controller.rb:23:20:23:44 | call to sub | app/controllers/users_controller.rb:24:18:26:7 | do ... end [captured unsanitized2] |
| app/controllers/users_controller.rb:23:20:23:44 | call to sub | app/controllers/users_controller.rb:27:16:27:39 | ... + ... |
| app/controllers/users_controller.rb:24:18:26:7 | do ... end [captured unsanitized2] | app/controllers/users_controller.rb:25:7:25:18 | unsanitized2 |
| app/controllers/users_controller.rb:33:19:33:25 | call to cookies | app/controllers/users_controller.rb:33:19:33:31 | ...[...] |
| app/controllers/users_controller.rb:33:19:33:31 | ...[...] | app/controllers/users_controller.rb:33:5:33:15 | unsanitized |
| app/controllers/users_controller.rb:33:19:33:31 | ...[...] | app/controllers/users_controller.rb:34:31:34:45 | { ... } [captured unsanitized] |
| app/controllers/users_controller.rb:33:19:33:31 | ...[...] | app/controllers/users_controller.rb:35:31:35:57 | { ... } [captured unsanitized] |
| app/controllers/users_controller.rb:34:31:34:45 | { ... } [captured unsanitized] | app/controllers/users_controller.rb:34:33:34:43 | unsanitized |
| app/controllers/users_controller.rb:35:31:35:57 | { ... } [captured unsanitized] | app/controllers/users_controller.rb:35:45:35:55 | unsanitized |
| app/controllers/users_controller.rb:35:45:35:55 | unsanitized | app/controllers/users_controller.rb:35:33:35:55 | ... + ... |
| app/controllers/users_controller.rb:49:19:49:24 | call to params | app/controllers/users_controller.rb:49:19:49:30 | ...[...] |
nodes
| app/controllers/users_controller.rb:15:5:15:15 | unsanitized | semmle.label | unsanitized |
@@ -19,16 +21,18 @@ nodes
| app/controllers/users_controller.rb:15:19:15:30 | ...[...] | semmle.label | ...[...] |
| app/controllers/users_controller.rb:16:19:16:29 | unsanitized | semmle.label | unsanitized |
| app/controllers/users_controller.rb:17:19:17:41 | ... + ... | semmle.label | ... + ... |
| app/controllers/users_controller.rb:23:5:23:16 | unsanitized2 | semmle.label | unsanitized2 |
| app/controllers/users_controller.rb:23:20:23:30 | unsanitized | semmle.label | unsanitized |
| app/controllers/users_controller.rb:23:20:23:44 | call to sub | semmle.label | call to sub |
| app/controllers/users_controller.rb:24:18:26:7 | do ... end [captured unsanitized2] | semmle.label | do ... end [captured unsanitized2] |
| app/controllers/users_controller.rb:25:7:25:18 | unsanitized2 | semmle.label | unsanitized2 |
| app/controllers/users_controller.rb:27:16:27:39 | ... + ... | semmle.label | ... + ... |
| app/controllers/users_controller.rb:33:5:33:15 | unsanitized | semmle.label | unsanitized |
| app/controllers/users_controller.rb:33:19:33:25 | call to cookies | semmle.label | call to cookies |
| app/controllers/users_controller.rb:33:19:33:31 | ...[...] | semmle.label | ...[...] |
| app/controllers/users_controller.rb:34:31:34:45 | { ... } [captured unsanitized] | semmle.label | { ... } [captured unsanitized] |
| app/controllers/users_controller.rb:34:33:34:43 | unsanitized | semmle.label | unsanitized |
| app/controllers/users_controller.rb:35:31:35:57 | { ... } [captured unsanitized] | semmle.label | { ... } [captured unsanitized] |
| app/controllers/users_controller.rb:35:33:35:55 | ... + ... | semmle.label | ... + ... |
| app/controllers/users_controller.rb:35:45:35:55 | unsanitized | semmle.label | unsanitized |
| app/controllers/users_controller.rb:49:19:49:24 | call to params | semmle.label | call to params |
| app/controllers/users_controller.rb:49:19:49:30 | ...[...] | semmle.label | ...[...] |
subpaths