Skip to content

Commit 6ce8e05

Browse files
committed
Ruby: Adopt shared type tracking library
1 parent 620e8dc commit 6ce8e05

27 files changed

+696
-593
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>

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)
@@ -456,7 +456,7 @@ private predicate splatArgumentAt(CfgNodes::ExprNodes::CallCfgNode c, int pos) {
456456
/** A collection of cached types and predicates to be evaluated in the same stage. */
457457
cached
458458
private module Cached {
459-
private import codeql.ruby.typetracking.TypeTrackerSpecific as TypeTrackerSpecific
459+
private import codeql.ruby.typetracking.internal.TypeTrackingImpl
460460

461461
cached
462462
newtype TNode =
@@ -575,14 +575,10 @@ private module Cached {
575575
VariableCapture::flowInsensitiveStep(nodeFrom, nodeTo)
576576
}
577577

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

588584
pragma[nomagic]
@@ -599,6 +595,16 @@ private module Cached {
599595
)
600596
}
601597

598+
private predicate isStoreTargetNode(Node n) {
599+
TypeTrackingInput::storeStep(_, n, _)
600+
or
601+
TypeTrackingInput::loadStoreStep(_, n, _, _)
602+
or
603+
TypeTrackingInput::withContentStepImpl(_, n, _)
604+
or
605+
TypeTrackingInput::withoutContentStepImpl(_, n, _)
606+
}
607+
602608
cached
603609
predicate isLocalSourceNode(Node n) {
604610
n instanceof TSourceParameterNode
@@ -614,11 +620,9 @@ private module Cached {
614620
entrySsaDefinition(n) and
615621
not LocalFlow::localFlowSsaParamInput(_, n)
616622
or
617-
TypeTrackerSpecific::basicStoreStep(_, n, _)
618-
or
619-
TypeTrackerSpecific::basicLoadStep(_, n, _)
623+
isStoreTargetNode(n)
620624
or
621-
TypeTrackerSpecific::basicLoadStoreStep(_, n, _, _)
625+
TypeTrackingInput::loadStep(_, n, _)
622626
}
623627

624628
cached
@@ -633,7 +637,7 @@ private module Cached {
633637
TElementContentOfTypeContent(string type, Boolean includeUnknown) {
634638
type = any(Content::KnownElementContent content).getIndex().getValueType()
635639
} or
636-
TNoContentSet() // Only used by type-tracking
640+
deprecated TNoContentSet() // Only used by type-tracking
637641

638642
cached
639643
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
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ private import codeql.ruby.ApiGraphs
77
private import codeql.ruby.Concepts
88
private import codeql.ruby.controlflow.CfgNodes::ExprNodes
99
private import codeql.ruby.DataFlow
10-
private import codeql.ruby.typetracking.TypeTracker
10+
private import codeql.ruby.typetracking.TypeTracking
1111
private import App as A
1212

1313
/** Contains implementation details for modeling `Rack::Response`. */

0 commit comments

Comments
 (0)