Skip to content

Commit 578b944

Browse files
committed
Flow for captured local variables
1 parent e467550 commit 578b944

2 files changed

Lines changed: 53 additions & 1 deletion

File tree

ql/src/codeql_ruby/dataflow/internal/SsaImpl.qll

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,49 @@ private module Cached {
176176
)
177177
}
178178

179+
/**
180+
* Holds if there is flow for a captured variable from the enclosing scope into a block.
181+
* ```rb
182+
* foo = 0
183+
* bar {
184+
* puts foo
185+
* }
186+
* ```
187+
*/
188+
cached
189+
predicate captureFlowIn(Definition def, Definition entry) {
190+
exists(LocalVariable v, BasicBlock bb, int i |
191+
ssaDefReachesRead(v, def, bb, i) and
192+
capturedCallRead(bb, i, v) and
193+
exists(BasicBlock bb2, int i2 |
194+
capturedEntryWrite(bb2, i2, v) and
195+
entry.definesAt(v, bb2, i2)
196+
)
197+
)
198+
}
199+
200+
/**
201+
* Holds if there is outgoinh flow for a captured variable that is updated in a block.
202+
* ```rb
203+
* foo = 0
204+
* bar {
205+
* foo += 10
206+
* }
207+
* puts foo
208+
* ```
209+
*/
210+
cached
211+
predicate captureFlowOut(Definition def, Definition exit) {
212+
exists(LocalVariable v, BasicBlock bb, int i |
213+
ssaDefReachesRead(v, def, bb, i) and
214+
capturedExitRead(bb, i, v) and
215+
exists(BasicBlock bb2, int i2 |
216+
capturedCallWrite(bb2, i2, v) and
217+
exit.definesAt(v, bb2, i2)
218+
)
219+
)
220+
}
221+
179222
cached
180223
Definition phiHasInputFromBlock(PhiNode phi, BasicBlock bb) {
181224
phiHasInputFromBlock(phi, result, bb)

ql/src/codeql_ruby/typetracking/TypeTrackerSpecific.qll

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ private import codeql_ruby.dataflow.internal.DataFlowImplCommon as DataFlowImplC
33
private import codeql_ruby.dataflow.internal.DataFlowPublic as DataFlowPublic
44
private import codeql_ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
55
private import codeql_ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch
6+
private import codeql_ruby.dataflow.internal.SsaImpl as SsaImpl
67
private import codeql_ruby.controlflow.CfgNodes
78

89
class Node = DataFlowPublic::Node;
@@ -11,7 +12,15 @@ class LocalSourceNode = DataFlowPublic::LocalSourceNode;
1112

1213
predicate simpleLocalFlowStep = DataFlowPrivate::simpleLocalFlowStep/2;
1314

14-
predicate jumpStep = DataFlowPrivate::jumpStep/2;
15+
predicate jumpStep(Node nodeFrom, Node nodeTo) {
16+
DataFlowPrivate::jumpStep(nodeFrom, nodeTo)
17+
or
18+
SsaImpl::captureFlowIn(nodeFrom.(DataFlowPrivate::SsaDefinitionNode).getDefinition(),
19+
nodeTo.(DataFlowPrivate::SsaDefinitionNode).getDefinition())
20+
or
21+
SsaImpl::captureFlowOut(nodeFrom.(DataFlowPrivate::SsaDefinitionNode).getDefinition(),
22+
nodeTo.(DataFlowPrivate::SsaDefinitionNode).getDefinition())
23+
}
1524

1625
/**
1726
* Gets the name of a possible piece of content. This will usually include things like

0 commit comments

Comments
 (0)