mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Ruby: Adopt shared type tracking library
This commit is contained in:
@@ -462,10 +462,6 @@
|
|||||||
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll",
|
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll",
|
||||||
"swift/ql/lib/codeql/swift/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": [
|
"SummaryTypeTracker": [
|
||||||
"python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll",
|
"python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll",
|
||||||
"ruby/ql/lib/codeql/ruby/typetracking/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/InlineTaintTest.ext.yml",
|
||||||
"python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml"
|
"python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
8
ruby/ql/consistency-queries/TypeTrackingConsistency.ql
Normal file
8
ruby/ql/consistency-queries/TypeTrackingConsistency.ql
Normal 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>
|
||||||
@@ -8,8 +8,7 @@
|
|||||||
private import codeql.ruby.AST
|
private import codeql.ruby.AST
|
||||||
private import codeql.ruby.DataFlow
|
private import codeql.ruby.DataFlow
|
||||||
private import codeql.ruby.typetracking.ApiGraphShared
|
private import codeql.ruby.typetracking.ApiGraphShared
|
||||||
private import codeql.ruby.typetracking.TypeTracker
|
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
|
||||||
private import codeql.ruby.typetracking.TypeTrackerSpecific as TypeTrackerSpecific
|
|
||||||
private import codeql.ruby.controlflow.CfgNodes
|
private import codeql.ruby.controlflow.CfgNodes
|
||||||
private import codeql.ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
private import codeql.ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
||||||
private import codeql.ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch
|
private import codeql.ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch
|
||||||
@@ -1050,9 +1049,9 @@ module API {
|
|||||||
|
|
||||||
/** INTERNAL USE ONLY. */
|
/** INTERNAL USE ONLY. */
|
||||||
module Internal {
|
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`. */
|
/** Gets the API node corresponding to the module/class object for `mod`. */
|
||||||
bindingset[mod]
|
bindingset[mod]
|
||||||
@@ -1093,7 +1092,7 @@ module API {
|
|||||||
private predicate needsSinkNode(DataFlow::Node node) {
|
private predicate needsSinkNode(DataFlow::Node node) {
|
||||||
node instanceof DataFlowPrivate::ArgumentNode
|
node instanceof DataFlowPrivate::ArgumentNode
|
||||||
or
|
or
|
||||||
TypeTrackerSpecific::basicStoreStep(node, _, _)
|
TypeTrackingInput::storeStep(node, _, _)
|
||||||
or
|
or
|
||||||
node = any(DataFlow::CallableNode callable).getAReturnNode()
|
node = any(DataFlow::CallableNode callable).getAReturnNode()
|
||||||
or
|
or
|
||||||
@@ -1203,10 +1202,8 @@ module API {
|
|||||||
|
|
||||||
cached
|
cached
|
||||||
predicate contentEdge(Node pred, DataFlow::Content content, Node succ) {
|
predicate contentEdge(Node pred, DataFlow::Content content, Node succ) {
|
||||||
exists(
|
exists(DataFlow::Node object, DataFlow::Node value, DataFlow::ContentSet c |
|
||||||
DataFlow::Node object, DataFlow::Node value, TypeTrackerSpecific::TypeTrackerContent c
|
TypeTrackingInput::loadStep(object, value, c) and
|
||||||
|
|
|
||||||
TypeTrackerSpecific::basicLoadStep(object, value, c) and
|
|
||||||
content = c.getAStoreContent() and
|
content = c.getAStoreContent() and
|
||||||
not c.isSingleton(any(DataFlow::Content::AttributeNameContent k)) and
|
not c.isSingleton(any(DataFlow::Content::AttributeNameContent k)) and
|
||||||
// `x -> x.foo` with content "foo"
|
// `x -> x.foo` with content "foo"
|
||||||
@@ -1214,7 +1211,7 @@ module API {
|
|||||||
succ = getForwardStartNode(value)
|
succ = getForwardStartNode(value)
|
||||||
or
|
or
|
||||||
// Based on `object.c = value` generate `object -> value` with content `c`
|
// 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
|
content = c.getAStoreContent() and
|
||||||
pred = getForwardOrBackwardEndNode(getALocalSourceStrict(object)) and
|
pred = getForwardOrBackwardEndNode(getALocalSourceStrict(object)) and
|
||||||
succ = MkSinkNode(value)
|
succ = MkSinkNode(value)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import codeql.ruby.AST
|
import codeql.ruby.AST
|
||||||
private import codeql.ruby.CFG
|
private import codeql.ruby.CFG
|
||||||
private import codeql.ruby.typetracking.TypeTracker
|
private import codeql.ruby.typetracking.TypeTracking
|
||||||
import codeql.ruby.DataFlow
|
import codeql.ruby.DataFlow
|
||||||
private import internal.FlowSummaryImpl as Impl
|
private import internal.FlowSummaryImpl as Impl
|
||||||
private import internal.DataFlowDispatch
|
private import internal.DataFlowDispatch
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
private import codeql.ruby.AST
|
private import codeql.ruby.AST
|
||||||
private import codeql.ruby.CFG
|
private import codeql.ruby.CFG
|
||||||
private import DataFlowPrivate
|
private import DataFlowPrivate
|
||||||
private import codeql.ruby.typetracking.TypeTracker
|
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
|
||||||
private import codeql.ruby.typetracking.TypeTrackerSpecific as TypeTrackerSpecific
|
|
||||||
private import codeql.ruby.ast.internal.Module
|
private import codeql.ruby.ast.internal.Module
|
||||||
private import FlowSummaryImpl as FlowSummaryImpl
|
private import FlowSummaryImpl as FlowSummaryImpl
|
||||||
private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
|
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) {
|
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
|
// We exclude steps into `self` parameters. For those, we instead rely on the type of
|
||||||
// the enclosing module
|
// the enclosing module
|
||||||
StepSummary::smallstepNoCall(nodeFrom, nodeTo, summary) and
|
smallStepNoCall(nodeFrom, nodeTo, summary) and
|
||||||
isNotSelf(nodeTo)
|
isNotSelf(nodeTo)
|
||||||
or
|
or
|
||||||
// We exclude steps into type checked variables. For those, we instead rely on the
|
// 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) {
|
predicate stepCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
|
||||||
StepSummary::smallstepCall(nodeFrom, nodeTo, summary)
|
smallStepCall(nodeFrom, nodeTo, summary)
|
||||||
}
|
}
|
||||||
|
|
||||||
class StateProj = Unit;
|
class StateProj = Unit;
|
||||||
@@ -941,7 +940,7 @@ private module TrackSingletonMethodOnInstanceInput implements CallGraphConstruct
|
|||||||
RelevantCall call, DataFlow::Node arg, DataFlow::ParameterNode p,
|
RelevantCall call, DataFlow::Node arg, DataFlow::ParameterNode p,
|
||||||
CfgNodes::ExprCfgNode nodeFromPreExpr
|
CfgNodes::ExprCfgNode nodeFromPreExpr
|
||||||
|
|
|
|
||||||
TypeTrackerSpecific::callStep(call, arg, p) and
|
callStep(call, arg, p) and
|
||||||
nodeTo.getPreUpdateNode() = arg and
|
nodeTo.getPreUpdateNode() = arg and
|
||||||
summary.toString() = "return" and
|
summary.toString() = "return" and
|
||||||
(
|
(
|
||||||
@@ -965,13 +964,13 @@ private module TrackSingletonMethodOnInstanceInput implements CallGraphConstruct
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicate stepNoCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
|
predicate stepNoCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
|
||||||
StepSummary::smallstepNoCall(nodeFrom, nodeTo, summary)
|
smallStepNoCall(nodeFrom, nodeTo, summary)
|
||||||
or
|
or
|
||||||
localFlowStep(nodeFrom, nodeTo, summary)
|
localFlowStep(nodeFrom, nodeTo, summary)
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate stepCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
|
predicate stepCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
|
||||||
StepSummary::smallstepCall(nodeFrom, nodeTo, summary)
|
smallStepCall(nodeFrom, nodeTo, summary)
|
||||||
or
|
or
|
||||||
paramReturnFlow(nodeFrom, nodeTo, summary)
|
paramReturnFlow(nodeFrom, nodeTo, summary)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ module LocalFlow {
|
|||||||
SsaImpl::lastRefBeforeRedefExt(def, bb, i, next.getDefinitionExt()) and
|
SsaImpl::lastRefBeforeRedefExt(def, bb, i, next.getDefinitionExt()) and
|
||||||
exprFrom = bb.getNode(i) and
|
exprFrom = bb.getNode(i) and
|
||||||
exprFrom.getExpr() instanceof VariableReadAccess 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())
|
firstReadExt(def, nodeTo.asExpr())
|
||||||
or
|
or
|
||||||
// Flow from post-update read to next read
|
// Flow from post-update read to next read
|
||||||
localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
|
localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNodeImpl).getPreUpdateNode(), nodeTo)
|
||||||
or
|
or
|
||||||
// Flow into phi (read) SSA definition node from def
|
// Flow into phi (read) SSA definition node from def
|
||||||
localFlowSsaInputFromDef(nodeFrom, def, nodeTo)
|
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. */
|
/** A collection of cached types and predicates to be evaluated in the same stage. */
|
||||||
cached
|
cached
|
||||||
private module Cached {
|
private module Cached {
|
||||||
private import codeql.ruby.typetracking.TypeTrackerSpecific as TypeTrackerSpecific
|
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TNode =
|
newtype TNode =
|
||||||
@@ -575,14 +575,10 @@ private module Cached {
|
|||||||
VariableCapture::flowInsensitiveStep(nodeFrom, nodeTo)
|
VariableCapture::flowInsensitiveStep(nodeFrom, nodeTo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Holds if `n` wraps an SSA definition without ingoing flow. */
|
||||||
private predicate entrySsaDefinition(SsaDefinitionExtNode n) {
|
private predicate entrySsaDefinition(SsaDefinitionExtNode n) {
|
||||||
n = LocalFlow::getParameterDefNode(_)
|
n.getDefinitionExt() =
|
||||||
or
|
any(SsaImpl::WriteDefinition def | not def.(Ssa::WriteDefinition).assigns(_))
|
||||||
exists(SsaImpl::DefinitionExt def | def = n.getDefinitionExt() |
|
|
||||||
def instanceof Ssa::SelfDefinition
|
|
||||||
or
|
|
||||||
def instanceof Ssa::CapturedEntryDefinition
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
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
|
cached
|
||||||
predicate isLocalSourceNode(Node n) {
|
predicate isLocalSourceNode(Node n) {
|
||||||
n instanceof TSourceParameterNode
|
n instanceof TSourceParameterNode
|
||||||
@@ -614,11 +620,9 @@ private module Cached {
|
|||||||
entrySsaDefinition(n) and
|
entrySsaDefinition(n) and
|
||||||
not LocalFlow::localFlowSsaParamInput(_, n)
|
not LocalFlow::localFlowSsaParamInput(_, n)
|
||||||
or
|
or
|
||||||
TypeTrackerSpecific::basicStoreStep(_, n, _)
|
isStoreTargetNode(n)
|
||||||
or
|
or
|
||||||
TypeTrackerSpecific::basicLoadStep(_, n, _)
|
TypeTrackingInput::loadStep(_, n, _)
|
||||||
or
|
|
||||||
TypeTrackerSpecific::basicLoadStoreStep(_, n, _, _)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
@@ -633,7 +637,7 @@ private module Cached {
|
|||||||
TElementContentOfTypeContent(string type, Boolean includeUnknown) {
|
TElementContentOfTypeContent(string type, Boolean includeUnknown) {
|
||||||
type = any(Content::KnownElementContent content).getIndex().getValueType()
|
type = any(Content::KnownElementContent content).getIndex().getValueType()
|
||||||
} or
|
} or
|
||||||
TNoContentSet() // Only used by type-tracking
|
deprecated TNoContentSet() // Only used by type-tracking
|
||||||
|
|
||||||
cached
|
cached
|
||||||
class TContentSet =
|
class TContentSet =
|
||||||
|
|||||||
@@ -2,10 +2,9 @@ private import codeql.ruby.AST
|
|||||||
private import DataFlowDispatch
|
private import DataFlowDispatch
|
||||||
private import DataFlowPrivate
|
private import DataFlowPrivate
|
||||||
private import codeql.ruby.CFG
|
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 codeql.ruby.dataflow.SSA
|
||||||
private import FlowSummaryImpl as FlowSummaryImpl
|
private import FlowSummaryImpl as FlowSummaryImpl
|
||||||
private import SsaImpl as SsaImpl
|
|
||||||
private import codeql.ruby.ApiGraphs
|
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. */
|
/** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */
|
||||||
pragma[inline]
|
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.
|
* 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.
|
* See `TypeBackTracker` for more details about how to use this.
|
||||||
*/
|
*/
|
||||||
pragma[inline]
|
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
|
* Gets a node to which data may flow from this node in zero or
|
||||||
* more local data-flow steps.
|
* more local data-flow steps.
|
||||||
*/
|
*/
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
Node getALocalUse() { hasLocalSource(result, this) }
|
Node getALocalUse() { flowsTo(this, result) }
|
||||||
|
|
||||||
/** Gets a method call where this node flows to the receiver. */
|
/** Gets a method call where this node flows to the receiver. */
|
||||||
CallNode getAMethodCall() { Cached::hasMethodCall(this, result, _) }
|
CallNode getAMethodCall() { Cached::hasMethodCall(this, result, _) }
|
||||||
@@ -354,21 +353,21 @@ class PostUpdateNode extends Node instanceof PostUpdateNodeImpl {
|
|||||||
Node getPreUpdateNode() { result = super.getPreUpdateNode() }
|
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
|
cached
|
||||||
private module 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
|
cached
|
||||||
predicate hasMethodCall(LocalSourceNode source, CallNode call, string name) {
|
predicate hasMethodCall(LocalSourceNode source, CallNode call, string name) {
|
||||||
source.flowsTo(call.getReceiver()) and
|
source.flowsTo(call.getReceiver()) and
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
private import codeql.ruby.Concepts
|
private import codeql.ruby.Concepts
|
||||||
private import codeql.ruby.AST
|
private import codeql.ruby.AST
|
||||||
private import codeql.ruby.DataFlow
|
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.ApiGraphs
|
||||||
private import codeql.ruby.controlflow.CfgNodes as CfgNodes
|
private import codeql.ruby.controlflow.CfgNodes as CfgNodes
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ private import codeql.ruby.AST
|
|||||||
private import codeql.ruby.ApiGraphs
|
private import codeql.ruby.ApiGraphs
|
||||||
private import codeql.ruby.Concepts
|
private import codeql.ruby.Concepts
|
||||||
private import codeql.ruby.DataFlow
|
private import codeql.ruby.DataFlow
|
||||||
private import codeql.ruby.typetracking.TypeTracker
|
private import codeql.ruby.typetracking.TypeTracking
|
||||||
private import Response::Private as RP
|
private import Response::Private as RP
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ private import codeql.ruby.ApiGraphs
|
|||||||
private import codeql.ruby.Concepts
|
private import codeql.ruby.Concepts
|
||||||
private import codeql.ruby.controlflow.CfgNodes::ExprNodes
|
private import codeql.ruby.controlflow.CfgNodes::ExprNodes
|
||||||
private import codeql.ruby.DataFlow
|
private import codeql.ruby.DataFlow
|
||||||
private import codeql.ruby.typetracking.TypeTracker
|
private import codeql.ruby.typetracking.TypeTracking
|
||||||
private import App as A
|
private import App as A
|
||||||
|
|
||||||
/** Contains implementation details for modeling `Rack::Response`. */
|
/** Contains implementation details for modeling `Rack::Response`. */
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ private import codeql.ruby.AST as Ast
|
|||||||
private import codeql.ruby.CFG
|
private import codeql.ruby.CFG
|
||||||
private import codeql.ruby.DataFlow
|
private import codeql.ruby.DataFlow
|
||||||
private import codeql.ruby.controlflow.CfgNodes
|
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.ApiGraphs
|
||||||
private import codeql.ruby.Concepts
|
private import codeql.ruby.Concepts
|
||||||
private import codeql.ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
|
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,
|
* Provides a version of type tracking where we first prune for reachable nodes,
|
||||||
* before doing the type tracking computation.
|
* before doing the type tracking computation.
|
||||||
*/
|
*/
|
||||||
private module TypeTrack<TypeTrackInputSig Input> {
|
private module PrunedTypeTrack<TypeTrackInputSig Input> {
|
||||||
private predicate additionalStep(
|
private predicate additionalStep(
|
||||||
DataFlow::LocalSourceNode nodeFrom, DataFlow::LocalSourceNode nodeTo
|
DataFlow::LocalSourceNode nodeFrom, DataFlow::LocalSourceNode nodeTo
|
||||||
) {
|
) {
|
||||||
@@ -130,10 +130,10 @@ private module TypeTrack<TypeTrackInputSig Input> {
|
|||||||
TypeTracker t, DataFlow::LocalSourceNode nodeFrom, DataFlow::LocalSourceNode nodeTo
|
TypeTracker t, DataFlow::LocalSourceNode nodeFrom, DataFlow::LocalSourceNode nodeTo
|
||||||
) {
|
) {
|
||||||
exists(StepSummary summary |
|
exists(StepSummary summary |
|
||||||
StepSummary::step(nodeFrom, nodeTo, summary) and
|
step(nodeFrom, nodeTo, summary) and
|
||||||
reached(nodeFrom, t) and
|
reached(nodeFrom, t) and
|
||||||
reached(nodeTo, result) and
|
reached(nodeTo, result) and
|
||||||
result = t.append(summary)
|
result = append(t, summary)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
additionalStep(nodeFrom, nodeTo) and
|
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,
|
* 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.
|
* 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`. */
|
/** Holds if `strConst` flows to a regex compilation (tracked by `t`), where the resulting regular expression is stored in `reg`. */
|
||||||
pragma[nomagic]
|
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.
|
* 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.
|
* 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. */
|
/** Gets a node that references a regular expression. */
|
||||||
private DataFlow::LocalSourceNode trackRegexpType(TypeTracker t) {
|
private DataFlow::LocalSourceNode trackRegexpType(TypeTracker t) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
private import codeql.ruby.AST
|
private import codeql.ruby.AST
|
||||||
private import codeql.ruby.DataFlow
|
private import codeql.ruby.DataFlow
|
||||||
private import codeql.ruby.Concepts
|
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.Files
|
||||||
private import codeql.ruby.frameworks.core.IO
|
private import codeql.ruby.frameworks.core.IO
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ private import internal.CryptoAlgorithmNames
|
|||||||
private import codeql.ruby.Concepts
|
private import codeql.ruby.Concepts
|
||||||
private import codeql.ruby.DataFlow
|
private import codeql.ruby.DataFlow
|
||||||
private import codeql.ruby.ApiGraphs
|
private import codeql.ruby.ApiGraphs
|
||||||
private import codeql.ruby.typetracking.TypeTracker
|
private import codeql.ruby.typetracking.TypeTracking
|
||||||
|
|
||||||
bindingset[algorithmString]
|
bindingset[algorithmString]
|
||||||
private string algorithmRegex(string algorithmString) {
|
private string algorithmRegex(string algorithmString) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
private import codeql.ruby.AST
|
private import codeql.ruby.AST
|
||||||
private import codeql.ruby.Concepts
|
private import codeql.ruby.Concepts
|
||||||
private import codeql.ruby.DataFlow
|
private import codeql.ruby.DataFlow
|
||||||
|
private import codeql.ruby.dataflow.SSA
|
||||||
private import codeql.ruby.controlflow.CfgNodes
|
private import codeql.ruby.controlflow.CfgNodes
|
||||||
private import codeql.ruby.frameworks.core.Kernel
|
private import codeql.ruby.frameworks.core.Kernel
|
||||||
|
|
||||||
@@ -29,10 +30,10 @@ module StackTraceExposure {
|
|||||||
*/
|
*/
|
||||||
class BacktraceCall extends Source, DataFlow::CallNode {
|
class BacktraceCall extends Source, DataFlow::CallNode {
|
||||||
BacktraceCall() {
|
BacktraceCall() {
|
||||||
exists(DataFlow::LocalSourceNode varAccess |
|
exists(DataFlow::SsaDefinitionNode ssaDef |
|
||||||
varAccess.asExpr().(ExprNodes::VariableReadAccessCfgNode).getExpr().getVariable() =
|
ssaDef.getDefinition().(Ssa::WriteDefinition).getWriteAccess().getAstNode() =
|
||||||
any(RescueClause rc).getVariableExpr().(VariableAccess).getVariable() and
|
any(RescueClause rc).getVariableExpr() and
|
||||||
varAccess.flowsTo(this.getReceiver())
|
ssaDef.(DataFlow::LocalSourceNode).flowsTo(this.getReceiver())
|
||||||
) and
|
) and
|
||||||
this.getMethodName() = ["backtrace", "backtrace_locations"]
|
this.getMethodName() = ["backtrace", "backtrace_locations"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ private import ruby
|
|||||||
private import codeql.ruby.ApiGraphs
|
private import codeql.ruby.ApiGraphs
|
||||||
private import codeql.ruby.frameworks.core.Gem::Gem as Gem
|
private import codeql.ruby.frameworks.core.Gem::Gem as Gem
|
||||||
private import codeql.ruby.Concepts as Concepts
|
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.
|
* 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`. */
|
/** Gets a node that is eventually executed as code at `codeExec`. */
|
||||||
DataFlow::Node getANodeExecutedAsCode(Concepts::CodeExecution 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`. */
|
/** Gets a node that is eventually executed as code at `codeExec`, type-tracked with `t`. */
|
||||||
private DataFlow::LocalSourceNode getANodeExecutedAsCode(
|
private DataFlow::LocalSourceNode getANodeExecutedAsCode(
|
||||||
TypeTracker::TypeBackTracker t, Concepts::CodeExecution codeExec
|
TypeBackTracker t, Concepts::CodeExecution codeExec
|
||||||
) {
|
) {
|
||||||
t.start() and
|
t.start() and
|
||||||
result = codeExec.getCode().getALocalSource() 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
|
codeExec.runsArbitraryCode() // methods like `Object.send` is benign here, because of the string-construction the attacker cannot control the entire method name
|
||||||
or
|
or
|
||||||
exists(TypeTracker::TypeBackTracker t2 |
|
exists(TypeBackTracker t2 | result = getANodeExecutedAsCode(t2, codeExec).backtrack(t2, t))
|
||||||
result = getANodeExecutedAsCode(t2, codeExec).backtrack(t2, t)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
private import ruby
|
private import ruby
|
||||||
private import codeql.ruby.ApiGraphs
|
private import codeql.ruby.ApiGraphs
|
||||||
private import codeql.ruby.frameworks.core.Gem::Gem as Gem
|
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.
|
* 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`. */
|
/** Gets a node that eventually ends up in the XSS `sink`. */
|
||||||
private DataFlow::Node getANodeThatEndsInXssSink(ReflectedXss::Sink 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`. */
|
/** Gets a node that is eventually ends up in the XSS `sink`, type-tracked with `t`. */
|
||||||
private DataFlow::LocalSourceNode getANodeThatEndsInXssSink(
|
private DataFlow::LocalSourceNode getANodeThatEndsInXssSink(
|
||||||
TypeTracker::TypeBackTracker t, ReflectedXss::Sink sink
|
TypeBackTracker t, ReflectedXss::Sink sink
|
||||||
) {
|
) {
|
||||||
t.start() and
|
t.start() and
|
||||||
result = sink.getALocalSource()
|
result = sink.getALocalSource()
|
||||||
or
|
or
|
||||||
exists(TypeTracker::TypeBackTracker t2 |
|
exists(TypeBackTracker t2 | result = getANodeThatEndsInXssSink(t2, sink).backtrack(t2, t))
|
||||||
result = getANodeThatEndsInXssSink(t2, sink).backtrack(t2, t)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ private import codeql.ruby.DataFlow
|
|||||||
private import codeql.ruby.ApiGraphs
|
private import codeql.ruby.ApiGraphs
|
||||||
private import codeql.ruby.frameworks.core.Gem::Gem as Gem
|
private import codeql.ruby.frameworks.core.Gem::Gem as Gem
|
||||||
private import codeql.ruby.Concepts as Concepts
|
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.
|
* 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` */
|
/** Holds if the string constructed at `source` is executed at `shellExec` */
|
||||||
predicate isUsedAsShellCommand(DataFlow::Node source, Concepts::SystemCommandExecution 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(
|
private DataFlow::LocalSourceNode backtrackShellExec(
|
||||||
TypeTracker::TypeBackTracker t, Concepts::SystemCommandExecution shellExec
|
TypeBackTracker t, Concepts::SystemCommandExecution shellExec
|
||||||
) {
|
) {
|
||||||
t.start() and
|
t.start() and
|
||||||
result = any(DataFlow::Node n | shellExec.isShellInterpreted(n)).getALocalSource()
|
result = any(DataFlow::Node n | shellExec.isShellInterpreted(n)).getALocalSource()
|
||||||
or
|
or
|
||||||
exists(TypeTracker::TypeBackTracker t2 |
|
exists(TypeBackTracker t2 | result = backtrackShellExec(t2, shellExec).backtrack(t2, t))
|
||||||
result = backtrackShellExec(t2, shellExec).backtrack(t2, t)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
private import codeql.Locations
|
private import codeql.Locations
|
||||||
private import codeql.ruby.typetracking.TypeTracker
|
private import codeql.ruby.DataFlow
|
||||||
private import TypeTrackerSpecific
|
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The signature to use when instantiating `ApiGraphShared`.
|
* 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.
|
* 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.
|
* Gets the backward node with the given type-tracking state.
|
||||||
*
|
*
|
||||||
* This node will have outgoing epsilon edges to its type-tracking predecessors.
|
* 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`.
|
* 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.
|
* 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.
|
* 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`. */
|
/** Gets a local source of `node`. */
|
||||||
bindingset[node]
|
bindingset[node]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
TypeTrackingNode getALocalSourceStrict(Node node) { result = node.getALocalSource() }
|
DataFlow::LocalSourceNode getALocalSourceStrict(DataFlow::Node node) {
|
||||||
|
result = node.getALocalSource()
|
||||||
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
private module Cached {
|
private module Cached {
|
||||||
@@ -85,23 +87,21 @@ module ApiGraphShared<ApiGraphSharedSig S> {
|
|||||||
cached
|
cached
|
||||||
predicate epsilonEdge(ApiNode pred, ApiNode succ) {
|
predicate epsilonEdge(ApiNode pred, ApiNode succ) {
|
||||||
exists(
|
exists(
|
||||||
StepSummary summary, TypeTrackingNode predNode, TypeTracker predState,
|
StepSummary summary, DataFlow::LocalSourceNode predNode, TypeTracker predState,
|
||||||
TypeTrackingNode succNode, TypeTracker succState
|
DataFlow::LocalSourceNode succNode, TypeTracker succState
|
||||||
|
|
|
|
||||||
StepSummary::stepCall(predNode, succNode, summary)
|
step(predNode, succNode, summary)
|
||||||
or
|
|
||||||
StepSummary::stepNoCall(predNode, succNode, summary)
|
|
||||||
|
|
|
|
||||||
pred = getForwardNode(predNode, predState) and
|
pred = getForwardNode(predNode, predState) and
|
||||||
succState = StepSummary::append(predState, summary) and
|
succState = append(predState, summary) and
|
||||||
succ = getForwardNode(succNode, succState)
|
succ = getForwardNode(succNode, succState)
|
||||||
or
|
or
|
||||||
succ = getBackwardNode(predNode, predState) and // swap order for backward flow
|
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
|
pred = getBackwardNode(succNode, succState) // swap order for backward flow
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
exists(Node sink, TypeTrackingNode localSource |
|
exists(DataFlow::Node sink, DataFlow::LocalSourceNode localSource |
|
||||||
pred = getSinkNode(sink) and
|
pred = getSinkNode(sink) and
|
||||||
localSource = getALocalSourceStrict(sink) and
|
localSource = getALocalSourceStrict(sink) and
|
||||||
succ = getBackwardStartNode(localSource)
|
succ = getBackwardStartNode(localSource)
|
||||||
@@ -121,39 +121,39 @@ module ApiGraphShared<ApiGraphSharedSig S> {
|
|||||||
|
|
||||||
/** Gets the API node to use when starting forward flow from `source` */
|
/** Gets the API node to use when starting forward flow from `source` */
|
||||||
cached
|
cached
|
||||||
ApiNode forwardStartNode(TypeTrackingNode source) {
|
ApiNode forwardStartNode(DataFlow::LocalSourceNode source) {
|
||||||
result = getForwardNode(source, TypeTracker::end(false))
|
result = getForwardNode(source, noContentTypeTracker(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the API node to use when starting backward flow from `sink` */
|
/** Gets the API node to use when starting backward flow from `sink` */
|
||||||
cached
|
cached
|
||||||
ApiNode backwardStartNode(TypeTrackingNode sink) {
|
ApiNode backwardStartNode(DataFlow::LocalSourceNode sink) {
|
||||||
// There is backward flow A->B iff there is forward flow B->A.
|
// 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.
|
// 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. */
|
/** Gets `node` as a data flow source. */
|
||||||
cached
|
cached
|
||||||
TypeTrackingNode asSourceCached(ApiNode node) { node = forwardEndNode(result) }
|
DataFlow::LocalSourceNode asSourceCached(ApiNode node) { node = forwardEndNode(result) }
|
||||||
|
|
||||||
/** Gets `node` as a data flow sink. */
|
/** Gets `node` as a data flow sink. */
|
||||||
cached
|
cached
|
||||||
Node asSinkCached(ApiNode node) { node = getSinkNode(result) }
|
DataFlow::Node asSinkCached(ApiNode node) { node = getSinkNode(result) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private import Cached
|
private import Cached
|
||||||
|
|
||||||
/** Gets an API node corresponding to the end of forward-tracking to `localSource`. */
|
/** Gets an API node corresponding to the end of forward-tracking to `localSource`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private ApiNode forwardEndNode(TypeTrackingNode localSource) {
|
private ApiNode forwardEndNode(DataFlow::LocalSourceNode localSource) {
|
||||||
result = getForwardNode(localSource, TypeTracker::end(_))
|
result = getForwardNode(localSource, noContentTypeTracker(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets an API node corresponding to the end of backtracking to `localSource`. */
|
/** Gets an API node corresponding to the end of backtracking to `localSource`. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private ApiNode backwardEndNode(TypeTrackingNode localSource) {
|
private ApiNode backwardEndNode(DataFlow::LocalSourceNode localSource) {
|
||||||
result = getBackwardNode(localSource, TypeTracker::end(false))
|
result = getBackwardNode(localSource, noContentTypeTracker(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a node reachable from `node` by zero or more epsilon edges, including `node` itself. */
|
/** 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. */
|
/** Gets `node` as a data flow sink. */
|
||||||
bindingset[node]
|
bindingset[node]
|
||||||
pragma[inline_late]
|
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. */
|
/** Gets `node` as a data flow source. */
|
||||||
bindingset[node]
|
bindingset[node]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
TypeTrackingNode asSourceInline(ApiNode node) { result = asSourceCached(node) }
|
DataFlow::LocalSourceNode asSourceInline(ApiNode node) { result = asSourceCached(node) }
|
||||||
|
|
||||||
/** Gets a value reachable from `source`. */
|
/** Gets a value reachable from `source`. */
|
||||||
bindingset[source]
|
bindingset[source]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
Node getAValueReachableFromSourceInline(ApiNode source) {
|
DataFlow::Node getAValueReachableFromSourceInline(ApiNode source) {
|
||||||
exists(TypeTrackingNode src |
|
exists(DataFlow::LocalSourceNode src |
|
||||||
src = asSourceInline(getAnEpsilonSuccessorInline(source)) and
|
src = asSourceInline(getAnEpsilonSuccessorInline(source)) and
|
||||||
src.flowsTo(pragma[only_bind_into](result))
|
src.flowsTo(pragma[only_bind_into](result))
|
||||||
)
|
)
|
||||||
@@ -184,7 +184,7 @@ module ApiGraphShared<ApiGraphSharedSig S> {
|
|||||||
/** Gets a value that can reach `sink`. */
|
/** Gets a value that can reach `sink`. */
|
||||||
bindingset[sink]
|
bindingset[sink]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
Node getAValueReachingSinkInline(ApiNode sink) {
|
DataFlow::Node getAValueReachingSinkInline(ApiNode sink) {
|
||||||
backwardStartNode(result) = getAnEpsilonSuccessorInline(sink)
|
backwardStartNode(result) = getAnEpsilonSuccessorInline(sink)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ module ApiGraphShared<ApiGraphSharedSig S> {
|
|||||||
*/
|
*/
|
||||||
bindingset[node]
|
bindingset[node]
|
||||||
pragma[inline_late]
|
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`.
|
* Gets the starting point of backtracking from `node`.
|
||||||
@@ -204,7 +204,7 @@ module ApiGraphShared<ApiGraphSharedSig S> {
|
|||||||
*/
|
*/
|
||||||
bindingset[node]
|
bindingset[node]
|
||||||
pragma[inline_late]
|
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`.
|
* Gets a possible ending point of forward-tracking at `node`.
|
||||||
@@ -216,7 +216,7 @@ module ApiGraphShared<ApiGraphSharedSig S> {
|
|||||||
*/
|
*/
|
||||||
bindingset[node]
|
bindingset[node]
|
||||||
pragma[inline_late]
|
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`.
|
* Gets a possible ending point backtracking to `node`.
|
||||||
@@ -228,7 +228,7 @@ module ApiGraphShared<ApiGraphSharedSig S> {
|
|||||||
*/
|
*/
|
||||||
bindingset[node]
|
bindingset[node]
|
||||||
pragma[inline_late]
|
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`.
|
* Gets a possible eding point of forward or backward tracking at `node`.
|
||||||
@@ -237,19 +237,19 @@ module ApiGraphShared<ApiGraphSharedSig S> {
|
|||||||
*/
|
*/
|
||||||
bindingset[node]
|
bindingset[node]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
ApiNode getForwardOrBackwardEndNode(Node node) {
|
ApiNode getForwardOrBackwardEndNode(DataFlow::Node node) {
|
||||||
result = getForwardEndNode(node) or result = getBackwardEndNode(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()` */
|
/** Gets an API node for tracking forward starting at `node`. This is the implementation of `DataFlow::LocalSourceNode.track()` */
|
||||||
bindingset[node]
|
bindingset[node]
|
||||||
pragma[inline_late]
|
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()`. */
|
/** Gets an API node for backtracking starting at `node`. The implementation of `DataFlow::Node.backtrack()`. */
|
||||||
bindingset[node]
|
bindingset[node]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
ApiNode getNodeForBacktracking(Node node) {
|
ApiNode getNodeForBacktracking(DataFlow::Node node) {
|
||||||
result = getBackwardStartNode(getALocalSourceStrict(node))
|
result = getBackwardStartNode(getALocalSourceStrict(node))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,22 +8,22 @@ private module Cached {
|
|||||||
* A description of a step on an inter-procedural data flow path.
|
* A description of a step on an inter-procedural data flow path.
|
||||||
*/
|
*/
|
||||||
cached
|
cached
|
||||||
newtype TStepSummary =
|
deprecated newtype TStepSummary =
|
||||||
LevelStep() or
|
LevelStep() or
|
||||||
CallStep() or
|
CallStep() or
|
||||||
ReturnStep() or
|
ReturnStep() or
|
||||||
StoreStep(TypeTrackerContent content) { basicStoreStep(_, _, content) } or
|
deprecated StoreStep(TypeTrackerContent content) { basicStoreStep(_, _, content) } or
|
||||||
LoadStep(TypeTrackerContent content) { basicLoadStep(_, _, content) } or
|
deprecated LoadStep(TypeTrackerContent content) { basicLoadStep(_, _, content) } or
|
||||||
LoadStoreStep(TypeTrackerContent load, TypeTrackerContent store) {
|
deprecated LoadStoreStep(TypeTrackerContent load, TypeTrackerContent store) {
|
||||||
basicLoadStoreStep(_, _, load, store)
|
basicLoadStoreStep(_, _, load, store)
|
||||||
} or
|
} or
|
||||||
WithContent(ContentFilter filter) { basicWithContentStep(_, _, filter) } or
|
deprecated WithContent(ContentFilter filter) { basicWithContentStep(_, _, filter) } or
|
||||||
WithoutContent(ContentFilter filter) { basicWithoutContentStep(_, _, filter) } or
|
deprecated WithoutContent(ContentFilter filter) { basicWithoutContentStep(_, _, filter) } or
|
||||||
JumpStep()
|
JumpStep()
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TTypeTracker =
|
deprecated newtype TTypeTracker =
|
||||||
MkTypeTracker(Boolean hasCall, OptionalTypeTrackerContent content) {
|
deprecated MkTypeTracker(Boolean hasCall, OptionalTypeTrackerContent content) {
|
||||||
content = noContent()
|
content = noContent()
|
||||||
or
|
or
|
||||||
// Restrict `content` to those that might eventually match a load.
|
// Restrict `content` to those that might eventually match a load.
|
||||||
@@ -40,8 +40,8 @@ private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
newtype TTypeBackTracker =
|
deprecated newtype TTypeBackTracker =
|
||||||
MkTypeBackTracker(Boolean hasReturn, OptionalTypeTrackerContent content) {
|
deprecated MkTypeBackTracker(Boolean hasReturn, OptionalTypeTrackerContent content) {
|
||||||
content = noContent()
|
content = noContent()
|
||||||
or
|
or
|
||||||
// As in MkTypeTracker, restrict `content` to those that might eventually match a store.
|
// 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. */
|
/** Gets a type tracker with no content and the call bit set to the given value. */
|
||||||
cached
|
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`. */
|
/** Gets the summary resulting from appending `step` to type-tracking summary `tt`. */
|
||||||
cached
|
cached
|
||||||
TypeTracker append(TypeTracker tt, StepSummary step) {
|
deprecated TypeTracker append(TypeTracker tt, StepSummary step) {
|
||||||
exists(Boolean hasCall, OptionalTypeTrackerContent currentContents |
|
exists(Boolean hasCall, OptionalTypeTrackerContent currentContents |
|
||||||
tt = MkTypeTracker(hasCall, currentContents)
|
tt = MkTypeTracker(hasCall, currentContents)
|
||||||
|
|
|
|
||||||
@@ -108,13 +110,13 @@ private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private TypeBackTracker noContentTypeBackTracker(boolean hasReturn) {
|
deprecated private TypeBackTracker noContentTypeBackTracker(boolean hasReturn) {
|
||||||
result = MkTypeBackTracker(hasReturn, noContent())
|
result = MkTypeBackTracker(hasReturn, noContent())
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the summary resulting from prepending `step` to this type-tracking summary. */
|
/** Gets the summary resulting from prepending `step` to this type-tracking summary. */
|
||||||
cached
|
cached
|
||||||
TypeBackTracker prepend(TypeBackTracker tbt, StepSummary step) {
|
deprecated TypeBackTracker prepend(TypeBackTracker tbt, StepSummary step) {
|
||||||
exists(Boolean hasReturn, OptionalTypeTrackerContent content |
|
exists(Boolean hasReturn, OptionalTypeTrackerContent content |
|
||||||
tbt = MkTypeBackTracker(hasReturn, content)
|
tbt = MkTypeBackTracker(hasReturn, content)
|
||||||
|
|
|
|
||||||
@@ -167,7 +169,9 @@ private module Cached {
|
|||||||
* Steps contained in this predicate should _not_ depend on the call graph.
|
* Steps contained in this predicate should _not_ depend on the call graph.
|
||||||
*/
|
*/
|
||||||
cached
|
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))
|
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`.
|
* inter-procedural step from `nodeFrom` to `nodeTo`.
|
||||||
*/
|
*/
|
||||||
cached
|
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))
|
exists(Node mid | nodeFrom.flowsTo(mid) and smallstepCall(mid, nodeTo, summary))
|
||||||
}
|
}
|
||||||
|
|
||||||
cached
|
cached
|
||||||
predicate smallstepNoCall(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
|
deprecated predicate smallstepNoCall(Node nodeFrom, TypeTrackingNode nodeTo, StepSummary summary) {
|
||||||
jumpStep(nodeFrom, nodeTo) and
|
jumpStep(nodeFrom, nodeTo) and
|
||||||
summary = JumpStep()
|
summary = JumpStep()
|
||||||
or
|
or
|
||||||
@@ -210,7 +216,7 @@ private module Cached {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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()
|
callStep(nodeFrom, nodeTo) and summary = CallStep()
|
||||||
or
|
or
|
||||||
returnStep(nodeFrom, nodeTo) and
|
returnStep(nodeFrom, nodeTo) and
|
||||||
@@ -223,25 +229,27 @@ private module Cached {
|
|||||||
|
|
||||||
private import 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)
|
stepNoCall(nodeFrom, nodeTo, summary)
|
||||||
or
|
or
|
||||||
stepCall(nodeFrom, nodeTo, summary)
|
stepCall(nodeFrom, nodeTo, summary)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate stepProj(TypeTrackingNode nodeFrom, StepSummary summary) {
|
deprecated private predicate stepProj(TypeTrackingNode nodeFrom, StepSummary summary) {
|
||||||
step(nodeFrom, _, 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)
|
smallstepNoCall(nodeFrom, nodeTo, summary)
|
||||||
or
|
or
|
||||||
smallstepCall(nodeFrom, nodeTo, summary)
|
smallstepCall(nodeFrom, nodeTo, summary)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate smallstepProj(Node nodeFrom, StepSummary summary) {
|
deprecated private predicate smallstepProj(Node nodeFrom, StepSummary summary) {
|
||||||
smallstep(nodeFrom, _, 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
|
* 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.
|
* 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
|
Node nodeFrom, TypeTrackingNode nodeTo, TypeTrackerContent content
|
||||||
) {
|
) {
|
||||||
exists(Node obj | nodeTo.flowsTo(obj) and basicStoreStep(nodeFrom, obj, 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`.
|
* 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,
|
Node nodeFrom, TypeTrackingNode nodeTo, TypeTrackerContent loadContent,
|
||||||
TypeTrackerContent storeContent
|
TypeTrackerContent storeContent
|
||||||
) {
|
) {
|
||||||
@@ -293,7 +301,7 @@ private predicate flowsToLoadStoreStep(
|
|||||||
*
|
*
|
||||||
* A description of a step on an inter-procedural data flow path.
|
* 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. */
|
/** Gets a textual representation of this step summary. */
|
||||||
string toString() {
|
string toString() {
|
||||||
this instanceof LevelStep and result = "level"
|
this instanceof LevelStep and result = "level"
|
||||||
@@ -316,7 +324,7 @@ class StepSummary extends TStepSummary {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Provides predicates for updating step summaries (`StepSummary`s). */
|
/** Provides predicates for updating step summaries (`StepSummary`s). */
|
||||||
module StepSummary {
|
deprecated module StepSummary {
|
||||||
predicate append = Cached::append/2;
|
predicate append = Cached::append/2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -437,7 +445,7 @@ module StepSummary {
|
|||||||
* `t = t2.step(myType(t2), result)`. If you additionally want to track individual
|
* `t = t2.step(myType(t2), result)`. If you additionally want to track individual
|
||||||
* intra-procedural steps, use `t = t2.smallstep(myCallback(t2), result)`.
|
* intra-procedural steps, use `t = t2.smallstep(myCallback(t2), result)`.
|
||||||
*/
|
*/
|
||||||
class TypeTracker extends TTypeTracker {
|
deprecated class TypeTracker extends TTypeTracker {
|
||||||
Boolean hasCall;
|
Boolean hasCall;
|
||||||
OptionalTypeTrackerContent content;
|
OptionalTypeTrackerContent content;
|
||||||
|
|
||||||
@@ -565,7 +573,7 @@ class TypeTracker extends TTypeTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Provides predicates for implementing custom `TypeTracker`s. */
|
/** Provides predicates for implementing custom `TypeTracker`s. */
|
||||||
module TypeTracker {
|
deprecated module TypeTracker {
|
||||||
/**
|
/**
|
||||||
* Gets a valid end point of type tracking.
|
* Gets a valid end point of type tracking.
|
||||||
*/
|
*/
|
||||||
@@ -580,11 +588,11 @@ module TypeTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate backStepProj(TypeTrackingNode nodeTo, StepSummary summary) {
|
deprecated private predicate backStepProj(TypeTrackingNode nodeTo, StepSummary summary) {
|
||||||
step(_, nodeTo, summary)
|
step(_, nodeTo, summary)
|
||||||
}
|
}
|
||||||
|
|
||||||
private predicate backSmallstepProj(TypeTrackingNode nodeTo, StepSummary summary) {
|
deprecated private predicate backSmallstepProj(TypeTrackingNode nodeTo, StepSummary summary) {
|
||||||
smallstep(_, nodeTo, 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
|
* `t2 = t.step(result, myCallback(t2))`. If you additionally want to track individual
|
||||||
* intra-procedural steps, use `t2 = t.smallstep(result, myCallback(t2))`.
|
* intra-procedural steps, use `t2 = t.smallstep(result, myCallback(t2))`.
|
||||||
*/
|
*/
|
||||||
class TypeBackTracker extends TTypeBackTracker {
|
deprecated class TypeBackTracker extends TTypeBackTracker {
|
||||||
Boolean hasReturn;
|
Boolean hasReturn;
|
||||||
OptionalTypeTrackerContent content;
|
OptionalTypeTrackerContent content;
|
||||||
|
|
||||||
@@ -747,7 +755,7 @@ class TypeBackTracker extends TTypeBackTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Provides predicates for implementing custom `TypeBackTracker`s. */
|
/** Provides predicates for implementing custom `TypeBackTracker`s. */
|
||||||
module TypeBackTracker {
|
deprecated module TypeBackTracker {
|
||||||
/**
|
/**
|
||||||
* Gets a valid end point of type back-tracking.
|
* 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
|
* `stepCall` relation (`stepNoCall` not being recursive, can be join-ordered in the
|
||||||
* same way as in `stepInlineLate`).
|
* same way as in `stepInlineLate`).
|
||||||
*/
|
*/
|
||||||
module CallGraphConstruction {
|
deprecated module CallGraphConstruction {
|
||||||
/** The input to call graph construction. */
|
/** The input to call graph construction. */
|
||||||
signature module InputSig {
|
signature module InputSig {
|
||||||
/** A state to track during type tracking. */
|
/** A state to track during type tracking. */
|
||||||
class State;
|
class State;
|
||||||
|
|
||||||
/** Holds if type tracking should start at `start` in state `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`,
|
* 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
|
* Implementing this predicate using `StepSummary::[small]stepNoCall` yields
|
||||||
* standard type tracking.
|
* 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`,
|
* 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
|
* Implementing this predicate using `StepSummary::[small]stepCall` yields
|
||||||
* standard type tracking.
|
* 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. */
|
/** A projection of an element from the state space. */
|
||||||
class StateProj;
|
class StateProj;
|
||||||
@@ -802,25 +810,25 @@ module CallGraphConstruction {
|
|||||||
StateProj stateProj(State state);
|
StateProj stateProj(State state);
|
||||||
|
|
||||||
/** Holds if type tracking should stop at `n` when we are tracking projected state `stateProj`. */
|
/** 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. */
|
/** Provides the `track` predicate for use in call graph construction. */
|
||||||
module Make<InputSig Input> {
|
module Make<InputSig Input> {
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate stepNoCallProj(Node nodeFrom, StepSummary summary) {
|
deprecated private predicate stepNoCallProj(Node nodeFrom, StepSummary summary) {
|
||||||
Input::stepNoCall(nodeFrom, _, summary)
|
Input::stepNoCall(nodeFrom, _, summary)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
private predicate stepCallProj(Node nodeFrom, StepSummary summary) {
|
deprecated private predicate stepCallProj(Node nodeFrom, StepSummary summary) {
|
||||||
Input::stepCall(nodeFrom, _, summary)
|
Input::stepCall(nodeFrom, _, summary)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindingset[nodeFrom, t]
|
bindingset[nodeFrom, t]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
pragma[noopt]
|
pragma[noopt]
|
||||||
private TypeTracker stepNoCallInlineLate(
|
deprecated private TypeTracker stepNoCallInlineLate(
|
||||||
TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo
|
TypeTracker t, TypeTrackingNode nodeFrom, TypeTrackingNode nodeTo
|
||||||
) {
|
) {
|
||||||
exists(StepSummary summary |
|
exists(StepSummary summary |
|
||||||
@@ -837,7 +845,7 @@ module CallGraphConstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
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)
|
t.start() and Input::start(result, state)
|
||||||
or
|
or
|
||||||
exists(Input::StateProj stateProj |
|
exists(Input::StateProj stateProj |
|
||||||
@@ -855,12 +863,12 @@ module CallGraphConstruction {
|
|||||||
|
|
||||||
bindingset[t, summary]
|
bindingset[t, summary]
|
||||||
pragma[inline_late]
|
pragma[inline_late]
|
||||||
private TypeTracker appendInlineLate(TypeTracker t, StepSummary summary) {
|
deprecated private TypeTracker appendInlineLate(TypeTracker t, StepSummary summary) {
|
||||||
result = t.append(summary)
|
result = t.append(summary)
|
||||||
}
|
}
|
||||||
|
|
||||||
pragma[nomagic]
|
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 |
|
exists(TypeTracker t2 |
|
||||||
// non-linear recursion
|
// non-linear recursion
|
||||||
result = track(state, t2) and
|
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`. */
|
/** Gets a node that can be reached from _some_ start node in state `state`. */
|
||||||
pragma[nomagic]
|
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. */
|
/** A simple version of `CallGraphConstruction` that uses standard type tracking. */
|
||||||
@@ -882,15 +890,15 @@ module CallGraphConstruction {
|
|||||||
class State;
|
class State;
|
||||||
|
|
||||||
/** Holds if type tracking should start at `start` in state `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`. */
|
/** 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. */
|
/** Provides the `track` predicate for use in call graph construction. */
|
||||||
module Make<InputSig Input> {
|
module Make<InputSig Input> {
|
||||||
private module I implements CallGraphConstruction::InputSig {
|
deprecated private module I implements CallGraphConstruction::InputSig {
|
||||||
private import codeql.util.Unit
|
private import codeql.util.Unit
|
||||||
|
|
||||||
class State = Input::State;
|
class State = Input::State;
|
||||||
@@ -915,7 +923,7 @@ module CallGraphConstruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
import CallGraphConstruction::Make<I>
|
deprecated import CallGraphConstruction::Make<I>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.FlowSummaryImpl as FlowSummaryImpl
|
||||||
private import codeql.ruby.dataflow.internal.FlowSummaryImplSpecific as FlowSummaryImplSpecific
|
private import codeql.ruby.dataflow.internal.FlowSummaryImplSpecific as FlowSummaryImplSpecific
|
||||||
private import codeql.ruby.dataflow.internal.AccessPathSyntax
|
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;
|
deprecated class TypeTrackerContent = DataFlowPublic::ContentSet;
|
||||||
|
|
||||||
private module SCS = SummaryComponentStack;
|
|
||||||
|
|
||||||
private module SC = SummaryComponent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An optional content set, that is, a `ContentSet` or the special "no content set" value.
|
* 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. */
|
/** Gets a textual representation of this content set. */
|
||||||
string toString() {
|
string toString() {
|
||||||
this instanceof DataFlowPrivate::TNoContentSet and
|
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
|
* A label to use for `WithContent` and `WithoutContent` steps, restricting
|
||||||
* which `ContentSet` may pass through.
|
* which `ContentSet` may pass through.
|
||||||
*/
|
*/
|
||||||
class ContentFilter extends TContentFilter {
|
deprecated class ContentFilter = TypeTrackingImpl::TypeTrackingInput::ContentFilter;
|
||||||
/** 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Module for getting `ContentFilter` values. */
|
/** Module for getting `ContentFilter` values. */
|
||||||
module ContentFilter {
|
deprecated module ContentFilter {
|
||||||
/** Gets the filter that only allow element contents. */
|
/** 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`.
|
* Holds if a value stored with `storeContents` can be read back with `loadContents`.
|
||||||
*/
|
*/
|
||||||
pragma[inline]
|
pragma[inline]
|
||||||
predicate compatibleContents(TypeTrackerContent storeContents, TypeTrackerContent loadContents) {
|
deprecated predicate compatibleContents(
|
||||||
|
TypeTrackerContent storeContents, TypeTrackerContent loadContents
|
||||||
|
) {
|
||||||
storeContents.getAStoreContent() = loadContents.getAReadContent()
|
storeContents.getAStoreContent() = loadContents.getAReadContent()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the "no content set" value to use for a type tracker not inside any content. */
|
/** 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` */
|
/** 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.
|
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
|
||||||
*/
|
*/
|
||||||
predicate jumpStep = DataFlowPrivate::jumpStep/2;
|
deprecated predicate jumpStep = TypeTrackingImpl::TypeTrackingInput::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)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which may depend on the call graph. */
|
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which may depend on the call graph. */
|
||||||
pragma[nomagic]
|
deprecated predicate levelStepCall = TypeTrackingImpl::TypeTrackingInput::levelStepCall/2;
|
||||||
predicate levelStepCall(Node nodeFrom, Node nodeTo) {
|
|
||||||
exists(DataFlowPublic::ParameterNode param |
|
|
||||||
flowThrough(param) and
|
|
||||||
callStepNoInitialize(nodeTo.asExpr(), nodeFrom, param)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph. */
|
/** Holds if there is a level step from `nodeFrom` to `nodeTo`, which does not depend on the call graph. */
|
||||||
pragma[nomagic]
|
deprecated predicate levelStepNoCall = TypeTrackingImpl::TypeTrackingInput::levelStepNoCall/2;
|
||||||
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)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call.
|
* 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
|
* recursion (or, at best, terrible performance), since identifying calls to library
|
||||||
* methods is done using API graphs (which uses type tracking).
|
* 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.
|
* 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
|
* recursion (or, at best, terrible performance), since identifying calls to library
|
||||||
* methods is done using API graphs (which uses type tracking).
|
* methods is done using API graphs (which uses type tracking).
|
||||||
*/
|
*/
|
||||||
predicate returnStep(Node nodeFrom, Node nodeTo) {
|
deprecated predicate returnStep = TypeTrackingImpl::TypeTrackingInput::returnStep/2;
|
||||||
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
|
* 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
|
* to `z` inside `bar`, even though this content write happens _after_ `bar` is
|
||||||
* called.
|
* called.
|
||||||
*/
|
*/
|
||||||
predicate basicStoreStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet contents) {
|
deprecated predicate basicStoreStep = TypeTrackingImpl::TypeTrackingInput::storeStep/3;
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`.
|
* Holds if `nodeTo` is the result of accessing the `content` content of `nodeFrom`.
|
||||||
*/
|
*/
|
||||||
predicate basicLoadStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet contents) {
|
deprecated predicate basicLoadStep = TypeTrackingImpl::TypeTrackingInput::loadStep/3;
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
|
* Holds if the `loadContent` of `nodeFrom` is stored in the `storeContent` of `nodeTo`.
|
||||||
*/
|
*/
|
||||||
predicate basicLoadStoreStep(
|
deprecated predicate basicLoadStoreStep = TypeTrackingImpl::TypeTrackingInput::loadStoreStep/4;
|
||||||
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)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if type-tracking should step from `nodeFrom` to `nodeTo` but block flow of contents matched by `filter` through here.
|
* 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) {
|
deprecated predicate basicWithoutContentStep =
|
||||||
TypeTrackerSummaryFlow::basicWithoutContentStep(nodeFrom, nodeTo, filter)
|
TypeTrackingImpl::TypeTrackingInput::withoutContentStep/3;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds if type-tracking should step from `nodeFrom` to `nodeTo` if inside a content matched by `filter`.
|
* 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) {
|
deprecated predicate basicWithContentStep = TypeTrackingImpl::TypeTrackingInput::withContentStep/3;
|
||||||
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>;
|
|
||||||
|
|||||||
7
ruby/ql/lib/codeql/ruby/typetracking/TypeTracking.qll
Normal file
7
ruby/ql/lib/codeql/ruby/typetracking/TypeTracking.qll
Normal 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>
|
||||||
@@ -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>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import ruby
|
import ruby
|
||||||
import TestUtilities.InlineExpectationsTest
|
import TestUtilities.InlineExpectationsTest
|
||||||
import TestUtilities.InlineFlowTestUtil
|
import TestUtilities.InlineFlowTestUtil
|
||||||
private import codeql.ruby.typetracking.TypeTracker
|
private import codeql.ruby.typetracking.TypeTracking
|
||||||
|
|
||||||
private DataFlow::LocalSourceNode track(TypeTracker t, DataFlow::CallNode source) {
|
private DataFlow::LocalSourceNode track(TypeTracker t, DataFlow::CallNode source) {
|
||||||
t.start() and
|
t.start() and
|
||||||
|
|||||||
@@ -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: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: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: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:1099:10:1099:13 | ...[...] | Unexpected result: hasValueFlow=105.2 |
|
||||||
| array_flow.rb:1100:10:1100:13 | ...[...] | Unexpected result: hasValueFlow=105.3 |
|
| array_flow.rb:1100:10:1100:13 | ...[...] | Unexpected result: hasValueFlow=105.3 |
|
||||||
| array_flow.rb:1110:10:1110:13 | ...[...] | Unexpected result: hasValueFlow=105.2 |
|
| array_flow.rb:1110:10:1110:13 | ...[...] | Unexpected result: hasValueFlow=105.2 |
|
||||||
|
|||||||
@@ -9,30 +9,16 @@ testFailures
|
|||||||
| hash_flow.rb:219:27:219:47 | # $ hasValueFlow=14.2 | Missing result:hasValueFlow=14.2 |
|
| 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:291:10:291:14 | ...[...] | Unexpected result: hasValueFlow=19.1 |
|
||||||
| hash_flow.rb:294:10:294:14 | ...[...] | Unexpected result: hasValueFlow=19.3 |
|
| 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: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: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.1 |
|
||||||
| hash_flow.rb:559:17:559:57 | # $ hasValueFlow=34.1 $ hasValueFlow=34.2 | Missing result:hasValueFlow=34.2 |
|
| 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: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.1 |
|
||||||
| hash_flow.rb:591:20:591:60 | # $ hasValueFlow=36.1 $ hasValueFlow=36.2 | Missing result:hasValueFlow=36.2 |
|
| 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: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:776:10:776:14 | ...[...] | Unexpected result: hasValueFlow=46.1 |
|
||||||
| hash_flow.rb:779:10:779:14 | ...[...] | Unexpected result: hasValueFlow=46.3 |
|
| 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:781:10:781:17 | ...[...] | Unexpected result: hasValueFlow=46.1 |
|
||||||
| hash_flow.rb:784:10:784:17 | ...[...] | Unexpected result: hasValueFlow=46.3 |
|
| 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
|
failures
|
||||||
|
|||||||
@@ -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 | 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 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: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 | 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 | 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 | 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 | 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 | 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 | 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 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: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 | 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 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: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 | 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 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: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 | 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 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: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: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 | 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 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: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 | 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: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 |
|
| 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: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: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: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: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: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: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: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: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 | 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: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: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 | 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: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: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 | 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: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: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 | 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: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: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: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 | 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: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: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 | 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: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 |
|
| params_flow.rb:128:10:128:31 | Array | params_flow.rb:128:10:128:31 | Array |
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import codeql.ruby.AST
|
import codeql.ruby.AST
|
||||||
import codeql.ruby.DataFlow
|
import codeql.ruby.DataFlow
|
||||||
import codeql.ruby.typetracking.TypeTracker
|
import codeql.ruby.typetracking.TypeTracking
|
||||||
|
|
||||||
class LocalSourceNode extends DataFlow::LocalSourceNode {
|
class LocalSourceNode extends DataFlow::LocalSourceNode {
|
||||||
LocalSourceNode() { this.getLocation().getFile().getExtension() = "rb" }
|
LocalSourceNode() { this.getLocation().getFile().getExtension() = "rb" }
|
||||||
|
|||||||
Reference in New Issue
Block a user