Skip to content

Commit 4f346dd

Browse files
committed
wip
1 parent 42925b5 commit 4f346dd

File tree

8 files changed

+1412
-121
lines changed

8 files changed

+1412
-121
lines changed

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,9 +176,6 @@ module Ssa {
176176

177177
override string toString() { result = this.getControlFlowNode().toString() }
178178

179-
/** Gets the location of this SSA definition. */
180-
Location getLocation() { result = this.getControlFlowNode().getLocation() }
181-
182179
/** Gets the scope of this SSA definition. */
183180
CfgScope getScope() { result = this.getBasicBlock().getScope() }
184181
}

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

Lines changed: 188 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -87,39 +87,37 @@ class SsaInputDefinitionExt extends SsaImpl::DefinitionExt {
8787

8888
/** Provides predicates related to local data flow. */
8989
module LocalFlow {
90-
/**
91-
* Holds if `nodeFrom` is a node for SSA definition `def`, which can reach `next`.
92-
*/
93-
pragma[nomagic]
94-
private predicate localFlowSsaInputFromDef(
95-
SsaDefinitionExtNode nodeFrom, SsaImpl::DefinitionExt def, SsaInputNode nodeTo
96-
) {
97-
exists(BasicBlock bb, int i, BasicBlock input, SsaInputDefinitionExt next |
98-
next.hasInputFromBlock(def, bb, i, input) and
99-
def = nodeFrom.getDefinitionExt() and
100-
def.definesAt(_, bb, i, _) and
101-
nodeTo = TSsaInputNode(next, input)
102-
)
103-
}
104-
105-
/**
106-
* Holds if `nodeFrom` is a last read of SSA definition `def`, which
107-
* can reach `nodeTo`.
108-
*/
109-
pragma[nomagic]
110-
predicate localFlowSsaInputFromRead(SsaImpl::DefinitionExt def, Node nodeFrom, SsaInputNode nodeTo) {
111-
exists(
112-
BasicBlock bb, int i, CfgNodes::ExprCfgNode exprFrom, BasicBlock input,
113-
SsaInputDefinitionExt next
114-
|
115-
next.hasInputFromBlock(def, bb, i, input) and
116-
exprFrom = bb.getNode(i) and
117-
exprFrom.getExpr() instanceof VariableReadAccess and
118-
exprFrom = [nodeFrom.asExpr(), nodeFrom.(PostUpdateNodeImpl).getPreUpdateNode().asExpr()] and
119-
nodeTo = TSsaInputNode(next, input)
120-
)
121-
}
122-
90+
// /**
91+
// * Holds if `nodeFrom` is a node for SSA definition `def`, which can reach `next`.
92+
// */
93+
// pragma[nomagic]
94+
// private predicate localFlowSsaInputFromDef(
95+
// SsaDefinitionExtNode nodeFrom, SsaImpl::DefinitionExt def, SsaInputNode nodeTo
96+
// ) {
97+
// exists(BasicBlock bb, int i, BasicBlock input, SsaInputDefinitionExt next |
98+
// next.hasInputFromBlock(def, bb, i, input) and
99+
// def = nodeFrom.getDefinitionExt() and
100+
// def.definesAt(_, bb, i, _) and
101+
// nodeTo = TSsaInputNode(next, input)
102+
// )
103+
// }
104+
// /**
105+
// * Holds if `nodeFrom` is a last read of SSA definition `def`, which
106+
// * can reach `nodeTo`.
107+
// */
108+
// pragma[nomagic]
109+
// predicate localFlowSsaInputFromRead(SsaImpl::DefinitionExt def, Node nodeFrom, SsaInputNode nodeTo) {
110+
// exists(
111+
// BasicBlock bb, int i, CfgNodes::ExprCfgNode exprFrom, BasicBlock input,
112+
// SsaInputDefinitionExt next
113+
// |
114+
// next.hasInputFromBlock(def, bb, i, input) and
115+
// exprFrom = bb.getNode(i) and
116+
// exprFrom.getExpr() instanceof VariableReadAccess and
117+
// exprFrom = [nodeFrom.asExpr(), nodeFrom.(PostUpdateNodeImpl).getPreUpdateNode().asExpr()] and
118+
// nodeTo = TSsaInputNode(next, input)
119+
// )
120+
// }
123121
/** Gets the SSA definition node corresponding to parameter `p`. */
124122
pragma[nomagic]
125123
SsaDefinitionExtNode getParameterDefNode(NamedParameter p) {
@@ -139,14 +137,13 @@ module LocalFlow {
139137
nodeTo.getDefinitionExt() = nodeFrom.(SelfParameterNodeImpl).getSelfDefinition()
140138
}
141139

142-
/**
143-
* Holds if there is a local use-use flow step from `nodeFrom` to `nodeTo`
144-
* involving SSA definition `def`.
145-
*/
146-
predicate localSsaFlowStepUseUse(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
147-
SsaImpl::adjacentReadPairExt(def, nodeFrom.asExpr(), nodeTo.asExpr())
148-
}
149-
140+
// /**
141+
// * Holds if there is a local use-use flow step from `nodeFrom` to `nodeTo`
142+
// * involving SSA definition `def`.
143+
// */
144+
// predicate localSsaFlowStepUseUse(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
145+
// SsaImpl::adjacentReadPairExt(def, nodeFrom.asExpr(), nodeTo.asExpr())
146+
// }
150147
/**
151148
* Holds if SSA definition `def` assigns `value` to the underlying variable.
152149
*
@@ -173,33 +170,32 @@ module LocalFlow {
173170
)
174171
}
175172

176-
/**
177-
* Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
178-
* SSA definition `def`.
179-
*/
180-
pragma[nomagic]
181-
predicate localSsaFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
182-
// Flow from assignment into SSA definition
183-
ssaDefAssigns(def, nodeFrom.asExpr()) and
184-
nodeTo.(SsaDefinitionExtNode).getDefinitionExt() = def
185-
or
186-
// Flow from SSA definition to first read
187-
def = nodeFrom.(SsaDefinitionExtNode).getDefinitionExt() and
188-
SsaImpl::firstReadExt(def, nodeTo.asExpr())
189-
or
190-
// Flow from post-update read to next read
191-
localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNodeImpl).getPreUpdateNode(), nodeTo)
192-
or
193-
// Flow into phi (read) SSA definition node from def
194-
localFlowSsaInputFromDef(nodeFrom, def, nodeTo)
195-
or
196-
nodeTo.(SsaDefinitionExtNode).getDefinitionExt() = def and
197-
def = nodeFrom.(SsaInputNode).getDefinitionExt()
198-
or
199-
localFlowSsaParamInput(nodeFrom, nodeTo) and
200-
def = nodeTo.(SsaDefinitionExtNode).getDefinitionExt()
201-
}
202-
173+
// /**
174+
// * Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
175+
// * SSA definition `def`.
176+
// */
177+
// pragma[nomagic]
178+
// predicate localSsaFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
179+
// // // Flow from assignment into SSA definition
180+
// // ssaDefAssigns(def, nodeFrom.asExpr()) and
181+
// // nodeTo.(SsaDefinitionExtNode).getDefinitionExt() = def
182+
// // or
183+
// // // Flow from SSA definition to first read
184+
// // def = nodeFrom.(SsaDefinitionExtNode).getDefinitionExt() and
185+
// // SsaImpl::firstReadExt(def, nodeTo.asExpr())
186+
// // or
187+
// // // Flow from post-update read to next read
188+
// // localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNodeImpl).getPreUpdateNode(), nodeTo)
189+
// // or
190+
// // // Flow into phi (read) SSA definition node from def
191+
// // localFlowSsaInputFromDef(nodeFrom, def, nodeTo)
192+
// // or
193+
// // nodeTo.(SsaDefinitionExtNode).getDefinitionExt() = def and
194+
// // def = nodeFrom.(SsaInputNode).getDefinitionExt()
195+
// // or
196+
// localFlowSsaParamInput(nodeFrom, nodeTo) and
197+
// def = nodeTo.(SsaDefinitionExtNode).getDefinitionExt()
198+
// }
203199
pragma[nomagic]
204200
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
205201
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::BlockArgumentCfgNode).getValue()
@@ -338,6 +334,70 @@ predicate isNonConstantExpr(CfgNodes::ExprCfgNode n) {
338334
not n.getExpr() instanceof ConstantAccess
339335
}
340336

337+
private module SsaIntegration {
338+
private module Input implements SsaImpl::Impl::DataFlowIntegrationInputSig {
339+
private import ruby::Ast as R
340+
341+
class Expr extends CfgNodes::ExprCfgNode {
342+
predicate hasCfgNode(SsaImpl::SsaInput::BasicBlock bb, int i) { this = bb.getNode(i) }
343+
344+
predicate hasPostUpdateNode() { this = any(ExprPostUpdateNode n).getPreUpdateNode().asExpr() }
345+
}
346+
347+
/**
348+
* Holds if SSA definition `def` assigns `value` to the underlying variable.
349+
*
350+
* This is either a direct assignment, `x = value`, or an assignment via
351+
* simple pattern matching
352+
*
353+
* ```rb
354+
* case value
355+
* in Foo => x then ...
356+
* in y => then ...
357+
* end
358+
* ```
359+
*/
360+
predicate ssaDefAssigns(SsaImpl::WriteDefinition def, Expr value) {
361+
def.(Ssa::WriteDefinition).assigns(value)
362+
or
363+
exists(CfgNodes::ExprNodes::CaseExprCfgNode case, CfgNodes::AstCfgNode pattern |
364+
case.getValue() = value and
365+
pattern = case.getBranch(_).(CfgNodes::ExprNodes::InClauseCfgNode).getPattern()
366+
|
367+
def.(Ssa::WriteDefinition).getWriteAccess() =
368+
[pattern, pattern.(CfgNodes::ExprNodes::AsPatternCfgNode).getVariableAccess()]
369+
)
370+
}
371+
372+
class Parameter = ParameterNodeImpl;
373+
374+
predicate ssaDefInitializesParam(SsaImpl::WriteDefinition def, ParameterNodeImpl p) {
375+
exists(BasicBlock bb, int i |
376+
bb.getNode(i).getAstNode() = p.getParameter().(NamedParameter).getDefiningAccess() and
377+
def.definesAt(_, bb, i)
378+
)
379+
or
380+
def = p.(SelfParameterNodeImpl).getSelfDefinition()
381+
}
382+
}
383+
384+
module Impl = SsaImpl::Impl::DataFlowIntegration<Input>;
385+
386+
private Impl::Node asNode(Node n) {
387+
result = n.(SsaNode).getSsaNode()
388+
or
389+
result.(Impl::ExprNode).getExpr() = n.asExpr()
390+
or
391+
result.(Impl::ExprPostUpdateNode).getExpr() = n.(PostUpdateNode).getPreUpdateNode().asExpr()
392+
or
393+
result.(Impl::ParameterNode).getParameter() = n
394+
}
395+
396+
predicate localFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
397+
Impl::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo))
398+
}
399+
}
400+
341401
/** Provides logic related to captured variables. */
342402
module VariableCapture {
343403
private import codeql.dataflow.VariableCapture as Shared
@@ -359,6 +419,8 @@ module VariableCapture {
359419

360420
class BasicBlock extends BasicBlocks::BasicBlock {
361421
Callable getEnclosingCallable() { result = this.getScope() }
422+
423+
Location getLocation(int i) { result = this.getNode(i).getLocation() }
362424
}
363425

364426
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
@@ -537,10 +599,11 @@ private module Cached {
537599
newtype TNode =
538600
TExprNode(CfgNodes::ExprCfgNode n) or
539601
TReturningNode(CfgNodes::ReturningCfgNode n) { exists(n.getReturnedValueNode()) } or
540-
TSsaDefinitionExtNode(SsaImpl::DefinitionExt def) or
541-
TSsaInputNode(SsaInputDefinitionExt def, BasicBlock input) {
542-
def.hasInputFromBlock(_, _, _, input)
543-
} or
602+
TSsaNode(SsaIntegration::Impl::SsaNode node) or
603+
// TSsaDefinitionExtNode(SsaImpl::DefinitionExt def) or
604+
// TSsaInputNode(SsaInputDefinitionExt def, BasicBlock input) {
605+
// def.hasInputFromBlock(_, _, _, input)
606+
// } or
544607
TCapturedVariableNode(VariableCapture::CapturedVariable v) or
545608
TNormalParameterNode(Parameter p) {
546609
p instanceof SimpleParameter or
@@ -621,13 +684,16 @@ private module Cached {
621684
// captured variables are handled by the shared `VariableCapture` library
622685
not def instanceof VariableCapture::CapturedSsaDefinitionExt
623686
|
624-
LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo)
625-
or
626-
LocalFlow::localSsaFlowStepUseUse(def, nodeFrom, nodeTo) and
627-
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
628-
or
629-
LocalFlow::localFlowSsaInputFromRead(def, nodeFrom, nodeTo) and
687+
SsaIntegration::localFlowStep(def, nodeFrom, nodeTo) and
630688
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
689+
// // SsaIntegration::Impl::localFlowStep(def, nodeFrom, nodeTo)
690+
// LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo)
691+
// or
692+
// LocalFlow::localSsaFlowStepUseUse(def, nodeFrom, nodeTo) and
693+
// not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
694+
// or
695+
// LocalFlow::localFlowSsaInputFromRead(def, nodeFrom, nodeTo) and
696+
// not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
631697
)
632698
or
633699
VariableCapture::valueStep(nodeFrom, nodeTo)
@@ -642,10 +708,11 @@ private module Cached {
642708
predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) {
643709
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
644710
or
645-
LocalFlow::localSsaFlowStep(_, nodeFrom, nodeTo)
646-
or
647-
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
711+
// LocalFlow::localSsaFlowStep(_, nodeFrom, nodeTo)
712+
SsaIntegration::localFlowStep(_, nodeFrom, nodeTo)
648713
or
714+
// LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
715+
// or
649716
// Simple flow through library code is included in the exposed local
650717
// step relation, even though flow is technically inter-procedural
651718
FlowSummaryImpl::Private::Steps::summaryThroughStepValue(nodeFrom, nodeTo, _)
@@ -658,12 +725,13 @@ private module Cached {
658725
predicate localFlowStepTypeTracker(Node nodeFrom, Node nodeTo) {
659726
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
660727
or
661-
LocalFlow::localSsaFlowStep(_, nodeFrom, nodeTo)
662-
or
663-
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
664-
or
665-
LocalFlow::localFlowSsaInputFromRead(_, nodeFrom, nodeTo)
728+
SsaIntegration::localFlowStep(_, nodeFrom, nodeTo)
666729
or
730+
// LocalFlow::localSsaFlowStep(_, nodeFrom, nodeTo)
731+
// or
732+
// LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
733+
// or
734+
// LocalFlow::localFlowSsaInputFromRead(_, nodeFrom, nodeTo)
667735
VariableCapture::flowInsensitiveStep(nodeFrom, nodeTo)
668736
or
669737
LocalFlow::flowSummaryLocalStep(nodeFrom, nodeTo, any(LibraryCallableToIncludeInTypeTracking c),
@@ -862,14 +930,28 @@ predicate nodeIsHidden(Node n) {
862930
}
863931

864932
/** An SSA definition, viewed as a node in a data flow graph. */
865-
class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
933+
abstract class SsaNode extends NodeImpl, TSsaNode {
934+
SsaIntegration::Impl::SsaNode node;
866935
SsaImpl::DefinitionExt def;
867936

868-
SsaDefinitionExtNode() { this = TSsaDefinitionExtNode(def) }
937+
SsaNode() {
938+
this = TSsaNode(node) and
939+
def = node.getDefinitionExt()
940+
}
941+
942+
SsaIntegration::Impl::SsaNode getSsaNode() { result = node }
869943

870-
/** Gets the underlying SSA definition. */
871944
SsaImpl::DefinitionExt getDefinitionExt() { result = def }
872945

946+
override Location getLocationImpl() { result = node.getLocation() }
947+
948+
override string toStringImpl() { result = node.toString() }
949+
}
950+
951+
/** An SSA definition, viewed as a node in a data flow graph. */
952+
class SsaDefinitionExtNode extends SsaNode {
953+
override SsaIntegration::Impl::SsaDefinitionExtNode node;
954+
873955
/** Gets the underlying variable. */
874956
Variable getVariable() { result = def.getSourceVariable() }
875957

@@ -881,10 +963,16 @@ class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
881963
}
882964

883965
override CfgScope getCfgScope() { result = def.getBasicBlock().getScope() }
966+
}
967+
968+
class SsaDefinitionNodeImpl extends SsaDefinitionExtNode {
969+
Ssa::Definition ssaDef;
884970

885-
override Location getLocationImpl() { result = def.getLocation() }
971+
SsaDefinitionNodeImpl() { ssaDef = def }
886972

887-
override string toStringImpl() { result = def.toString() }
973+
override Location getLocationImpl() { result = ssaDef.getLocation() }
974+
975+
override string toStringImpl() { result = ssaDef.toString() }
888976
}
889977

890978
/**
@@ -922,20 +1010,20 @@ class SsaDefinitionExtNode extends NodeImpl, TSsaDefinitionExtNode {
9221010
*
9231011
* both inputs into the phi read node after the outer condition are guarded.
9241012
*/
925-
class SsaInputNode extends NodeImpl, TSsaInputNode {
926-
SsaImpl::DefinitionExt def;
1013+
class SsaInputNode extends SsaNode {
1014+
override SsaIntegration::Impl::SsaInputNode node;
9271015
BasicBlock input;
9281016

929-
SsaInputNode() { this = TSsaInputNode(def, input) }
1017+
SsaInputNode() { node.hasInputFromBlock(def, input) }
9301018

931-
/** Gets the underlying SSA definition. */
932-
SsaImpl::DefinitionExt getDefinitionExt() { result = def }
1019+
predicate isInputInto(BasicBlock bb, SsaImpl::DefinitionExt target) {
1020+
bb = input and
1021+
target = def
1022+
}
9331023

9341024
override CfgScope getCfgScope() { result = input.getScope() }
935-
936-
override Location getLocationImpl() { result = input.getLastNode().getLocation() }
937-
938-
override string toStringImpl() { result = "[input] " + def }
1025+
// override Location getLocationImpl() { result = input.getLastNode().getLocation() }
1026+
// override string toStringImpl() { result = "[input] " + def }
9391027
}
9401028

9411029
/** An SSA definition for a `self` variable. */

0 commit comments

Comments
 (0)