Skip to content

Commit dde83b6

Browse files
authored
Merge pull request github#14709 from hvitved/ruby/shared-type-tracking
Ruby: Adopt shared type tracking library
2 parents 2c625e3 + c6e805f commit dde83b6

28 files changed

+709
-594
lines changed

config/identical-files.json

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -462,10 +462,6 @@
462462
"ruby/ql/lib/codeql/ruby/security/internal/SensitiveDataHeuristics.qll",
463463
"swift/ql/lib/codeql/swift/security/internal/SensitiveDataHeuristics.qll"
464464
],
465-
"TypeTracker": [
466-
"python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll",
467-
"ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll"
468-
],
469465
"SummaryTypeTracker": [
470466
"python/ql/lib/semmle/python/dataflow/new/internal/SummaryTypeTracker.qll",
471467
"ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll"
@@ -534,4 +530,4 @@
534530
"python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ext.yml",
535531
"python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml"
536532
]
537-
}
533+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import codeql.ruby.DataFlow
2+
import codeql.ruby.typetracking.internal.TypeTrackingImpl
3+
4+
private module ConsistencyChecksInput implements ConsistencyChecksInputSig {
5+
predicate unreachableNodeExclude(DataFlow::Node n) { n instanceof DataFlow::PostUpdateNode }
6+
}
7+
8+
import ConsistencyChecks<ConsistencyChecksInput>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Ruby now makes use of the shared type tracking library, exposed as `codeql.ruby.typetracking.TypeTracking`. The existing type tracking library, `codeql.ruby.typetracking.TypeTracker`, has consequently been deprecated.

ruby/ql/lib/codeql/ruby/ApiGraphs.qll

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
private import codeql.ruby.AST
99
private import codeql.ruby.DataFlow
1010
private import codeql.ruby.typetracking.ApiGraphShared
11-
private import codeql.ruby.typetracking.TypeTracker
12-
private import codeql.ruby.typetracking.TypeTrackerSpecific as TypeTrackerSpecific
11+
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
1312
private import codeql.ruby.controlflow.CfgNodes
1413
private import codeql.ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
1514
private import codeql.ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch
@@ -1050,9 +1049,9 @@ module API {
10501049

10511050
/** INTERNAL USE ONLY. */
10521051
module Internal {
1053-
private module Shared = ApiGraphShared<SharedArg>;
1052+
private module MkShared = ApiGraphShared<SharedArg>;
10541053

1055-
import Shared
1054+
import MkShared
10561055

10571056
/** Gets the API node corresponding to the module/class object for `mod`. */
10581057
bindingset[mod]
@@ -1093,7 +1092,7 @@ module API {
10931092
private predicate needsSinkNode(DataFlow::Node node) {
10941093
node instanceof DataFlowPrivate::ArgumentNode
10951094
or
1096-
TypeTrackerSpecific::basicStoreStep(node, _, _)
1095+
TypeTrackingInput::storeStep(node, _, _)
10971096
or
10981097
node = any(DataFlow::CallableNode callable).getAReturnNode()
10991098
or
@@ -1203,18 +1202,16 @@ module API {
12031202

12041203
cached
12051204
predicate contentEdge(Node pred, DataFlow::Content content, Node succ) {
1206-
exists(
1207-
DataFlow::Node object, DataFlow::Node value, TypeTrackerSpecific::TypeTrackerContent c
1208-
|
1209-
TypeTrackerSpecific::basicLoadStep(object, value, c) and
1205+
exists(DataFlow::Node object, DataFlow::Node value, DataFlow::ContentSet c |
1206+
TypeTrackingInput::loadStep(object, value, c) and
12101207
content = c.getAStoreContent() and
12111208
not c.isSingleton(any(DataFlow::Content::AttributeNameContent k)) and
12121209
// `x -> x.foo` with content "foo"
12131210
pred = getForwardOrBackwardEndNode(getALocalSourceStrict(object)) and
12141211
succ = getForwardStartNode(value)
12151212
or
12161213
// Based on `object.c = value` generate `object -> value` with content `c`
1217-
TypeTrackerSpecific::basicStoreStep(value, object, c) and
1214+
TypeTrackingInput::storeStep(value, object, c) and
12181215
content = c.getAStoreContent() and
12191216
pred = getForwardOrBackwardEndNode(getALocalSourceStrict(object)) and
12201217
succ = MkSinkNode(value)

ruby/ql/lib/codeql/ruby/dataflow/FlowSummary.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import codeql.ruby.AST
44
private import codeql.ruby.CFG
5-
private import codeql.ruby.typetracking.TypeTracker
5+
private import codeql.ruby.typetracking.TypeTracking
66
import codeql.ruby.DataFlow
77
private import internal.FlowSummaryImpl as Impl
88
private import internal.DataFlowDispatch

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
private import codeql.ruby.AST
22
private import codeql.ruby.CFG
33
private import DataFlowPrivate
4-
private import codeql.ruby.typetracking.TypeTracker
5-
private import codeql.ruby.typetracking.TypeTrackerSpecific as TypeTrackerSpecific
4+
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
65
private import codeql.ruby.ast.internal.Module
76
private import FlowSummaryImpl as FlowSummaryImpl
87
private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
@@ -657,7 +656,7 @@ private module TrackInstanceInput implements CallGraphConstruction::InputSig {
657656
predicate stepNoCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
658657
// We exclude steps into `self` parameters. For those, we instead rely on the type of
659658
// the enclosing module
660-
StepSummary::smallstepNoCall(nodeFrom, nodeTo, summary) and
659+
smallStepNoCall(nodeFrom, nodeTo, summary) and
661660
isNotSelf(nodeTo)
662661
or
663662
// We exclude steps into type checked variables. For those, we instead rely on the
@@ -667,7 +666,7 @@ private module TrackInstanceInput implements CallGraphConstruction::InputSig {
667666
}
668667

669668
predicate stepCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
670-
StepSummary::smallstepCall(nodeFrom, nodeTo, summary)
669+
smallStepCall(nodeFrom, nodeTo, summary)
671670
}
672671

673672
class StateProj = Unit;
@@ -941,7 +940,7 @@ private module TrackSingletonMethodOnInstanceInput implements CallGraphConstruct
941940
RelevantCall call, DataFlow::Node arg, DataFlow::ParameterNode p,
942941
CfgNodes::ExprCfgNode nodeFromPreExpr
943942
|
944-
TypeTrackerSpecific::callStep(call, arg, p) and
943+
callStep(call, arg, p) and
945944
nodeTo.getPreUpdateNode() = arg and
946945
summary.toString() = "return" and
947946
(
@@ -965,13 +964,13 @@ private module TrackSingletonMethodOnInstanceInput implements CallGraphConstruct
965964
}
966965

967966
predicate stepNoCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
968-
StepSummary::smallstepNoCall(nodeFrom, nodeTo, summary)
967+
smallStepNoCall(nodeFrom, nodeTo, summary)
969968
or
970969
localFlowStep(nodeFrom, nodeTo, summary)
971970
}
972971

973972
predicate stepCall(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, StepSummary summary) {
974-
StepSummary::smallstepCall(nodeFrom, nodeTo, summary)
973+
smallStepCall(nodeFrom, nodeTo, summary)
975974
or
976975
paramReturnFlow(nodeFrom, nodeTo, summary)
977976
}

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ module LocalFlow {
113113
SsaImpl::lastRefBeforeRedefExt(def, bb, i, next.getDefinitionExt()) and
114114
exprFrom = bb.getNode(i) and
115115
exprFrom.getExpr() instanceof VariableReadAccess and
116-
exprFrom = [nodeFrom.asExpr(), nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr()]
116+
exprFrom = [nodeFrom.asExpr(), nodeFrom.(PostUpdateNodeImpl).getPreUpdateNode().asExpr()]
117117
)
118118
}
119119

@@ -159,7 +159,7 @@ module LocalFlow {
159159
firstReadExt(def, nodeTo.asExpr())
160160
or
161161
// Flow from post-update read to next read
162-
localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
162+
localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNodeImpl).getPreUpdateNode(), nodeTo)
163163
or
164164
// Flow into phi (read) SSA definition node from def
165165
localFlowSsaInputFromDef(nodeFrom, def, nodeTo)
@@ -454,7 +454,7 @@ private predicate splatArgumentAt(CfgNodes::ExprNodes::CallCfgNode c, int pos) {
454454
/** A collection of cached types and predicates to be evaluated in the same stage. */
455455
cached
456456
private module Cached {
457-
private import codeql.ruby.typetracking.TypeTrackerSpecific as TypeTrackerSpecific
457+
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
458458

459459
cached
460460
newtype TNode =
@@ -573,14 +573,10 @@ private module Cached {
573573
VariableCapture::flowInsensitiveStep(nodeFrom, nodeTo)
574574
}
575575

576+
/** Holds if `n` wraps an SSA definition without ingoing flow. */
576577
private predicate entrySsaDefinition(SsaDefinitionExtNode n) {
577-
n = LocalFlow::getParameterDefNode(_)
578-
or
579-
exists(SsaImpl::DefinitionExt def | def = n.getDefinitionExt() |
580-
def instanceof Ssa::SelfDefinition
581-
or
582-
def instanceof Ssa::CapturedEntryDefinition
583-
)
578+
n.getDefinitionExt() =
579+
any(SsaImpl::WriteDefinition def | not def.(Ssa::WriteDefinition).assigns(_))
584580
}
585581

586582
pragma[nomagic]
@@ -597,6 +593,16 @@ private module Cached {
597593
)
598594
}
599595

596+
private predicate isStoreTargetNode(Node n) {
597+
TypeTrackingInput::storeStep(_, n, _)
598+
or
599+
TypeTrackingInput::loadStoreStep(_, n, _, _)
600+
or
601+
TypeTrackingInput::withContentStepImpl(_, n, _)
602+
or
603+
TypeTrackingInput::withoutContentStepImpl(_, n, _)
604+
}
605+
600606
cached
601607
predicate isLocalSourceNode(Node n) {
602608
n instanceof TSourceParameterNode
@@ -612,11 +618,9 @@ private module Cached {
612618
entrySsaDefinition(n) and
613619
not LocalFlow::localFlowSsaParamInput(_, n)
614620
or
615-
TypeTrackerSpecific::basicStoreStep(_, n, _)
616-
or
617-
TypeTrackerSpecific::basicLoadStep(_, n, _)
621+
isStoreTargetNode(n)
618622
or
619-
TypeTrackerSpecific::basicLoadStoreStep(_, n, _, _)
623+
TypeTrackingInput::loadStep(_, n, _)
620624
}
621625

622626
cached
@@ -631,7 +635,7 @@ private module Cached {
631635
TElementContentOfTypeContent(string type, Boolean includeUnknown) {
632636
type = any(Content::KnownElementContent content).getIndex().getValueType()
633637
} or
634-
TNoContentSet() // Only used by type-tracking
638+
deprecated TNoContentSet() // Only used by type-tracking
635639

636640
cached
637641
class TContentSet =

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPublic.qll

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@ private import codeql.ruby.AST
22
private import DataFlowDispatch
33
private import DataFlowPrivate
44
private import codeql.ruby.CFG
5-
private import codeql.ruby.typetracking.TypeTracker
5+
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
66
private import codeql.ruby.dataflow.SSA
77
private import FlowSummaryImpl as FlowSummaryImpl
8-
private import SsaImpl as SsaImpl
98
private import codeql.ruby.ApiGraphs
109

1110
/**
@@ -245,7 +244,7 @@ class LocalSourceNode extends Node {
245244

246245
/** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */
247246
pragma[inline]
248-
predicate flowsTo(Node nodeTo) { hasLocalSource(nodeTo, this) }
247+
predicate flowsTo(Node nodeTo) { flowsTo(this, nodeTo) }
249248

250249
/**
251250
* Gets a node that this node may flow to using one heap and/or interprocedural step.
@@ -261,14 +260,14 @@ class LocalSourceNode extends Node {
261260
* See `TypeBackTracker` for more details about how to use this.
262261
*/
263262
pragma[inline]
264-
LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t2 = t.step(result, this) }
263+
LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t = t2.step(result, this) }
265264

266265
/**
267266
* Gets a node to which data may flow from this node in zero or
268267
* more local data-flow steps.
269268
*/
270269
pragma[inline]
271-
Node getALocalUse() { hasLocalSource(result, this) }
270+
Node getALocalUse() { flowsTo(this, result) }
272271

273272
/** Gets a method call where this node flows to the receiver. */
274273
CallNode getAMethodCall() { Cached::hasMethodCall(this, result, _) }
@@ -354,21 +353,21 @@ class PostUpdateNode extends Node instanceof PostUpdateNodeImpl {
354353
Node getPreUpdateNode() { result = super.getPreUpdateNode() }
355354
}
356355

356+
/** An SSA definition, viewed as a node in a data flow graph. */
357+
class SsaDefinitionNode extends Node instanceof SsaDefinitionExtNode {
358+
Ssa::Definition def;
359+
360+
SsaDefinitionNode() { this = TSsaDefinitionExtNode(def) }
361+
362+
/** Gets the underlying SSA definition. */
363+
Ssa::Definition getDefinition() { result = def }
364+
365+
/** Gets the underlying variable. */
366+
Variable getVariable() { result = def.getSourceVariable() }
367+
}
368+
357369
cached
358370
private module Cached {
359-
cached
360-
predicate hasLocalSource(Node sink, Node source) {
361-
// Declaring `source` to be a `SourceNode` currently causes a redundant check in the
362-
// recursive case, so instead we check it explicitly here.
363-
source = sink and
364-
source instanceof LocalSourceNode
365-
or
366-
exists(Node mid |
367-
hasLocalSource(mid, source) and
368-
localFlowStepTypeTracker(mid, sink)
369-
)
370-
}
371-
372371
cached
373372
predicate hasMethodCall(LocalSourceNode source, CallNode call, string name) {
374373
source.flowsTo(call.getReceiver()) and

ruby/ql/lib/codeql/ruby/frameworks/XmlParsing.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
private import codeql.ruby.Concepts
66
private import codeql.ruby.AST
77
private import codeql.ruby.DataFlow
8-
private import codeql.ruby.typetracking.TypeTracker
8+
private import codeql.ruby.typetracking.TypeTracking
99
private import codeql.ruby.ApiGraphs
1010
private import codeql.ruby.controlflow.CfgNodes as CfgNodes
1111

ruby/ql/lib/codeql/ruby/frameworks/rack/internal/App.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ private import codeql.ruby.AST
66
private import codeql.ruby.ApiGraphs
77
private import codeql.ruby.Concepts
88
private import codeql.ruby.DataFlow
9-
private import codeql.ruby.typetracking.TypeTracker
9+
private import codeql.ruby.typetracking.TypeTracking
1010
private import Response::Private as RP
1111

1212
/**

0 commit comments

Comments
 (0)