Ruby: Adopt shared type tracking library

This commit is contained in:
Tom Hvitved
2023-11-06 13:00:44 +01:00
parent 620e8dcb37
commit 6ce8e0510f
27 changed files with 696 additions and 593 deletions

View File

@@ -462,10 +462,6 @@
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll",
"swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll"
],
"TypeTracker": [
"python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll",
"ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll"
],
"SummaryTypeTracker": [
"python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll",
"ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll"
@@ -534,4 +530,4 @@
"python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ext.yml",
"python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml"
]
}
}

View File

@@ -0,0 +1,8 @@
import codeql.ruby.DataFlow
import codeql.ruby.typetracking.internal.TypeTrackingImpl
private module ConsistencyChecksInput implements ConsistencyChecksInputSig {
predicate unreachableNodeExclude(DataFlow::Node n) { n instanceof DataFlow::PostUpdateNode }
}
import ConsistencyChecks<ConsistencyChecksInput>

View File

@@ -8,8 +8,7 @@
private import codeql.ruby.AST
private import codeql.ruby.DataFlow
private import codeql.ruby.typetracking.ApiGraphShared
private import codeql.ruby.typetracking.TypeTracker
private import codeql.ruby.typetracking.TypeTrackerSpecific as TypeTrackerSpecific
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
private import codeql.ruby.controlflow.CfgNodes
private import codeql.ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
private import codeql.ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch
@@ -1050,9 +1049,9 @@ module API {
/** INTERNAL USE ONLY. */
module Internal {
private module Shared = ApiGraphShared<SharedArg>;
private module MkShared = ApiGraphShared<SharedArg>;
import Shared
import MkShared
/** Gets the API node corresponding to the module/class object for `mod`. */
bindingset[mod]
@@ -1093,7 +1092,7 @@ module API {
private predicate needsSinkNode(DataFlow::Node node) {
node instanceof DataFlowPrivate::ArgumentNode
or
TypeTrackerSpecific::basicStoreStep(node, _, _)
TypeTrackingInput::storeStep(node, _, _)
or
node = any(DataFlow::CallableNode callable).getAReturnNode()
or
@@ -1203,10 +1202,8 @@ module API {
cached
predicate contentEdge(Node pred, DataFlow::Content content, Node succ) {
exists(
DataFlow::Node object, DataFlow::Node value, TypeTrackerSpecific::TypeTrackerContent c
|
TypeTrackerSpecific::basicLoadStep(object, value, c) and
exists(DataFlow::Node object, DataFlow::Node value, DataFlow::ContentSet c |
TypeTrackingInput::loadStep(object, value, c) and
content = c.getAStoreContent() and
not c.isSingleton(any(DataFlow::Content::AttributeNameContent k)) and
// `x -> x.foo` with content "foo"
@@ -1214,7 +1211,7 @@ module API {
succ = getForwardStartNode(value)
or
// Based on `object.c = value` generate `object -> value` with content `c`
TypeTrackerSpecific::basicStoreStep(value, object, c) and
TypeTrackingInput::storeStep(value, object, c) and
content = c.getAStoreContent() and
pred = getForwardOrBackwardEndNode(getALocalSourceStrict(object)) and
succ = MkSinkNode(value)

View File

@@ -2,7 +2,7 @@
import codeql.ruby.AST
private import codeql.ruby.CFG
private import codeql.ruby.typetracking.TypeTracker
private import codeql.ruby.typetracking.TypeTracking
import codeql.ruby.DataFlow
private import internal.FlowSummaryImpl as Impl
private import internal.DataFlowDispatch

View File

@@ -1,8 +1,7 @@
private import codeql.ruby.AST
private import codeql.ruby.CFG
private import DataFlowPrivate
private import codeql.ruby.typetracking.TypeTracker
private import codeql.ruby.typetracking.TypeTrackerSpecific as TypeTrackerSpecific
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
private import codeql.ruby.ast.internal.Module
private import FlowSummaryImpl as FlowSummaryImpl
private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
@@ -657,7 +656,7 @@ private module TrackInstanceInput implements CallGraphConstruction::InputSig {
predicate stepNoCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
// We exclude steps into `self` parameters. For those, we instead rely on the type of
// the enclosing module
StepSummary::smallstepNoCall(nodeFrom, nodeTo, summary) and
smallStepNoCall(nodeFrom, nodeTo, summary) and
isNotSelf(nodeTo)
or
// We exclude steps into type checked variables. For those, we instead rely on the
@@ -667,7 +666,7 @@ private module TrackInstanceInput implements CallGraphConstruction::InputSig {
}
predicate stepCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
StepSummary::smallstepCall(nodeFrom, nodeTo, summary)
smallStepCall(nodeFrom, nodeTo, summary)
}
class StateProj = Unit;
@@ -941,7 +940,7 @@ private module TrackSingletonMethodOnInstanceInput implements CallGraphConstruct
RelevantCall call, DataFlow::Node arg, DataFlow::ParameterNode p,
CfgNodes::ExprCfgNode nodeFromPreExpr
|
TypeTrackerSpecific::callStep(call, arg, p) and
callStep(call, arg, p) and
nodeTo.getPreUpdateNode() = arg and
summary.toString() = "return" and
(
@@ -965,13 +964,13 @@ private module TrackSingletonMethodOnInstanceInput implements CallGraphConstruct
}
predicate stepNoCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
StepSummary::smallstepNoCall(nodeFrom, nodeTo, summary)
smallStepNoCall(nodeFrom, nodeTo, summary)
or
localFlowStep(nodeFrom, nodeTo, summary)
}
predicate stepCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
StepSummary::smallstepCall(nodeFrom, nodeTo, summary)
smallStepCall(nodeFrom, nodeTo, summary)
or
paramReturnFlow(nodeFrom, nodeTo, summary)
}

View File

@@ -113,7 +113,7 @@ module LocalFlow {
SsaImpl::lastRefBeforeRedefExt(def, bb, i, next.getDefinitionExt()) and
exprFrom = bb.getNode(i) and
exprFrom.getExpr() instanceof VariableReadAccess and
exprFrom = [nodeFrom.asExpr(), nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr()]
exprFrom = [nodeFrom.asExpr(), nodeFrom.(PostUpdateNodeImpl).getPreUpdateNode().asExpr()]
)
}
@@ -159,7 +159,7 @@ module LocalFlow {
firstReadExt(def, nodeTo.asExpr())
or
// Flow from post-update read to next read
localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNodeImpl).getPreUpdateNode(), nodeTo)
or
// Flow into phi (read) SSA definition node from def
localFlowSsaInputFromDef(nodeFrom, def, nodeTo)
@@ -456,7 +456,7 @@ private predicate splatArgumentAt(CfgNodes::ExprNodes::CallCfgNode c, int pos) {
/** A collection of cached types and predicates to be evaluated in the same stage. */
cached
private module Cached {
private import codeql.ruby.typetracking.TypeTrackerSpecific as TypeTrackerSpecific
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
cached
newtype TNode =
@@ -575,14 +575,10 @@ private module Cached {
VariableCapture::flowInsensitiveStep(nodeFrom, nodeTo)
}
/** Holds if `n` wraps an SSA definition without ingoing flow. */
private predicate entrySsaDefinition(SsaDefinitionExtNode n) {
n = LocalFlow::getParameterDefNode(_)
or
exists(SsaImpl::DefinitionExt def | def = n.getDefinitionExt() |
def instanceof Ssa::SelfDefinition
or
def instanceof Ssa::CapturedEntryDefinition
)
n.getDefinitionExt() =
any(SsaImpl::WriteDefinition def | not def.(Ssa::WriteDefinition).assigns(_))
}
pragma[nomagic]
@@ -599,6 +595,16 @@ private module Cached {
)
}
private predicate isStoreTargetNode(Node n) {
TypeTrackingInput::storeStep(_, n, _)
or
TypeTrackingInput::loadStoreStep(_, n, _, _)
or
TypeTrackingInput::withContentStepImpl(_, n, _)
or
TypeTrackingInput::withoutContentStepImpl(_, n, _)
}
cached
predicate isLocalSourceNode(Node n) {
n instanceof TSourceParameterNode
@@ -614,11 +620,9 @@ private module Cached {
entrySsaDefinition(n) and
not LocalFlow::localFlowSsaParamInput(_, n)
or
TypeTrackerSpecific::basicStoreStep(_, n, _)
isStoreTargetNode(n)
or
TypeTrackerSpecific::basicLoadStep(_, n, _)
or
TypeTrackerSpecific::basicLoadStoreStep(_, n, _, _)
TypeTrackingInput::loadStep(_, n, _)
}
cached
@@ -633,7 +637,7 @@ private module Cached {
TElementContentOfTypeContent(string type, Boolean includeUnknown) {
type = any(Content::KnownElementContent content).getIndex().getValueType()
} or
TNoContentSet() // Only used by type-tracking
deprecated TNoContentSet() // Only used by type-tracking
cached
class TContentSet =

View File

@@ -2,10 +2,9 @@ private import codeql.ruby.AST
private import DataFlowDispatch
private import DataFlowPrivate
private import codeql.ruby.CFG
private import codeql.ruby.typetracking.TypeTracker
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
private import codeql.ruby.dataflow.SSA
private import FlowSummaryImpl as FlowSummaryImpl
private import SsaImpl as SsaImpl
private import codeql.ruby.ApiGraphs
/**
@@ -245,7 +244,7 @@ class LocalSourceNode extends Node {
/** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */
pragma[inline]
predicate flowsTo(Node nodeTo) { hasLocalSource(nodeTo, this) }
predicate flowsTo(Node nodeTo) { flowsTo(this, nodeTo) }
/**
* Gets a node that this node may flow to using one heap and/or interprocedural step.
@@ -261,14 +260,14 @@ class LocalSourceNode extends Node {
* See `TypeBackTracker` for more details about how to use this.
*/
pragma[inline]
LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t2 = t.step(result, this) }
LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t = t2.step(result, this) }
/**
* Gets a node to which data may flow from this node in zero or
* more local data-flow steps.
*/
pragma[inline]
Node getALocalUse() { hasLocalSource(result, this) }
Node getALocalUse() { flowsTo(this, result) }
/** Gets a method call where this node flows to the receiver. */
CallNode getAMethodCall() { Cached::hasMethodCall(this, result, _) }
@@ -354,21 +353,21 @@ class PostUpdateNode extends Node instanceof PostUpdateNodeImpl {
Node getPreUpdateNode() { result = super.getPreUpdateNode() }
}
/** An SSA definition, viewed as a node in a data flow graph. */
class SsaDefinitionNode extends Node instanceof SsaDefinitionExtNode {
Ssa::Definition def;
SsaDefinitionNode() { this = TSsaDefinitionExtNode(def) }
/** Gets the underlying SSA definition. */
Ssa::Definition getDefinition() { result = def }
/** Gets the underlying variable. */
Variable getVariable() { result = def.getSourceVariable() }
}
cached
private module Cached {
cached
predicate hasLocalSource(Node sink, Node source) {
// Declaring `source` to be a `SourceNode` currently causes a redundant check in the
// recursive case, so instead we check it explicitly here.
source = sink and
source instanceof LocalSourceNode
or
exists(Node mid |
hasLocalSource(mid, source) and
localFlowStepTypeTracker(mid, sink)
)
}
cached
predicate hasMethodCall(LocalSourceNode source, CallNode call, string name) {
source.flowsTo(call.getReceiver()) and

View File

@@ -5,7 +5,7 @@
private import codeql.ruby.Concepts
private import codeql.ruby.AST
private import codeql.ruby.DataFlow
private import codeql.ruby.typetracking.TypeTracker
private import codeql.ruby.typetracking.TypeTracking
private import codeql.ruby.ApiGraphs
private import codeql.ruby.controlflow.CfgNodes as CfgNodes

View File

@@ -6,7 +6,7 @@ private import codeql.ruby.AST
private import codeql.ruby.ApiGraphs
private import codeql.ruby.Concepts
private import codeql.ruby.DataFlow
private import codeql.ruby.typetracking.TypeTracker
private import codeql.ruby.typetracking.TypeTracking
private import Response::Private as RP
/**

View File

@@ -7,7 +7,7 @@ private import codeql.ruby.ApiGraphs
private import codeql.ruby.Concepts
private import codeql.ruby.controlflow.CfgNodes::ExprNodes
private import codeql.ruby.DataFlow
private import codeql.ruby.typetracking.TypeTracker
private import codeql.ruby.typetracking.TypeTracking
private import App as A
/** Contains implementation details for modeling `Rack::Response`. */

View File

@@ -17,7 +17,7 @@ private import codeql.ruby.AST as Ast
private import codeql.ruby.CFG
private import codeql.ruby.DataFlow
private import codeql.ruby.controlflow.CfgNodes
private import codeql.ruby.typetracking.TypeTracker
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
private import codeql.ruby.ApiGraphs
private import codeql.ruby.Concepts
private import codeql.ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
@@ -67,7 +67,7 @@ private signature module TypeTrackInputSig {
* Provides a version of type tracking where we first prune for reachable nodes,
* before doing the type tracking computation.
*/
private module TypeTrack<TypeTrackInputSig Input> {
private module PrunedTypeTrack<TypeTrackInputSig Input> {
private predicate additionalStep(
DataFlow::LocalSourceNode nodeFrom, DataFlow::LocalSourceNode nodeTo
) {
@@ -130,10 +130,10 @@ private module TypeTrack<TypeTrackInputSig Input> {
TypeTracker t, DataFlow::LocalSourceNode nodeFrom, DataFlow::LocalSourceNode nodeTo
) {
exists(StepSummary summary |
StepSummary::step(nodeFrom, nodeTo, summary) and
step(nodeFrom, nodeTo, summary) and
reached(nodeFrom, t) and
reached(nodeTo, result) and
result = t.append(summary)
result = append(t, summary)
)
or
additionalStep(nodeFrom, nodeTo) and
@@ -195,7 +195,7 @@ private module StringTypeTrackInput implements TypeTrackInputSig {
* This is used to figure out where `start` is evaluated as a regular expression against an input string,
* or where `start` is compiled into a regular expression.
*/
private predicate trackStrings = TypeTrack<StringTypeTrackInput>::track/2;
private predicate trackStrings = PrunedTypeTrack<StringTypeTrackInput>::track/2;
/** Holds if `strConst` flows to a regex compilation (tracked by `t`), where the resulting regular expression is stored in `reg`. */
pragma[nomagic]
@@ -222,7 +222,7 @@ private module RegTypeTrackInput implements TypeTrackInputSig {
* Gets a node that has been tracked from the regular expression `start` to some node.
* This is used to figure out where `start` is executed against an input string.
*/
private predicate trackRegs = TypeTrack<RegTypeTrackInput>::track/2;
private predicate trackRegs = PrunedTypeTrack<RegTypeTrackInput>::track/2;
/** Gets a node that references a regular expression. */
private DataFlow::LocalSourceNode trackRegexpType(TypeTracker t) {

View File

@@ -7,7 +7,7 @@
private import codeql.ruby.AST
private import codeql.ruby.DataFlow
private import codeql.ruby.Concepts
private import codeql.ruby.typetracking.TypeTracker
private import codeql.ruby.typetracking.TypeTracking
private import codeql.ruby.frameworks.Files
private import codeql.ruby.frameworks.core.IO

View File

@@ -7,7 +7,7 @@ private import internal.CryptoAlgorithmNames
private import codeql.ruby.Concepts
private import codeql.ruby.DataFlow
private import codeql.ruby.ApiGraphs
private import codeql.ruby.typetracking.TypeTracker
private import codeql.ruby.typetracking.TypeTracking
bindingset[algorithmString]
private string algorithmRegex(string algorithmString) {

View File

@@ -6,6 +6,7 @@
private import codeql.ruby.AST
private import codeql.ruby.Concepts
private import codeql.ruby.DataFlow
private import codeql.ruby.dataflow.SSA
private import codeql.ruby.controlflow.CfgNodes
private import codeql.ruby.frameworks.core.Kernel
@@ -29,10 +30,10 @@ module StackTraceExposure {
*/
class BacktraceCall extends Source, DataFlow::CallNode {
BacktraceCall() {
exists(DataFlow::LocalSourceNode varAccess |
varAccess.asExpr().(ExprNodes::VariableReadAccessCfgNode).getExpr().getVariable() =
any(RescueClause rc).getVariableExpr().(VariableAccess).getVariable() and
varAccess.flowsTo(this.getReceiver())
exists(DataFlow::SsaDefinitionNode ssaDef |
ssaDef.getDefinition().(Ssa::WriteDefinition).getWriteAccess().getAstNode() =
any(RescueClause rc).getVariableExpr() and
ssaDef.(DataFlow::LocalSourceNode).flowsTo(this.getReceiver())
) and
this.getMethodName() = ["backtrace", "backtrace_locations"]
}

View File

@@ -8,6 +8,7 @@ private import ruby
private import codeql.ruby.ApiGraphs
private import codeql.ruby.frameworks.core.Gem::Gem as Gem
private import codeql.ruby.Concepts as Concepts
private import codeql.ruby.typetracking.TypeTracking
/**
* Module containing sources, sinks, and sanitizers for code constructed from library input.
@@ -39,22 +40,20 @@ module UnsafeCodeConstruction {
/** Gets a node that is eventually executed as code at `codeExec`. */
DataFlow::Node getANodeExecutedAsCode(Concepts::CodeExecution codeExec) {
result = getANodeExecutedAsCode(TypeTracker::TypeBackTracker::end(), codeExec)
result = getANodeExecutedAsCode(TypeBackTracker::end(), codeExec)
}
import codeql.ruby.typetracking.TypeTracker as TypeTracker
deprecated import codeql.ruby.typetracking.TypeTracker as TypeTracker
/** Gets a node that is eventually executed as code at `codeExec`, type-tracked with `t`. */
private DataFlow::LocalSourceNode getANodeExecutedAsCode(
TypeTracker::TypeBackTracker t, Concepts::CodeExecution codeExec
TypeBackTracker t, Concepts::CodeExecution codeExec
) {
t.start() and
result = codeExec.getCode().getALocalSource() and
codeExec.runsArbitraryCode() // methods like `Object.send` is benign here, because of the string-construction the attacker cannot control the entire method name
or
exists(TypeTracker::TypeBackTracker t2 |
result = getANodeExecutedAsCode(t2, codeExec).backtrack(t2, t)
)
exists(TypeBackTracker t2 | result = getANodeExecutedAsCode(t2, codeExec).backtrack(t2, t))
}
/**

View File

@@ -7,6 +7,7 @@
private import ruby
private import codeql.ruby.ApiGraphs
private import codeql.ruby.frameworks.core.Gem::Gem as Gem
private import codeql.ruby.typetracking.TypeTracking
/**
* Module containing sources, sinks, and sanitizers for HTML constructed from library input.
@@ -37,21 +38,17 @@ module UnsafeHtmlConstruction {
/** Gets a node that eventually ends up in the XSS `sink`. */
private DataFlow::Node getANodeThatEndsInXssSink(ReflectedXss::Sink sink) {
result = getANodeThatEndsInXssSink(TypeTracker::TypeBackTracker::end(), sink)
result = getANodeThatEndsInXssSink(TypeBackTracker::end(), sink)
}
private import codeql.ruby.typetracking.TypeTracker as TypeTracker
/** Gets a node that is eventually ends up in the XSS `sink`, type-tracked with `t`. */
private DataFlow::LocalSourceNode getANodeThatEndsInXssSink(
TypeTracker::TypeBackTracker t, ReflectedXss::Sink sink
TypeBackTracker t, ReflectedXss::Sink sink
) {
t.start() and
result = sink.getALocalSource()
or
exists(TypeTracker::TypeBackTracker t2 |
result = getANodeThatEndsInXssSink(t2, sink).backtrack(t2, t)
)
exists(TypeBackTracker t2 | result = getANodeThatEndsInXssSink(t2, sink).backtrack(t2, t))
}
/**

View File

@@ -9,6 +9,7 @@ private import codeql.ruby.DataFlow
private import codeql.ruby.ApiGraphs
private import codeql.ruby.frameworks.core.Gem::Gem as Gem
private import codeql.ruby.Concepts as Concepts
import codeql.ruby.typetracking.TypeTracking
/**
* Module containing sources, sinks, and sanitizers for shell command constructed from library input.
@@ -44,20 +45,18 @@ module UnsafeShellCommandConstruction {
/** Holds if the string constructed at `source` is executed at `shellExec` */
predicate isUsedAsShellCommand(DataFlow::Node source, Concepts::SystemCommandExecution shellExec) {
source = backtrackShellExec(TypeTracker::TypeBackTracker::end(), shellExec)
source = backtrackShellExec(TypeBackTracker::end(), shellExec)
}
import codeql.ruby.typetracking.TypeTracker as TypeTracker
deprecated import codeql.ruby.typetracking.TypeTracker as TypeTracker
private DataFlow::LocalSourceNode backtrackShellExec(
TypeTracker::TypeBackTracker t, Concepts::SystemCommandExecution shellExec
TypeBackTracker t, Concepts::SystemCommandExecution shellExec
) {
t.start() and
result = any(DataFlow::Node n | shellExec.isShellInterpreted(n)).getALocalSource()
or
exists(TypeTracker::TypeBackTracker t2 |
result = backtrackShellExec(t2, shellExec).backtrack(t2, t)
)
exists(TypeBackTracker t2 | result = backtrackShellExec(t2, shellExec).backtrack(t2, t))
}
/**

View File

@@ -5,8 +5,8 @@
*/
private import codeql.Locations
private import codeql.ruby.typetracking.TypeTracker
private import TypeTrackerSpecific
private import codeql.ruby.DataFlow
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
/**
* The signature to use when instantiating `ApiGraphShared`.
@@ -37,14 +37,14 @@ signature module ApiGraphSharedSig {
*
* This node will have outgoing epsilon edges to its type-tracking successors.
*/
ApiNode getForwardNode(TypeTrackingNode node, TypeTracker t);
ApiNode getForwardNode(DataFlow::LocalSourceNode node, TypeTracker t);
/**
* Gets the backward node with the given type-tracking state.
*
* This node will have outgoing epsilon edges to its type-tracking predecessors.
*/
ApiNode getBackwardNode(TypeTrackingNode node, TypeTracker t);
ApiNode getBackwardNode(DataFlow::LocalSourceNode node, TypeTracker t);
/**
* Gets the sink node corresponding to `node`.
@@ -55,7 +55,7 @@ signature module ApiGraphSharedSig {
*
* Sink nodes have outgoing epsilon edges to the backward nodes corresponding to their local sources.
*/
ApiNode getSinkNode(Node node);
ApiNode getSinkNode(DataFlow::Node node);
/**
* Holds if a language-specific epsilon edge `pred -> succ` should be generated.
@@ -72,7 +72,9 @@ module ApiGraphShared<ApiGraphSharedSig S> {
/** Gets a local source of `node`. */
bindingset[node]
pragma[inline_late]
TypeTrackingNode getALocalSourceStrict(Node node) { result = node.getALocalSource() }
DataFlow::LocalSourceNode getALocalSourceStrict(DataFlow::Node node) {
result = node.getALocalSource()
}
cached
private module Cached {
@@ -85,23 +87,21 @@ module ApiGraphShared<ApiGraphSharedSig S> {
cached
predicate epsilonEdge(ApiNode pred, ApiNode succ) {
exists(
StepSummary summary, TypeTrackingNode predNode, TypeTracker predState,
TypeTrackingNode succNode, TypeTracker succState
StepSummary summary, DataFlow::LocalSourceNode predNode, TypeTracker predState,
DataFlow::LocalSourceNode succNode, TypeTracker succState
|
StepSummary::stepCall(predNode, succNode, summary)
or
StepSummary::stepNoCall(predNode, succNode, summary)
step(predNode, succNode, summary)
|
pred = getForwardNode(predNode, predState) and
succState = StepSummary::append(predState, summary) and
succState = append(predState, summary) and
succ = getForwardNode(succNode, succState)
or
succ = getBackwardNode(predNode, predState) and // swap order for backward flow
succState = StepSummary::append(predState, summary) and
succState = append(predState, summary) and
pred = getBackwardNode(succNode, succState) // swap order for backward flow
)
or
exists(Node sink, TypeTrackingNode localSource |
exists(DataFlow::Node sink, DataFlow::LocalSourceNode localSource |
pred = getSinkNode(sink) and
localSource = getALocalSourceStrict(sink) and
succ = getBackwardStartNode(localSource)
@@ -121,39 +121,39 @@ module ApiGraphShared<ApiGraphSharedSig S> {
/** Gets the API node to use when starting forward flow from `source` */
cached
ApiNode forwardStartNode(TypeTrackingNode source) {
result = getForwardNode(source, TypeTracker::end(false))
ApiNode forwardStartNode(DataFlow::LocalSourceNode source) {
result = getForwardNode(source, noContentTypeTracker(false))
}
/** Gets the API node to use when starting backward flow from `sink` */
cached
ApiNode backwardStartNode(TypeTrackingNode sink) {
ApiNode backwardStartNode(DataFlow::LocalSourceNode sink) {
// There is backward flow A->B iff there is forward flow B->A.
// The starting point of backward flow corresponds to the end of a forward flow, and vice versa.
result = getBackwardNode(sink, TypeTracker::end(_))
result = getBackwardNode(sink, noContentTypeTracker(_))
}
/** Gets `node` as a data flow source. */
cached
TypeTrackingNode asSourceCached(ApiNode node) { node = forwardEndNode(result) }
DataFlow::LocalSourceNode asSourceCached(ApiNode node) { node = forwardEndNode(result) }
/** Gets `node` as a data flow sink. */
cached
Node asSinkCached(ApiNode node) { node = getSinkNode(result) }
DataFlow::Node asSinkCached(ApiNode node) { node = getSinkNode(result) }
}
private import Cached
/** Gets an API node corresponding to the end of forward-tracking to `localSource`. */
pragma[nomagic]
private ApiNode forwardEndNode(TypeTrackingNode localSource) {
result = getForwardNode(localSource, TypeTracker::end(_))
private ApiNode forwardEndNode(DataFlow::LocalSourceNode localSource) {
result = getForwardNode(localSource, noContentTypeTracker(_))
}
/** Gets an API node corresponding to the end of backtracking to `localSource`. */
pragma[nomagic]
private ApiNode backwardEndNode(TypeTrackingNode localSource) {
result = getBackwardNode(localSource, TypeTracker::end(false))
private ApiNode backwardEndNode(DataFlow::LocalSourceNode localSource) {
result = getBackwardNode(localSource, noContentTypeTracker(false))
}
/** Gets a node reachable from `node` by zero or more epsilon edges, including `node` itself. */
@@ -164,18 +164,18 @@ module ApiGraphShared<ApiGraphSharedSig S> {
/** Gets `node` as a data flow sink. */
bindingset[node]
pragma[inline_late]
Node asSinkInline(ApiNode node) { result = asSinkCached(node) }
DataFlow::Node asSinkInline(ApiNode node) { result = asSinkCached(node) }
/** Gets `node` as a data flow source. */
bindingset[node]
pragma[inline_late]
TypeTrackingNode asSourceInline(ApiNode node) { result = asSourceCached(node) }
DataFlow::LocalSourceNode asSourceInline(ApiNode node) { result = asSourceCached(node) }
/** Gets a value reachable from `source`. */
bindingset[source]
pragma[inline_late]
Node getAValueReachableFromSourceInline(ApiNode source) {
exists(TypeTrackingNode src |
DataFlow::Node getAValueReachableFromSourceInline(ApiNode source) {
exists(DataFlow::LocalSourceNode src |
src = asSourceInline(getAnEpsilonSuccessorInline(source)) and
src.flowsTo(pragma[only_bind_into](result))
)
@@ -184,7 +184,7 @@ module ApiGraphShared<ApiGraphSharedSig S> {
/** Gets a value that can reach `sink`. */
bindingset[sink]
pragma[inline_late]
Node getAValueReachingSinkInline(ApiNode sink) {
DataFlow::Node getAValueReachingSinkInline(ApiNode sink) {
backwardStartNode(result) = getAnEpsilonSuccessorInline(sink)
}
@@ -195,7 +195,7 @@ module ApiGraphShared<ApiGraphSharedSig S> {
*/
bindingset[node]
pragma[inline_late]
ApiNode getForwardStartNode(Node node) { result = forwardStartNode(node) }
ApiNode getForwardStartNode(DataFlow::Node node) { result = forwardStartNode(node) }
/**
* Gets the starting point of backtracking from `node`.
@@ -204,7 +204,7 @@ module ApiGraphShared<ApiGraphSharedSig S> {
*/
bindingset[node]
pragma[inline_late]
ApiNode getBackwardStartNode(Node node) { result = backwardStartNode(node) }
ApiNode getBackwardStartNode(DataFlow::Node node) { result = backwardStartNode(node) }
/**
* Gets a possible ending point of forward-tracking at `node`.
@@ -216,7 +216,7 @@ module ApiGraphShared<ApiGraphSharedSig S> {
*/
bindingset[node]
pragma[inline_late]
ApiNode getForwardEndNode(Node node) { result = forwardEndNode(node) }
ApiNode getForwardEndNode(DataFlow::Node node) { result = forwardEndNode(node) }
/**
* Gets a possible ending point backtracking to `node`.
@@ -228,7 +228,7 @@ module ApiGraphShared<ApiGraphSharedSig S> {
*/
bindingset[node]
pragma[inline_late]
ApiNode getBackwardEndNode(Node node) { result = backwardEndNode(node) }
ApiNode getBackwardEndNode(DataFlow::Node node) { result = backwardEndNode(node) }
/**
* Gets a possible eding point of forward or backward tracking at `node`.
@@ -237,19 +237,19 @@ module ApiGraphShared<ApiGraphSharedSig S> {
*/
bindingset[node]
pragma[inline_late]
ApiNode getForwardOrBackwardEndNode(Node node) {
ApiNode getForwardOrBackwardEndNode(DataFlow::Node node) {
result = getForwardEndNode(node) or result = getBackwardEndNode(node)
}
/** Gets an API node for tracking forward starting at `node`. This is the implementation of `DataFlow::LocalSourceNode.track()` */
bindingset[node]
pragma[inline_late]
ApiNode getNodeForForwardTracking(Node node) { result = forwardStartNode(node) }
ApiNode getNodeForForwardTracking(DataFlow::Node node) { result = forwardStartNode(node) }
/** Gets an API node for backtracking starting at `node`. The implementation of `DataFlow::Node.backtrack()`. */
bindingset[node]
pragma[inline_late]
ApiNode getNodeForBacktracking(Node node) {
ApiNode getNodeForBacktracking(DataFlow::Node node) {
result = getBackwardStartNode(getALocalSourceStrict(node))
}

View File

@@ -8,22 +8,22 @@ private module Cached {
* A description of a step on an inter-procedural data flow path.
*/
cached
newtype TStepSummary =
deprecated newtype TStepSummary =
LevelStep() or
CallStep() or
ReturnStep() or
StoreStep(TypeTrackerContent content) { basicStoreStep(_, _, content) } or
LoadStep(TypeTrackerContent content) { basicLoadStep(_, _, content) } or
LoadStoreStep(TypeTrackerContent load, TypeTrackerContent store) {
deprecated StoreStep(TypeTrackerContent content) { basicStoreStep(_, _, content) } or
deprecated LoadStep(TypeTrackerContent content) { basicLoadStep(_, _, content) } or
deprecated LoadStoreStep(TypeTrackerContent load, TypeTrackerContent store) {
basicLoadStoreStep(_, _, load, store)
} or
WithContent(ContentFilter filter) { basicWithContentStep(_, _, filter) } or
WithoutContent(ContentFilter filter) { basicWithoutContentStep(_, _, filter) } or
deprecated WithContent(ContentFilter filter) { basicWithContentStep(_, _, filter) } or
deprecated WithoutContent(ContentFilter filter) { basicWithoutContentStep(_, _, filter) } or
JumpStep()
cached
newtype TTypeTracker =
MkTypeTracker(Boolean hasCall, OptionalTypeTrackerContent content) {
deprecated newtype TTypeTracker =
deprecated MkTypeTracker(Boolean hasCall, OptionalTypeTrackerContent content) {
content = noContent()
or
// Restrict `content` to those that might eventually match a load.
@@ -40,8 +40,8 @@ private module Cached {
}
cached
newtype TTypeBackTracker =
MkTypeBackTracker(Boolean hasReturn, OptionalTypeTrackerContent content) {
deprecated newtype TTypeBackTracker =
deprecated MkTypeBackTracker(Boolean hasReturn, OptionalTypeTrackerContent content) {
content = noContent()
or
// As in MkTypeTracker, restrict `content` to those that might eventually match a store.
@@ -57,11 +57,13 @@ private module Cached {
/** Gets a type tracker with no content and the call bit set to the given value. */
cached
TypeTracker noContentTypeTracker(boolean hasCall) { result = MkTypeTracker(hasCall, noContent()) }
deprecated TypeTracker noContentTypeTracker(boolean hasCall) {
result = MkTypeTracker(hasCall, noContent())
}
/** Gets the summary resulting from appending `step` to type-tracking summary `tt`. */
cached
TypeTracker append(TypeTracker tt, StepSummary step) {
deprecated TypeTracker append(TypeTracker tt, StepSummary step) {
exists(Boolean hasCall, OptionalTypeTrackerContent currentContents |
tt = MkTypeTracker(hasCall, currentContents)
|
@@ -108,13 +110,13 @@ private module Cached {
}
pragma[nomagic]
private TypeBackTracker noContentTypeBackTracker(boolean hasReturn) {
deprecated private TypeBackTracker noContentTypeBackTracker(boolean hasReturn) {
result = MkTypeBackTracker(hasReturn, noContent())
}
/** Gets the summary resulting from prepending `step` to this type-tracking summary. */
cached
TypeBackTracker prepend(TypeBackTracker tbt, StepSummary step) {
deprecated TypeBackTracker prepend(TypeBackTracker tbt, StepSummary step) {
exists(Boolean hasReturn, OptionalTypeTrackerContent content |
tbt = MkTypeBackTracker(hasReturn, content)
|
@@ -167,7 +169,9 @@ private module Cached {
* Steps contained in this predicate should _not_ depend on the call graph.
*/
cached
predicate stepNoCall(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
deprecated predicate stepNoCall(
TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary
) {
exists(Node mid | nodeFrom.flowsTo(mid) and smallstepNoCall(mid, nodeTo, summary))
}
@@ -176,12 +180,14 @@ private module Cached {
* inter-procedural step from `nodeFrom` to `nodeTo`.
*/
cached
predicate stepCall(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
deprecated predicate stepCall(
TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary
) {
exists(Node mid | nodeFrom.flowsTo(mid) and smallstepCall(mid, nodeTo, summary))
}
cached
predicate smallstepNoCall(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
deprecated predicate smallstepNoCall(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
jumpStep(nodeFrom, nodeTo) and
summary = JumpStep()
or
@@ -210,7 +216,7 @@ private module Cached {
}
cached
predicate smallstepCall(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
deprecated predicate smallstepCall(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
callStep(nodeFrom, nodeTo) and summary = CallStep()
or
returnStep(nodeFrom, nodeTo) and
@@ -223,25 +229,27 @@ private module Cached {
private import Cached
private predicate step(TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
deprecated private predicate step(
TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo, StepSummary summary
) {
stepNoCall(nodeFrom, nodeTo, summary)
or
stepCall(nodeFrom, nodeTo, summary)
}
pragma[nomagic]
private predicate stepProj(TypeTrackingNode nodeFrom, StepSummary summary) {
deprecated private predicate stepProj(TypeTrackingNode nodeFrom, StepSummary summary) {
step(nodeFrom, _, summary)
}
private predicate smallstep(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
deprecated private predicate smallstep(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
smallstepNoCall(nodeFrom, nodeTo, summary)
or
smallstepCall(nodeFrom, nodeTo, summary)
}
pragma[nomagic]
private predicate smallstepProj(Node nodeFrom, StepSummary summary) {
deprecated private predicate smallstepProj(Node nodeFrom, StepSummary summary) {
smallstep(nodeFrom, _, summary)
}
@@ -270,7 +278,7 @@ private predicate smallstepProj(Node nodeFrom, StepSummary summary) {
* function. This means we will track the fact that `x.attr` can have the type of `y` into the
* assignment to `z` inside `bar`, even though this attribute write happens _after_ `bar` is called.
*/
private predicate flowsToStoreStep(
deprecated private predicate flowsToStoreStep(
Node nodeFrom, TypeTrackingNode nodeTo, TypeTrackerContent content
) {
exists(Node obj | nodeTo.flowsTo(obj) and basicStoreStep(nodeFrom, obj, content))
@@ -279,7 +287,7 @@ private predicate flowsToStoreStep(
/**
* Holds if `loadContent` is loaded from `nodeFrom` and written to `storeContent` of `nodeTo`.
*/
private predicate flowsToLoadStoreStep(
deprecated private predicate flowsToLoadStoreStep(
Node nodeFrom, TypeTrackingNode nodeTo, TypeTrackerContent loadContent,
TypeTrackerContent storeContent
) {
@@ -293,7 +301,7 @@ private predicate flowsToLoadStoreStep(
*
* A description of a step on an inter-procedural data flow path.
*/
class StepSummary extends TStepSummary {
deprecated class StepSummary extends TStepSummary {
/** Gets a textual representation of this step summary. */
string toString() {
this instanceof LevelStep and result = "level"
@@ -316,7 +324,7 @@ class StepSummary extends TStepSummary {
}
/** Provides predicates for updating step summaries (`StepSummary`s). */
module StepSummary {
deprecated module StepSummary {
predicate append = Cached::append/2;
/**
@@ -437,7 +445,7 @@ module StepSummary {
* `t = t2.step(myType(t2), result)`. If you additionally want to track individual
* intra-procedural steps, use `t = t2.smallstep(myCallback(t2), result)`.
*/
class TypeTracker extends TTypeTracker {
deprecated class TypeTracker extends TTypeTracker {
Boolean hasCall;
OptionalTypeTrackerContent content;
@@ -565,7 +573,7 @@ class TypeTracker extends TTypeTracker {
}
/** Provides predicates for implementing custom `TypeTracker`s. */
module TypeTracker {
deprecated module TypeTracker {
/**
* Gets a valid end point of type tracking.
*/
@@ -580,11 +588,11 @@ module TypeTracker {
}
pragma[nomagic]
private predicate backStepProj(TypeTrackingNode nodeTo, StepSummary summary) {
deprecated private predicate backStepProj(TypeTrackingNode nodeTo, StepSummary summary) {
step(_, nodeTo, summary)
}
private predicate backSmallstepProj(TypeTrackingNode nodeTo, StepSummary summary) {
deprecated private predicate backSmallstepProj(TypeTrackingNode nodeTo, StepSummary summary) {
smallstep(_, nodeTo, summary)
}
@@ -618,7 +626,7 @@ private predicate backSmallstepProj(TypeTrackingNode nodeTo, StepSummary summary
* `t2 = t.step(result, myCallback(t2))`. If you additionally want to track individual
* intra-procedural steps, use `t2 = t.smallstep(result, myCallback(t2))`.
*/
class TypeBackTracker extends TTypeBackTracker {
deprecated class TypeBackTracker extends TTypeBackTracker {
Boolean hasReturn;
OptionalTypeTrackerContent content;
@@ -747,7 +755,7 @@ class TypeBackTracker extends TTypeBackTracker {
}
/** Provides predicates for implementing custom `TypeBackTracker`s. */
module TypeBackTracker {
deprecated module TypeBackTracker {
/**
* Gets a valid end point of type back-tracking.
*/
@@ -768,14 +776,14 @@ module TypeBackTracker {
* `stepCall` relation (`stepNoCall` not being recursive, can be join-ordered in the
* same way as in `stepInlineLate`).
*/
module CallGraphConstruction {
deprecated module CallGraphConstruction {
/** The input to call graph construction. */
signature module InputSig {
/** A state to track during type tracking. */
class State;
/** Holds if type tracking should start at `start` in state `state`. */
predicate start(Node start, State state);
deprecated predicate start(Node start, State state);
/**
* Holds if type tracking should use the step from `nodeFrom` to `nodeTo`,
@@ -784,7 +792,7 @@ module CallGraphConstruction {
* Implementing this predicate using `StepSummary::[small]stepNoCall` yields
* standard type tracking.
*/
predicate stepNoCall(Node nodeFrom, Node nodeTo, StepSummary summary);
deprecated predicate stepNoCall(Node nodeFrom, Node nodeTo, StepSummary summary);
/**
* Holds if type tracking should use the step from `nodeFrom` to `nodeTo`,
@@ -793,7 +801,7 @@ module CallGraphConstruction {
* Implementing this predicate using `StepSummary::[small]stepCall` yields
* standard type tracking.
*/
predicate stepCall(Node nodeFrom, Node nodeTo, StepSummary summary);
deprecated predicate stepCall(Node nodeFrom, Node nodeTo, StepSummary summary);
/** A projection of an element from the state space. */
class StateProj;
@@ -802,25 +810,25 @@ module CallGraphConstruction {
StateProj stateProj(State state);
/** Holds if type tracking should stop at `n` when we are tracking projected state `stateProj`. */
predicate filter(Node n, StateProj stateProj);
deprecated predicate filter(Node n, StateProj stateProj);
}
/** Provides the `track` predicate for use in call graph construction. */
module Make<InputSig Input> {
pragma[nomagic]
private predicate stepNoCallProj(Node nodeFrom, StepSummary summary) {
deprecated private predicate stepNoCallProj(Node nodeFrom, StepSummary summary) {
Input::stepNoCall(nodeFrom, _, summary)
}
pragma[nomagic]
private predicate stepCallProj(Node nodeFrom, StepSummary summary) {
deprecated private predicate stepCallProj(Node nodeFrom, StepSummary summary) {
Input::stepCall(nodeFrom, _, summary)
}
bindingset[nodeFrom, t]
pragma[inline_late]
pragma[noopt]
private TypeTracker stepNoCallInlineLate(
deprecated private TypeTracker stepNoCallInlineLate(
TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo
) {
exists(StepSummary summary |
@@ -837,7 +845,7 @@ module CallGraphConstruction {
}
pragma[nomagic]
private Node track(Input::State state, TypeTracker t) {
deprecated private Node track(Input::State state, TypeTracker t) {
t.start() and Input::start(result, state)
or
exists(Input::StateProj stateProj |
@@ -855,12 +863,12 @@ module CallGraphConstruction {
bindingset[t, summary]
pragma[inline_late]
private TypeTracker appendInlineLate(TypeTracker t, StepSummary summary) {
deprecated private TypeTracker appendInlineLate(TypeTracker t, StepSummary summary) {
result = t.append(summary)
}
pragma[nomagic]
private Node trackCall(Input::State state, TypeTracker t, StepSummary summary) {
deprecated private Node trackCall(Input::State state, TypeTracker t, StepSummary summary) {
exists(TypeTracker t2 |
// non-linear recursion
result = track(state, t2) and
@@ -871,7 +879,7 @@ module CallGraphConstruction {
/** Gets a node that can be reached from _some_ start node in state `state`. */
pragma[nomagic]
Node track(Input::State state) { result = track(state, TypeTracker::end()) }
deprecated Node track(Input::State state) { result = track(state, TypeTracker::end()) }
}
/** A simple version of `CallGraphConstruction` that uses standard type tracking. */
@@ -882,15 +890,15 @@ module CallGraphConstruction {
class State;
/** Holds if type tracking should start at `start` in state `state`. */
predicate start(Node start, State state);
deprecated predicate start(Node start, State state);
/** Holds if type tracking should stop at `n`. */
predicate filter(Node n);
deprecated predicate filter(Node n);
}
/** Provides the `track` predicate for use in call graph construction. */
module Make<InputSig Input> {
private module I implements CallGraphConstruction::InputSig {
deprecated private module I implements CallGraphConstruction::InputSig {
private import codeql.util.Unit
class State = Input::State;
@@ -915,7 +923,7 @@ module CallGraphConstruction {
}
}
import CallGraphConstruction::Make<I>
deprecated import CallGraphConstruction::Make<I>
}
}
}

View File

@@ -9,21 +9,19 @@ private import codeql.ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatc
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
private import internal.TypeTrackingImpl as TypeTrackingImpl
import codeql.util.Boolean
class Node = DataFlowPublic::Node;
deprecated class Node = DataFlowPublic::Node;
class TypeTrackingNode = DataFlowPublic::LocalSourceNode;
deprecated class TypeTrackingNode = DataFlowPublic::LocalSourceNode;
class TypeTrackerContent = DataFlowPublic::ContentSet;
private module SCS = SummaryComponentStack;
private module SC = SummaryComponent;
deprecated class TypeTrackerContent = DataFlowPublic::ContentSet;
/**
* An optional content set, that is, a `ContentSet` or the special "no content set" value.
*/
class OptionalTypeTrackerContent extends DataFlowPrivate::TOptionalContentSet {
deprecated class OptionalTypeTrackerContent extends DataFlowPrivate::TOptionalContentSet {
/** Gets a textual representation of this content set. */
string toString() {
this instanceof DataFlowPrivate::TNoContentSet and
@@ -33,178 +31,45 @@ class OptionalTypeTrackerContent extends DataFlowPrivate::TOptionalContentSet {
}
}
private newtype TContentFilter = MkElementFilter()
/**
* A label to use for `WithContent` and `WithoutContent` steps, restricting
* which `ContentSet` may pass through.
*/
class ContentFilter extends TContentFilter {
/** Gets a string representation of this content filter. */
string toString() { this = MkElementFilter() and result = "elements" }
/** Gets the content of a type-tracker that matches this filter. */
TypeTrackerContent getAMatchingContent() {
this = MkElementFilter() and
result.getAReadContent() instanceof DataFlow::Content::ElementContent
}
}
deprecated class ContentFilter = TypeTrackingImpl::TypeTrackingInput::ContentFilter;
/** Module for getting `ContentFilter` values. */
module ContentFilter {
deprecated module ContentFilter {
/** Gets the filter that only allow element contents. */
ContentFilter hasElements() { result = MkElementFilter() }
ContentFilter hasElements() { any() }
}
/**
* Holds if a value stored with `storeContents` can be read back with `loadContents`.
*/
pragma[inline]
predicate compatibleContents(TypeTrackerContent storeContents, TypeTrackerContent loadContents) {
deprecated predicate compatibleContents(
TypeTrackerContent storeContents, TypeTrackerContent loadContents
) {
storeContents.getAStoreContent() = loadContents.getAReadContent()
}
/** Gets the "no content set" value to use for a type tracker not inside any content. */
OptionalTypeTrackerContent noContent() { result = DataFlowPrivate::TNoContentSet() }
deprecated OptionalTypeTrackerContent noContent() { result = DataFlowPrivate::TNoContentSet() }
/** Holds if there is a simple local flow step from `nodeFrom` to `nodeTo` */
predicate simpleLocalFlowStep = DataFlowPrivate::localFlowStepTypeTracker/2;
deprecated predicate simpleLocalFlowStep =
TypeTrackingImpl::TypeTrackingInput::simpleLocalSmallStep/2;
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
predicate jumpStep = DataFlowPrivate::jumpStep/2;
/** Holds if there is direct flow from `param` to a return. */
pragma[nomagic]
private predicate flowThrough(DataFlowPublic::ParameterNode param) {
exists(DataFlowPrivate::SourceReturnNode returnNode, DataFlowDispatch::ReturnKind rk |
param.flowsTo(returnNode) and
returnNode.hasKind(rk, param.(DataFlowPrivate::NodeImpl).getCfgScope())
|
rk instanceof DataFlowDispatch::NormalReturnKind
or
rk instanceof DataFlowDispatch::BreakReturnKind
)
}
/** Holds if there is flow from `arg` to `p` via the call `call`, not counting `new -> initialize` call steps. */
pragma[nomagic]
predicate callStepNoInitialize(
ExprNodes::CallCfgNode call, Node arg, DataFlowPrivate::ParameterNodeImpl p
) {
exists(DataFlowDispatch::ParameterPosition pos |
argumentPositionMatch(call, arg, pos) and
p.isSourceParameterOf(DataFlowDispatch::getTarget(call), pos)
)
}
deprecated predicate jumpStep = TypeTrackingImpl::TypeTrackingInput::jumpStep/2;
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which may depend on the call graph. */
pragma[nomagic]
predicate levelStepCall(Node nodeFrom, Node nodeTo) {
exists(DataFlowPublic::ParameterNode param |
flowThrough(param) and
callStepNoInitialize(nodeTo.asExpr(), nodeFrom, param)
)
}
deprecated predicate levelStepCall = TypeTrackingImpl::TypeTrackingInput::levelStepCall/2;
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph. */
pragma[nomagic]
predicate levelStepNoCall(Node nodeFrom, Node nodeTo) {
TypeTrackerSummaryFlow::levelStepNoCall(nodeFrom, nodeTo)
or
localFieldStep(nodeFrom, nodeTo)
}
/**
* Gets a method of `mod`, with `instance` indicating if this is an instance method.
*
* Does not take inheritance or the various forms of inclusion into account.
*/
pragma[nomagic]
private MethodBase getAMethod(ModuleBase mod, boolean instance) {
not mod instanceof SingletonClass and
result = mod.getAMethod() and
if result instanceof SingletonMethod then instance = false else instance = true
or
exists(SingletonClass cls |
cls.getValue().(SelfVariableAccess).getVariable().getDeclaringScope() = mod and
result = cls.getAMethod().(Method) and
instance = false
)
}
/**
* Gets a value flowing into `field` in `mod`, with `instance` indicating if it's
* a field on an instance of `mod` (as opposed to the module object itself).
*/
pragma[nomagic]
private Node fieldPredecessor(ModuleBase mod, boolean instance, string field) {
exists(InstanceVariableWriteAccess access, AssignExpr assign |
access.getReceiver().getVariable().getDeclaringScope() = getAMethod(mod, instance) and
field = access.getVariable().getName() and
assign.getLeftOperand() = access and
result.asExpr().getExpr() = assign.getRightOperand()
)
}
/**
* Gets a reference to `field` in `mod`, with `instance` indicating if it's
* a field on an instance of `mod` (as opposed to the module object itself).
*/
pragma[nomagic]
private Node fieldSuccessor(ModuleBase mod, boolean instance, string field) {
exists(InstanceVariableReadAccess access |
access.getReceiver().getVariable().getDeclaringScope() = getAMethod(mod, instance) and
result.asExpr().getExpr() = access and
field = access.getVariable().getName()
)
}
/**
* Holds if `pred -> succ` should be used a level step, from a field assignment to
* a read within the same class.
*/
private predicate localFieldStep(Node pred, Node succ) {
exists(ModuleBase mod, boolean instance, string field |
pred = fieldPredecessor(mod, instance, field) and
succ = fieldSuccessor(mod, instance, field)
)
}
pragma[noinline]
private predicate argumentPositionMatch(
ExprNodes::CallCfgNode call, DataFlowPrivate::ArgumentNode arg,
DataFlowDispatch::ParameterPosition ppos
) {
exists(DataFlowDispatch::ArgumentPosition apos |
arg.sourceArgumentOf(call, apos) and
not apos.isLambdaSelf() and
DataFlowDispatch::parameterMatch(ppos, apos)
)
}
pragma[noinline]
private predicate viableParam(
ExprNodes::CallCfgNode call, DataFlowPrivate::ParameterNodeImpl p,
DataFlowDispatch::ParameterPosition ppos
) {
exists(Cfg::CfgScope callable |
DataFlowDispatch::getTarget(call) = callable or
DataFlowDispatch::getInitializeTarget(call) = callable
|
p.isSourceParameterOf(callable, ppos)
)
}
/** Holds if there is flow from `arg` to `p` via the call `call`. */
pragma[nomagic]
predicate callStep(ExprNodes::CallCfgNode call, Node arg, DataFlowPrivate::ParameterNodeImpl p) {
exists(DataFlowDispatch::ParameterPosition pos |
argumentPositionMatch(call, arg, pos) and
viableParam(call, p, pos)
)
}
deprecated predicate levelStepNoCall = TypeTrackingImpl::TypeTrackingInput::levelStepNoCall/2;
/**
* Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call.
@@ -213,7 +78,7 @@ predicate callStep(ExprNodes::CallCfgNode call, Node arg, DataFlowPrivate::Param
* recursion (or, at best, terrible performance), since identifying calls to library
* methods is done using API graphs (which uses type tracking).
*/
predicate callStep(Node nodeFrom, Node nodeTo) { callStep(_, nodeFrom, nodeTo) }
deprecated predicate callStep = TypeTrackingImpl::TypeTrackingInput::callStep/2;
/**
* Holds if `nodeFrom` steps to `nodeTo` by being returned from a call.
@@ -222,17 +87,7 @@ predicate callStep(Node nodeFrom, Node nodeTo) { callStep(_, nodeFrom, nodeTo) }
* recursion (or, at best, terrible performance), since identifying calls to library
* methods is done using API graphs (which uses type tracking).
*/
predicate returnStep(Node nodeFrom, Node nodeTo) {
exists(ExprNodes::CallCfgNode call |
nodeFrom instanceof DataFlowPrivate::ReturnNode and
not nodeFrom instanceof DataFlowPrivate::InitializeReturnNode and
nodeFrom.(DataFlowPrivate::NodeImpl).getCfgScope() = DataFlowDispatch::getTarget(call) and
// deliberately do not include `getInitializeTarget`, since calls to `new` should not
// get the return value from `initialize`. Any fields being set in the initializer
// will reach all reads via `callStep` and `localFieldStep`.
nodeTo.asExpr().getAstNode() = call.getAstNode()
)
}
deprecated predicate returnStep = TypeTrackingImpl::TypeTrackingInput::returnStep/2;
/**
* Holds if `nodeFrom` is being written to the `contents` of the object
@@ -265,211 +120,25 @@ predicate returnStep(Node nodeFrom, Node nodeTo) {
* to `z` inside `bar`, even though this content write happens _after_ `bar` is
* called.
*/
predicate basicStoreStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet contents) {
storeStepIntoSourceNode(nodeFrom, nodeTo, contents)
or
TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, contents)
}
/**
* Holds if a store step `nodeFrom -> nodeTo` with `contents` exists, where the destination node
* is a post-update node that should be treated as a local source node.
*/
private predicate storeStepIntoSourceNode(Node nodeFrom, Node nodeTo, DataFlow::ContentSet contents) {
// TODO: support SetterMethodCall inside TuplePattern
exists(ExprNodes::MethodCallCfgNode call |
contents
.isSingleton(DataFlowPublic::Content::getAttributeName(call.getExpr()
.(Ast::SetterMethodCall)
.getTargetName())) and
nodeTo.(DataFlowPublic::PostUpdateNode).getPreUpdateNode().asExpr() = call.getReceiver() and
call.getExpr() instanceof Ast::SetterMethodCall and
call.getArgument(call.getNumberOfArguments() - 1) =
nodeFrom.(DataFlowPublic::ExprNode).getExprNode()
)
or
DataFlowPrivate::storeStepCommon(nodeFrom, contents, nodeTo)
}
deprecated predicate basicStoreStep = TypeTrackingImpl::TypeTrackingInput::storeStep/3;
/**
* Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`.
*/
predicate basicLoadStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet contents) {
readStepIntoSourceNode(nodeFrom, nodeTo, contents)
or
exists(ExprNodes::MethodCallCfgNode call |
call.getExpr().getNumberOfArguments() = 0 and
contents.isSingleton(DataFlowPublic::Content::getAttributeName(call.getExpr().getMethodName())) and
nodeFrom.asExpr() = call.getReceiver() and
nodeTo.asExpr() = call
)
or
TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, contents)
}
/**
* Holds if a read step `nodeFrom -> nodeTo` with `contents` exists, where the destination node
* should be treated as a local source node.
*/
private predicate readStepIntoSourceNode(Node nodeFrom, Node nodeTo, DataFlow::ContentSet contents) {
DataFlowPrivate::readStepCommon(nodeFrom, contents, nodeTo)
}
deprecated predicate basicLoadStep = TypeTrackingImpl::TypeTrackingInput::loadStep/3;
/**
* Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
*/
predicate basicLoadStoreStep(
Node nodeFrom, Node nodeTo, DataFlow::ContentSet loadContent, DataFlow::ContentSet storeContent
) {
readStoreStepIntoSourceNode(nodeFrom, nodeTo, loadContent, storeContent)
or
TypeTrackerSummaryFlow::basicLoadStoreStep(nodeFrom, nodeTo, loadContent, storeContent)
}
/**
* Holds if a read+store step `nodeFrom -> nodeTo` exists, where the destination node
* should be treated as a local source node.
*/
private predicate readStoreStepIntoSourceNode(
Node nodeFrom, Node nodeTo, DataFlow::ContentSet loadContent, DataFlow::ContentSet storeContent
) {
exists(DataFlowPrivate::SynthSplatParameterShiftNode shift |
shift.readFrom(nodeFrom, loadContent) and
shift.storeInto(nodeTo, storeContent)
)
or
exists(DataFlowPrivate::SynthSplatArgumentShiftNode shift |
shift.readFrom(nodeFrom, loadContent) and
shift.storeInto(nodeTo, storeContent)
)
}
deprecated predicate basicLoadStoreStep = TypeTrackingImpl::TypeTrackingInput::loadStoreStep/4;
/**
* Holds if type-tracking should step from `nodeFrom` to `nodeTo` but block flow of contents matched by `filter` through here.
*/
predicate basicWithoutContentStep(Node nodeFrom, Node nodeTo, ContentFilter filter) {
TypeTrackerSummaryFlow::basicWithoutContentStep(nodeFrom, nodeTo, filter)
}
deprecated predicate basicWithoutContentStep =
TypeTrackingImpl::TypeTrackingInput::withoutContentStep/3;
/**
* Holds if type-tracking should step from `nodeFrom` to `nodeTo` if inside a content matched by `filter`.
*/
predicate basicWithContentStep(Node nodeFrom, Node nodeTo, ContentFilter filter) {
TypeTrackerSummaryFlow::basicWithContentStep(nodeFrom, nodeTo, filter)
}
/**
* A utility class that is equivalent to `boolean` but does not require type joining.
*/
class Boolean extends boolean {
Boolean() { this = true or this = false }
}
private import SummaryComponentStack
/**
* Holds if the given component can't be evaluated by `evaluateSummaryComponentStackLocal`.
*/
pragma[nomagic]
predicate isNonLocal(SummaryComponent component) {
component = SC::content(_)
or
component = SC::withContent(_)
}
private import internal.SummaryTypeTracker as SummaryTypeTracker
private import codeql.ruby.dataflow.FlowSummary as FlowSummary
private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input {
// Dataflow nodes
class Node = DataFlow::Node;
// Content
class TypeTrackerContent = DataFlowPublic::ContentSet;
class TypeTrackerContentFilter = ContentFilter;
TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content) {
(
content.isAnyElement()
or
content.isElementLowerBoundOrUnknown(_)
or
content.isElementOfTypeOrUnknown(_)
or
content.isSingleton(any(DataFlow::Content::UnknownElementContent c))
) and
result = MkElementFilter()
}
TypeTrackerContentFilter getFilterFromWithContentStep(TypeTrackerContent content) {
(
content.isAnyElement()
or
content.isElementLowerBound(_)
or
content.isElementLowerBoundOrUnknown(_)
or
content.isElementOfType(_)
or
content.isElementOfTypeOrUnknown(_)
or
content.isSingleton(any(DataFlow::Content::ElementContent c))
) and
result = MkElementFilter()
}
// Summaries and their stacks
class SummaryComponent = FlowSummary::SummaryComponent;
class SummaryComponentStack = FlowSummary::SummaryComponentStack;
predicate singleton = FlowSummary::SummaryComponentStack::singleton/1;
predicate push = FlowSummary::SummaryComponentStack::push/2;
// Relating content to summaries
predicate content = FlowSummary::SummaryComponent::content/1;
predicate withoutContent = FlowSummary::SummaryComponent::withoutContent/1;
predicate withContent = FlowSummary::SummaryComponent::withContent/1;
predicate return = FlowSummary::SummaryComponent::return/0;
// Callables
class SummarizedCallable = FlowSummary::SummarizedCallable;
// Relating nodes to summaries
Node argumentOf(Node call, SummaryComponent arg, boolean isPostUpdate) {
exists(DataFlowDispatch::ParameterPosition pos, DataFlowPrivate::ArgumentNode n |
arg = SummaryComponent::argument(pos) and
argumentPositionMatch(call.asExpr(), n, pos)
|
isPostUpdate = false and result = n
or
isPostUpdate = true and result.(DataFlowPublic::PostUpdateNode).getPreUpdateNode() = n
)
}
Node parameterOf(Node callable, SummaryComponent param) {
exists(DataFlowDispatch::ArgumentPosition apos, DataFlowDispatch::ParameterPosition ppos |
param = SummaryComponent::parameter(apos) and
DataFlowDispatch::parameterMatch(ppos, apos) and
result
.(DataFlowPrivate::ParameterNodeImpl)
.isSourceParameterOf(callable.asExpr().getExpr(), ppos)
)
}
Node returnOf(Node callable, SummaryComponent return) {
return = SummaryComponent::return() and
result.(DataFlowPrivate::ReturnNode).(DataFlowPrivate::NodeImpl).getCfgScope() =
callable.asExpr().getExpr()
}
// Relating callables to nodes
Node callTo(SummarizedCallable callable) { result.asExpr().getExpr() = callable.getACallSimple() }
}
private module TypeTrackerSummaryFlow = SummaryTypeTracker::SummaryFlow<SummaryTypeTrackerInput>;
deprecated predicate basicWithContentStep = TypeTrackingImpl::TypeTrackingInput::withContentStep/3;

View File

@@ -0,0 +1,7 @@
/**
* Provides classes and predicates for simple data-flow reachability suitable
* for tracking types.
*/
private import codeql.ruby.typetracking.internal.TypeTrackingImpl as Impl
import Impl::Shared::TypeTracking<Impl::TypeTrackingInput>

View File

@@ -0,0 +1,430 @@
import codeql.typetracking.TypeTracking as Shared
import codeql.typetracking.internal.TypeTrackingImpl as SharedImpl
private import codeql.ruby.AST
private import codeql.ruby.CFG as Cfg
private import Cfg::CfgNodes
private import SummaryTypeTracker as SummaryTypeTracker
private import codeql.ruby.DataFlow
private import codeql.ruby.dataflow.FlowSummary as FlowSummary
private import codeql.ruby.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
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.FlowSummaryImpl as FlowSummaryImpl
private import codeql.ruby.dataflow.internal.FlowSummaryImplSpecific as FlowSummaryImplSpecific
private import codeql.ruby.dataflow.internal.AccessPathSyntax
/** Holds if there is direct flow from `param` to a return. */
pragma[nomagic]
private predicate flowThrough(DataFlowPublic::ParameterNode param) {
exists(DataFlowPrivate::SourceReturnNode returnNode, DataFlowDispatch::ReturnKind rk |
param.flowsTo(returnNode) and
returnNode.hasKind(rk, param.(DataFlowPrivate::NodeImpl).getCfgScope())
|
rk instanceof DataFlowDispatch::NormalReturnKind
or
rk instanceof DataFlowDispatch::BreakReturnKind
)
}
/** Holds if there is flow from `arg` to `p` via the call `call`, not counting `new -> initialize` call steps. */
pragma[nomagic]
private predicate callStepNoInitialize(
ExprNodes::CallCfgNode call, DataFlow::Node arg, DataFlowPrivate::ParameterNodeImpl p
) {
exists(DataFlowDispatch::ParameterPosition pos |
argumentPositionMatch(call, arg, pos) and
p.isSourceParameterOf(DataFlowDispatch::getTarget(call), pos)
)
}
/**
* Gets a method of `mod`, with `instance` indicating if this is an instance method.
*
* Does not take inheritance or the various forms of inclusion into account.
*/
pragma[nomagic]
private MethodBase getAMethod(ModuleBase mod, boolean instance) {
not mod instanceof SingletonClass and
result = mod.getAMethod() and
if result instanceof SingletonMethod then instance = false else instance = true
or
exists(SingletonClass cls |
cls.getValue().(SelfVariableAccess).getVariable().getDeclaringScope() = mod and
result = cls.getAMethod().(Method) and
instance = false
)
}
/**
* Gets a value flowing into `field` in `mod`, with `instance` indicating if it's
* a field on an instance of `mod` (as opposed to the module object itself).
*/
pragma[nomagic]
private DataFlow::Node fieldPredecessor(ModuleBase mod, boolean instance, string field) {
exists(InstanceVariableWriteAccess access, AssignExpr assign |
access.getReceiver().getVariable().getDeclaringScope() = getAMethod(mod, instance) and
field = access.getVariable().getName() and
assign.getLeftOperand() = access and
result.asExpr().getExpr() = assign.getRightOperand()
)
}
/**
* Gets a reference to `field` in `mod`, with `instance` indicating if it's
* a field on an instance of `mod` (as opposed to the module object itself).
*/
pragma[nomagic]
private DataFlow::Node fieldSuccessor(ModuleBase mod, boolean instance, string field) {
exists(InstanceVariableReadAccess access |
access.getReceiver().getVariable().getDeclaringScope() = getAMethod(mod, instance) and
result.asExpr().getExpr() = access and
field = access.getVariable().getName()
)
}
/**
* Holds if `pred -> succ` should be used a level step, from a field assignment to
* a read within the same class.
*/
private predicate localFieldStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(ModuleBase mod, boolean instance, string field |
pred = fieldPredecessor(mod, instance, field) and
succ = fieldSuccessor(mod, instance, field)
)
}
pragma[noinline]
private predicate argumentPositionMatch(
ExprNodes::CallCfgNode call, DataFlowPrivate::ArgumentNode arg,
DataFlowDispatch::ParameterPosition ppos
) {
exists(DataFlowDispatch::ArgumentPosition apos |
arg.sourceArgumentOf(call, apos) and
not apos.isLambdaSelf() and
DataFlowDispatch::parameterMatch(ppos, apos)
)
}
pragma[noinline]
private predicate viableParam(
ExprNodes::CallCfgNode call, DataFlowPrivate::ParameterNodeImpl p,
DataFlowDispatch::ParameterPosition ppos
) {
exists(Cfg::CfgScope callable |
DataFlowDispatch::getTarget(call) = callable or
DataFlowDispatch::getInitializeTarget(call) = callable
|
p.isSourceParameterOf(callable, ppos)
)
}
/** Holds if there is flow from `arg` to `p` via the call `call`. */
pragma[nomagic]
predicate callStep(
ExprNodes::CallCfgNode call, DataFlow::Node arg, DataFlowPrivate::ParameterNodeImpl p
) {
exists(DataFlowDispatch::ParameterPosition pos |
argumentPositionMatch(call, arg, pos) and
viableParam(call, p, pos)
)
}
private module SummaryTypeTrackerInput implements SummaryTypeTracker::Input {
// Dataflow nodes
class Node = DataFlow::Node;
// Content
class TypeTrackerContent = DataFlowPublic::ContentSet;
class TypeTrackerContentFilter = TypeTrackingInput::ContentFilter;
TypeTrackerContentFilter getFilterFromWithoutContentStep(TypeTrackerContent content) {
(
content.isAnyElement()
or
content.isElementLowerBoundOrUnknown(_)
or
content.isElementOfTypeOrUnknown(_)
or
content.isSingleton(any(DataFlow::Content::UnknownElementContent c))
) and
result = MkElementFilter()
}
TypeTrackerContentFilter getFilterFromWithContentStep(TypeTrackerContent content) {
(
content.isAnyElement()
or
content.isElementLowerBound(_)
or
content.isElementLowerBoundOrUnknown(_)
or
content.isElementOfType(_)
or
content.isElementOfTypeOrUnknown(_)
or
content.isSingleton(any(DataFlow::Content::ElementContent c))
) and
result = MkElementFilter()
}
// Summaries and their stacks
class SummaryComponent = FlowSummary::SummaryComponent;
class SummaryComponentStack = FlowSummary::SummaryComponentStack;
predicate singleton = FlowSummary::SummaryComponentStack::singleton/1;
predicate push = FlowSummary::SummaryComponentStack::push/2;
// Relating content to summaries
predicate content = FlowSummary::SummaryComponent::content/1;
predicate withoutContent = FlowSummary::SummaryComponent::withoutContent/1;
predicate withContent = FlowSummary::SummaryComponent::withContent/1;
predicate return = FlowSummary::SummaryComponent::return/0;
// Callables
class SummarizedCallable = FlowSummary::SummarizedCallable;
// Relating nodes to summaries
Node argumentOf(Node call, SummaryComponent arg, boolean isPostUpdate) {
exists(DataFlowDispatch::ParameterPosition pos, DataFlowPrivate::ArgumentNode n |
arg = FlowSummary::SummaryComponent::argument(pos) and
argumentPositionMatch(call.asExpr(), n, pos)
|
isPostUpdate = false and result = n
or
isPostUpdate = true and result.(DataFlowPublic::PostUpdateNode).getPreUpdateNode() = n
)
}
Node parameterOf(Node callable, SummaryComponent param) {
exists(DataFlowDispatch::ArgumentPosition apos, DataFlowDispatch::ParameterPosition ppos |
param = FlowSummary::SummaryComponent::parameter(apos) and
DataFlowDispatch::parameterMatch(ppos, apos) and
result
.(DataFlowPrivate::ParameterNodeImpl)
.isSourceParameterOf(callable.asExpr().getExpr(), ppos)
)
}
Node returnOf(Node callable, SummaryComponent return) {
return = FlowSummary::SummaryComponent::return() and
result.(DataFlowPrivate::ReturnNode).(DataFlowPrivate::NodeImpl).getCfgScope() =
callable.asExpr().getExpr()
}
// Relating callables to nodes
Node callTo(SummarizedCallable callable) { result.asExpr().getExpr() = callable.getACallSimple() }
}
private module TypeTrackerSummaryFlow = SummaryTypeTracker::SummaryFlow<SummaryTypeTrackerInput>;
private newtype TContentFilter = MkElementFilter()
module TypeTrackingInput implements Shared::TypeTrackingInput {
class Node = DataFlowPublic::Node;
class LocalSourceNode = DataFlowPublic::LocalSourceNode;
class Content = DataFlowPublic::ContentSet;
/**
* A label to use for `WithContent` and `WithoutContent` steps, restricting
* which `ContentSet` may pass through.
*/
class ContentFilter extends TContentFilter {
/** Gets a string representation of this content filter. */
string toString() { this = MkElementFilter() and result = "elements" }
/** Gets the content of a type-tracker that matches this filter. */
Content getAMatchingContent() {
this = MkElementFilter() and
result.getAReadContent() instanceof DataFlow::Content::ElementContent
}
}
/**
* Holds if a value stored with `storeContents` can be read back with `loadContents`.
*/
pragma[inline]
predicate compatibleContents(Content storeContents, Content loadContents) {
storeContents.getAStoreContent() = loadContents.getAReadContent()
}
/** Holds if there is a simple local flow step from `nodeFrom` to `nodeTo` */
predicate simpleLocalSmallStep = DataFlowPrivate::localFlowStepTypeTracker/2;
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph. */
pragma[nomagic]
predicate levelStepNoCall(Node nodeFrom, LocalSourceNode nodeTo) {
TypeTrackerSummaryFlow::levelStepNoCall(nodeFrom, nodeTo)
or
localFieldStep(nodeFrom, nodeTo)
}
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which may depend on the call graph. */
pragma[nomagic]
predicate levelStepCall(Node nodeFrom, LocalSourceNode nodeTo) {
exists(DataFlowPublic::ParameterNode param |
flowThrough(param) and
callStepNoInitialize(nodeTo.asExpr(), nodeFrom, param)
)
}
/**
* Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call.
*
* Flow into summarized library methods is not included, as that will lead to negative
* recursion (or, at best, terrible performance), since identifying calls to library
* methods is done using API graphs (which uses type tracking).
*/
predicate callStep(Node nodeFrom, LocalSourceNode nodeTo) { callStep(_, nodeFrom, nodeTo) }
/**
* Holds if `nodeFrom` steps to `nodeTo` by being returned from a call.
*
* Flow out of summarized library methods is not included, as that will lead to negative
* recursion (or, at best, terrible performance), since identifying calls to library
* methods is done using API graphs (which uses type tracking).
*/
predicate returnStep(Node nodeFrom, LocalSourceNode nodeTo) {
exists(ExprNodes::CallCfgNode call |
nodeFrom instanceof DataFlowPrivate::ReturnNode and
not nodeFrom instanceof DataFlowPrivate::InitializeReturnNode and
nodeFrom.(DataFlowPrivate::NodeImpl).getCfgScope() = DataFlowDispatch::getTarget(call) and
// deliberately do not include `getInitializeTarget`, since calls to `new` should not
// get the return value from `initialize`. Any fields being set in the initializer
// will reach all reads via `callStep` and `localFieldStep`.
nodeTo.asExpr().getAstNode() = call.getAstNode()
)
}
/**
* Holds if `nodeFrom` is being written to the `contents` of the object
* in `nodeTo`.
*
* Note that the choice of `nodeTo` does not have to make sense
* "chronologically". All we care about is whether the `contents` of
* `nodeTo` can have a specific type, and the assumption is that if a specific
* type appears here, then any access of that particular content can yield
* something of that particular type.
*
* Thus, in an example such as
*
* ```rb
* def foo(y)
* x = Foo.new
* bar(x)
* x.content = y
* baz(x)
* end
*
* def bar(x)
* z = x.content
* end
* ```
* for the content write `x.content = y`, we will have `contents` being the
* literal string `"content"`, `nodeFrom` will be `y`, and `nodeTo` will be the
* `Foo` object created on the first line of the function. This means we will
* track the fact that `x.content` can have the type of `y` into the assignment
* to `z` inside `bar`, even though this content write happens _after_ `bar` is
* called.
*/
predicate storeStep(Node nodeFrom, Node nodeTo, Content contents) {
// TODO: support SetterMethodCall inside TuplePattern
exists(ExprNodes::MethodCallCfgNode call |
contents
.isSingleton(DataFlowPublic::Content::getAttributeName(call.getExpr()
.(SetterMethodCall)
.getTargetName())) and
nodeTo.(DataFlowPublic::PostUpdateNode).getPreUpdateNode().asExpr() = call.getReceiver() and
call.getExpr() instanceof SetterMethodCall and
call.getArgument(call.getNumberOfArguments() - 1) =
nodeFrom.(DataFlowPublic::ExprNode).getExprNode()
)
or
DataFlowPrivate::storeStepCommon(nodeFrom, contents, nodeTo)
or
TypeTrackerSummaryFlow::basicStoreStep(nodeFrom, nodeTo, contents)
}
/**
* Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`.
*/
predicate loadStep(Node nodeFrom, LocalSourceNode nodeTo, Content contents) {
DataFlowPrivate::readStepCommon(nodeFrom, contents, nodeTo)
or
exists(ExprNodes::MethodCallCfgNode call |
call.getExpr().getNumberOfArguments() = 0 and
contents
.isSingleton(DataFlowPublic::Content::getAttributeName(call.getExpr().getMethodName())) and
nodeFrom.asExpr() = call.getReceiver() and
nodeTo.asExpr() = call
)
or
TypeTrackerSummaryFlow::basicLoadStep(nodeFrom, nodeTo, contents)
}
/**
* Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
*/
predicate loadStoreStep(Node nodeFrom, Node nodeTo, Content loadContent, Content storeContent) {
exists(DataFlowPrivate::SynthSplatParameterShiftNode shift |
shift.readFrom(nodeFrom, loadContent) and
shift.storeInto(nodeTo, storeContent)
)
or
exists(DataFlowPrivate::SynthSplatArgumentShiftNode shift |
shift.readFrom(nodeFrom, loadContent) and
shift.storeInto(nodeTo, storeContent)
)
or
TypeTrackerSummaryFlow::basicLoadStoreStep(nodeFrom, nodeTo, loadContent, storeContent)
}
/**
* Same as `withContentStep`, but `nodeTo` has type `Node` instead of `LocalSourceNode`,
* which allows for it by used in the definition of `LocalSourceNode`.
*/
additional predicate withContentStepImpl(Node nodeFrom, Node nodeTo, ContentFilter filter) {
TypeTrackerSummaryFlow::basicWithContentStep(nodeFrom, nodeTo, filter)
}
/**
* Holds if type-tracking should step from `nodeFrom` to `nodeTo` if inside a content matched by `filter`.
*/
predicate withContentStep(Node nodeFrom, LocalSourceNode nodeTo, ContentFilter filter) {
withContentStepImpl(nodeFrom, nodeTo, filter)
}
/**
* Same as `withoutContentStep`, but `nodeTo` has type `Node` instead of `LocalSourceNode`,
* which allows for it by used in the definition of `LocalSourceNode`.
*/
additional predicate withoutContentStepImpl(Node nodeFrom, Node nodeTo, ContentFilter filter) {
TypeTrackerSummaryFlow::basicWithoutContentStep(nodeFrom, nodeTo, filter)
}
/**
* Holds if type-tracking should step from `nodeFrom` to `nodeTo` but block flow of contents matched by `filter` through here.
*/
predicate withoutContentStep(Node nodeFrom, LocalSourceNode nodeTo, ContentFilter filter) {
withoutContentStepImpl(nodeFrom, nodeTo, filter)
}
/**
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
*/
predicate jumpStep(Node nodeFrom, LocalSourceNode nodeTo) {
DataFlowPrivate::jumpStep(nodeFrom, nodeTo)
}
predicate hasFeatureBacktrackStoreTarget() { none() }
}
import SharedImpl::TypeTracking<TypeTrackingInput>

View File

@@ -1,7 +1,7 @@
import ruby
import TestUtilities.InlineExpectationsTest
import TestUtilities.InlineFlowTestUtil
private import codeql.ruby.typetracking.TypeTracker
private import codeql.ruby.typetracking.TypeTracking
private DataFlow::LocalSourceNode track(TypeTracker t, DataFlow::CallNode source) {
t.start() and

View File

@@ -32,7 +32,6 @@ testFailures
| array_flow.rb:940:18:940:78 | # $ hasValueFlow=91.1 $ hasValueFlow=91.2 $ hasValueFlow=91.3 | Missing result:hasValueFlow=91.3 |
| array_flow.rb:957:28:957:46 | # $ hasValueFlow=93 | Missing result:hasValueFlow=93 |
| array_flow.rb:958:28:958:46 | # $ hasValueFlow=93 | Missing result:hasValueFlow=93 |
| array_flow.rb:1018:16:1018:36 | # $ hasValueFlow=99.2 | Missing result:hasValueFlow=99.2 |
| array_flow.rb:1099:10:1099:13 | ...[...] | Unexpected result: hasValueFlow=105.2 |
| array_flow.rb:1100:10:1100:13 | ...[...] | Unexpected result: hasValueFlow=105.3 |
| array_flow.rb:1110:10:1110:13 | ...[...] | Unexpected result: hasValueFlow=105.2 |

View File

@@ -9,30 +9,16 @@ testFailures
| hash_flow.rb:219:27:219:47 | # $ hasValueFlow=14.2 | Missing result:hasValueFlow=14.2 |
| hash_flow.rb:291:10:291:14 | ...[...] | Unexpected result: hasValueFlow=19.1 |
| hash_flow.rb:294:10:294:14 | ...[...] | Unexpected result: hasValueFlow=19.3 |
| hash_flow.rb:453:22:453:42 | # $ hasValueFlow=27.3 | Missing result:hasValueFlow=27.3 |
| hash_flow.rb:455:22:455:42 | # $ hasValueFlow=27.4 | Missing result:hasValueFlow=27.4 |
| hash_flow.rb:467:16:467:36 | # $ hasValueFlow=28.1 | Missing result:hasValueFlow=28.1 |
| hash_flow.rb:513:22:513:42 | # $ hasValueFlow=31.1 | Missing result:hasValueFlow=31.1 |
| hash_flow.rb:515:10:515:20 | ( ... ) | Unexpected result: hasValueFlow=31.3 |
| hash_flow.rb:515:22:515:42 | # $ hasValueFlow=31.2 | Missing result:hasValueFlow=31.2 |
| hash_flow.rb:559:17:559:57 | # $ hasValueFlow=34.1 $ hasValueFlow=34.2 | Missing result:hasValueFlow=34.1 |
| hash_flow.rb:559:17:559:57 | # $ hasValueFlow=34.1 $ hasValueFlow=34.2 | Missing result:hasValueFlow=34.2 |
| hash_flow.rb:571:18:571:38 | # $ hasValueFlow=35.1 | Missing result:hasValueFlow=35.1 |
| hash_flow.rb:591:20:591:60 | # $ hasValueFlow=36.1 $ hasValueFlow=36.2 | Missing result:hasValueFlow=36.1 |
| hash_flow.rb:591:20:591:60 | # $ hasValueFlow=36.1 $ hasValueFlow=36.2 | Missing result:hasValueFlow=36.2 |
| hash_flow.rb:673:10:673:19 | ( ... ) | Unexpected result: hasValueFlow=41.1 |
| hash_flow.rb:704:22:704:42 | # $ hasValueFlow=42.3 | Missing result:hasValueFlow=42.3 |
| hash_flow.rb:706:22:706:42 | # $ hasValueFlow=42.4 | Missing result:hasValueFlow=42.4 |
| hash_flow.rb:776:10:776:14 | ...[...] | Unexpected result: hasValueFlow=46.1 |
| hash_flow.rb:779:10:779:14 | ...[...] | Unexpected result: hasValueFlow=46.3 |
| hash_flow.rb:781:10:781:17 | ...[...] | Unexpected result: hasValueFlow=46.1 |
| hash_flow.rb:784:10:784:17 | ...[...] | Unexpected result: hasValueFlow=46.3 |
| hash_flow.rb:841:22:841:42 | # $ hasValueFlow=48.3 | Missing result:hasValueFlow=48.3 |
| hash_flow.rb:843:22:843:42 | # $ hasValueFlow=48.4 | Missing result:hasValueFlow=48.4 |
| hash_flow.rb:903:22:903:42 | # $ hasValueFlow=50.3 | Missing result:hasValueFlow=50.3 |
| hash_flow.rb:905:22:905:42 | # $ hasValueFlow=50.4 | Missing result:hasValueFlow=50.4 |
| hash_flow.rb:933:22:933:42 | # $ hasValueFlow=51.3 | Missing result:hasValueFlow=51.3 |
| hash_flow.rb:935:22:935:42 | # $ hasValueFlow=51.4 | Missing result:hasValueFlow=51.4 |
| hash_flow.rb:963:22:963:42 | # $ hasValueFlow=52.3 | Missing result:hasValueFlow=52.3 |
| hash_flow.rb:965:22:965:42 | # $ hasValueFlow=52.4 | Missing result:hasValueFlow=52.4 |
failures

View File

@@ -2580,52 +2580,52 @@ track
| params_flow.rb:120:1:126:3 | destruct | type tracker without call steps | params_flow.rb:120:1:126:3 | destruct |
| params_flow.rb:120:1:126:3 | self in destruct | type tracker with call steps | params_flow.rb:5:1:7:3 | self in sink |
| params_flow.rb:120:1:126:3 | self in destruct | type tracker without call steps | params_flow.rb:120:1:126:3 | self in destruct |
| params_flow.rb:120:15:120:15 | a | type tracker with call steps | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:15:120:15 | a | type tracker with call steps with content splat position 0 | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:120:15:120:15 | a | type tracker with call steps with content splat position 0 | params_flow.rb:6:5:6:10 | synthetic splat argument |
| params_flow.rb:120:15:120:15 | a | type tracker without call steps | params_flow.rb:120:15:120:15 | a |
| params_flow.rb:120:15:120:15 | a | type tracker without call steps | params_flow.rb:120:15:120:15 | a |
| params_flow.rb:120:15:120:15 | a | type tracker without call steps with content splat position 0 | params_flow.rb:121:5:121:10 | synthetic splat argument |
| params_flow.rb:120:17:120:17 | b | type tracker with call steps | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:17:120:17 | b | type tracker with call steps with content splat position 0 | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:120:17:120:17 | b | type tracker with call steps with content splat position 0 | params_flow.rb:6:5:6:10 | synthetic splat argument |
| params_flow.rb:120:17:120:17 | b | type tracker without call steps | params_flow.rb:120:17:120:17 | b |
| params_flow.rb:120:17:120:17 | b | type tracker without call steps | params_flow.rb:120:17:120:17 | b |
| params_flow.rb:120:17:120:17 | b | type tracker without call steps with content splat position 0 | params_flow.rb:122:5:122:10 | synthetic splat argument |
| params_flow.rb:120:22:120:22 | c | type tracker with call steps | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:22:120:22 | c | type tracker with call steps with content splat position 0 | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:120:22:120:22 | c | type tracker with call steps with content splat position 0 | params_flow.rb:6:5:6:10 | synthetic splat argument |
| params_flow.rb:120:22:120:22 | c | type tracker without call steps | params_flow.rb:120:22:120:22 | c |
| params_flow.rb:120:22:120:22 | c | type tracker without call steps | params_flow.rb:120:22:120:22 | c |
| params_flow.rb:120:22:120:22 | c | type tracker without call steps with content splat position 0 | params_flow.rb:123:5:123:10 | synthetic splat argument |
| params_flow.rb:120:25:120:25 | d | type tracker with call steps | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:25:120:25 | d | type tracker with call steps with content splat position 0 | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:120:25:120:25 | d | type tracker with call steps with content splat position 0 | params_flow.rb:6:5:6:10 | synthetic splat argument |
| params_flow.rb:120:25:120:25 | d | type tracker without call steps | params_flow.rb:120:25:120:25 | d |
| params_flow.rb:120:25:120:25 | d | type tracker without call steps | params_flow.rb:120:25:120:25 | d |
| params_flow.rb:120:25:120:25 | d | type tracker without call steps with content splat position 0 | params_flow.rb:124:5:124:10 | synthetic splat argument |
| params_flow.rb:120:27:120:27 | e | type tracker with call steps | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:27:120:27 | e | type tracker with call steps with content splat position 0 | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:120:27:120:27 | e | type tracker with call steps with content splat position 0 | params_flow.rb:6:5:6:10 | synthetic splat argument |
| params_flow.rb:120:27:120:27 | e | type tracker without call steps | params_flow.rb:120:27:120:27 | e |
| params_flow.rb:120:27:120:27 | e | type tracker without call steps | params_flow.rb:120:27:120:27 | e |
| params_flow.rb:120:27:120:27 | e | type tracker without call steps with content splat position 0 | params_flow.rb:125:5:125:10 | synthetic splat argument |
| params_flow.rb:121:5:121:10 | call to sink | type tracker without call steps | params_flow.rb:121:5:121:10 | call to sink |
| params_flow.rb:121:5:121:10 | synthetic splat argument | type tracker with call steps | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:121:5:121:10 | synthetic splat argument | type tracker without call steps | params_flow.rb:121:5:121:10 | synthetic splat argument |
| params_flow.rb:121:10:121:10 | a | type tracker with call steps | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:121:10:121:10 | a | type tracker with call steps with content splat position 0 | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:121:10:121:10 | a | type tracker with call steps with content splat position 0 | params_flow.rb:6:5:6:10 | synthetic splat argument |
| params_flow.rb:121:10:121:10 | a | type tracker without call steps | params_flow.rb:121:10:121:10 | a |
| params_flow.rb:121:10:121:10 | a | type tracker without call steps with content splat position 0 | params_flow.rb:121:5:121:10 | synthetic splat argument |
| params_flow.rb:122:5:122:10 | call to sink | type tracker without call steps | params_flow.rb:122:5:122:10 | call to sink |
| params_flow.rb:122:5:122:10 | synthetic splat argument | type tracker with call steps | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:122:5:122:10 | synthetic splat argument | type tracker without call steps | params_flow.rb:122:5:122:10 | synthetic splat argument |
| params_flow.rb:122:10:122:10 | b | type tracker with call steps | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:122:10:122:10 | b | type tracker with call steps with content splat position 0 | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:122:10:122:10 | b | type tracker with call steps with content splat position 0 | params_flow.rb:6:5:6:10 | synthetic splat argument |
| params_flow.rb:122:10:122:10 | b | type tracker without call steps | params_flow.rb:122:10:122:10 | b |
| params_flow.rb:122:10:122:10 | b | type tracker without call steps with content splat position 0 | params_flow.rb:122:5:122:10 | synthetic splat argument |
| params_flow.rb:123:5:123:10 | call to sink | type tracker without call steps | params_flow.rb:123:5:123:10 | call to sink |
| params_flow.rb:123:5:123:10 | synthetic splat argument | type tracker with call steps | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:123:5:123:10 | synthetic splat argument | type tracker without call steps | params_flow.rb:123:5:123:10 | synthetic splat argument |
| params_flow.rb:123:10:123:10 | c | type tracker with call steps | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:123:10:123:10 | c | type tracker with call steps with content splat position 0 | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:123:10:123:10 | c | type tracker with call steps with content splat position 0 | params_flow.rb:6:5:6:10 | synthetic splat argument |
| params_flow.rb:123:10:123:10 | c | type tracker without call steps | params_flow.rb:123:10:123:10 | c |
| params_flow.rb:123:10:123:10 | c | type tracker without call steps with content splat position 0 | params_flow.rb:123:5:123:10 | synthetic splat argument |
| params_flow.rb:124:5:124:10 | call to sink | type tracker without call steps | params_flow.rb:124:5:124:10 | call to sink |
| params_flow.rb:124:5:124:10 | synthetic splat argument | type tracker with call steps | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:124:5:124:10 | synthetic splat argument | type tracker without call steps | params_flow.rb:124:5:124:10 | synthetic splat argument |
| params_flow.rb:124:10:124:10 | d | type tracker with call steps | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:124:10:124:10 | d | type tracker with call steps with content splat position 0 | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:124:10:124:10 | d | type tracker with call steps with content splat position 0 | params_flow.rb:6:5:6:10 | synthetic splat argument |
| params_flow.rb:124:10:124:10 | d | type tracker without call steps | params_flow.rb:124:10:124:10 | d |
| params_flow.rb:124:10:124:10 | d | type tracker without call steps with content splat position 0 | params_flow.rb:124:5:124:10 | synthetic splat argument |
| params_flow.rb:125:5:125:10 | call to sink | type tracker without call steps | params_flow.rb:125:5:125:10 | call to sink |
| params_flow.rb:125:5:125:10 | call to sink | type tracker without call steps | params_flow.rb:128:1:128:61 | call to destruct |
| params_flow.rb:125:5:125:10 | synthetic splat argument | type tracker with call steps | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:125:5:125:10 | synthetic splat argument | type tracker without call steps | params_flow.rb:125:5:125:10 | synthetic splat argument |
| params_flow.rb:125:10:125:10 | e | type tracker with call steps | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:125:10:125:10 | e | type tracker with call steps with content splat position 0 | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:125:10:125:10 | e | type tracker with call steps with content splat position 0 | params_flow.rb:6:5:6:10 | synthetic splat argument |
| params_flow.rb:125:10:125:10 | e | type tracker without call steps | params_flow.rb:125:10:125:10 | e |
| params_flow.rb:125:10:125:10 | e | type tracker without call steps with content splat position 0 | params_flow.rb:125:5:125:10 | synthetic splat argument |
| params_flow.rb:128:1:128:61 | call to destruct | type tracker without call steps | params_flow.rb:128:1:128:61 | call to destruct |
| params_flow.rb:128:1:128:61 | synthetic splat argument | type tracker without call steps | params_flow.rb:128:1:128:61 | synthetic splat argument |
| params_flow.rb:128:10:128:31 | Array | type tracker without call steps | params_flow.rb:128:10:128:31 | Array |
@@ -5297,47 +5297,52 @@ trackEnd
| params_flow.rb:120:1:126:3 | self in destruct | params_flow.rb:123:5:123:10 | self |
| params_flow.rb:120:1:126:3 | self in destruct | params_flow.rb:124:5:124:10 | self |
| params_flow.rb:120:1:126:3 | self in destruct | params_flow.rb:125:5:125:10 | self |
| params_flow.rb:120:15:120:15 | a | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:15:120:15 | a | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:15:120:15 | a | params_flow.rb:6:10:6:10 | x |
| params_flow.rb:120:15:120:15 | a | params_flow.rb:120:15:120:15 | a |
| params_flow.rb:120:15:120:15 | a | params_flow.rb:120:15:120:15 | a |
| params_flow.rb:120:15:120:15 | a | params_flow.rb:121:10:121:10 | a |
| params_flow.rb:120:17:120:17 | b | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:17:120:17 | b | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:17:120:17 | b | params_flow.rb:6:10:6:10 | x |
| params_flow.rb:120:17:120:17 | b | params_flow.rb:120:17:120:17 | b |
| params_flow.rb:120:17:120:17 | b | params_flow.rb:120:17:120:17 | b |
| params_flow.rb:120:17:120:17 | b | params_flow.rb:122:10:122:10 | b |
| params_flow.rb:120:22:120:22 | c | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:22:120:22 | c | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:22:120:22 | c | params_flow.rb:6:10:6:10 | x |
| params_flow.rb:120:22:120:22 | c | params_flow.rb:120:22:120:22 | c |
| params_flow.rb:120:22:120:22 | c | params_flow.rb:120:22:120:22 | c |
| params_flow.rb:120:22:120:22 | c | params_flow.rb:123:10:123:10 | c |
| params_flow.rb:120:25:120:25 | d | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:25:120:25 | d | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:25:120:25 | d | params_flow.rb:6:10:6:10 | x |
| params_flow.rb:120:25:120:25 | d | params_flow.rb:120:25:120:25 | d |
| params_flow.rb:120:25:120:25 | d | params_flow.rb:120:25:120:25 | d |
| params_flow.rb:120:25:120:25 | d | params_flow.rb:124:10:124:10 | d |
| params_flow.rb:120:27:120:27 | e | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:27:120:27 | e | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:120:27:120:27 | e | params_flow.rb:6:10:6:10 | x |
| params_flow.rb:120:27:120:27 | e | params_flow.rb:120:27:120:27 | e |
| params_flow.rb:120:27:120:27 | e | params_flow.rb:120:27:120:27 | e |
| params_flow.rb:120:27:120:27 | e | params_flow.rb:125:10:125:10 | e |
| params_flow.rb:121:5:121:10 | call to sink | params_flow.rb:121:5:121:10 | call to sink |
| params_flow.rb:121:5:121:10 | synthetic splat argument | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:121:5:121:10 | synthetic splat argument | params_flow.rb:121:5:121:10 | synthetic splat argument |
| params_flow.rb:121:10:121:10 | a | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:121:10:121:10 | a | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:121:10:121:10 | a | params_flow.rb:6:10:6:10 | x |
| params_flow.rb:121:10:121:10 | a | params_flow.rb:121:10:121:10 | a |
| params_flow.rb:122:5:122:10 | call to sink | params_flow.rb:122:5:122:10 | call to sink |
| params_flow.rb:122:5:122:10 | synthetic splat argument | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:122:5:122:10 | synthetic splat argument | params_flow.rb:122:5:122:10 | synthetic splat argument |
| params_flow.rb:122:10:122:10 | b | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:122:10:122:10 | b | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:122:10:122:10 | b | params_flow.rb:6:10:6:10 | x |
| params_flow.rb:122:10:122:10 | b | params_flow.rb:122:10:122:10 | b |
| params_flow.rb:123:5:123:10 | call to sink | params_flow.rb:123:5:123:10 | call to sink |
| params_flow.rb:123:5:123:10 | synthetic splat argument | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:123:5:123:10 | synthetic splat argument | params_flow.rb:123:5:123:10 | synthetic splat argument |
| params_flow.rb:123:10:123:10 | c | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:123:10:123:10 | c | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:123:10:123:10 | c | params_flow.rb:6:10:6:10 | x |
| params_flow.rb:123:10:123:10 | c | params_flow.rb:123:10:123:10 | c |
| params_flow.rb:124:5:124:10 | call to sink | params_flow.rb:124:5:124:10 | call to sink |
| params_flow.rb:124:5:124:10 | synthetic splat argument | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:124:5:124:10 | synthetic splat argument | params_flow.rb:124:5:124:10 | synthetic splat argument |
| params_flow.rb:124:10:124:10 | d | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:124:10:124:10 | d | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:124:10:124:10 | d | params_flow.rb:6:10:6:10 | x |
| params_flow.rb:124:10:124:10 | d | params_flow.rb:124:10:124:10 | d |
| params_flow.rb:125:5:125:10 | call to sink | params_flow.rb:125:5:125:10 | call to sink |
| params_flow.rb:125:5:125:10 | call to sink | params_flow.rb:128:1:128:61 | call to destruct |
| params_flow.rb:125:5:125:10 | synthetic splat argument | params_flow.rb:5:1:7:3 | synthetic splat parameter |
| params_flow.rb:125:5:125:10 | synthetic splat argument | params_flow.rb:125:5:125:10 | synthetic splat argument |
| params_flow.rb:125:10:125:10 | e | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:125:10:125:10 | e | params_flow.rb:5:10:5:10 | x |
| params_flow.rb:125:10:125:10 | e | params_flow.rb:6:10:6:10 | x |
| params_flow.rb:125:10:125:10 | e | params_flow.rb:125:10:125:10 | e |
| params_flow.rb:128:1:128:61 | call to destruct | params_flow.rb:128:1:128:61 | call to destruct |
| params_flow.rb:128:1:128:61 | synthetic splat argument | params_flow.rb:128:1:128:61 | synthetic splat argument |
| params_flow.rb:128:10:128:31 | Array | params_flow.rb:128:10:128:31 | Array |

View File

@@ -1,6 +1,6 @@
import codeql.ruby.AST
import codeql.ruby.DataFlow
import codeql.ruby.typetracking.TypeTracker
import codeql.ruby.typetracking.TypeTracking
class LocalSourceNode extends DataFlow::LocalSourceNode {
LocalSourceNode() { this.getLocation().getFile().getExtension() = "rb" }