Skip to content

Commit a68b55b

Browse files
authored
Merge pull request #7208 from hvitved/ruby/restrict-use-use
Ruby: Restrict use-use flow
2 parents 245edd4 + da39f15 commit a68b55b

File tree

1 file changed

+72
-65
lines changed

1 file changed

+72
-65
lines changed

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

Lines changed: 72 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -64,37 +64,37 @@ module LocalFlow {
6464
)
6565
}
6666

67+
/**
68+
* Holds if there is a local use-use flow step from `nodeFrom` to `nodeTo`
69+
* involving SSA definition `def`.
70+
*/
71+
predicate localSsaFlowStepUseUse(Ssa::Definition def, Node nodeFrom, Node nodeTo) {
72+
def.hasAdjacentReads(nodeFrom.asExpr(), nodeTo.asExpr())
73+
}
74+
6775
/**
6876
* Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
6977
* SSA definition `def`.
7078
*/
71-
predicate localSsaFlowStep(Ssa::Definition def, Node nodeFrom, Node nodeTo) {
72-
// Flow from assignment into SSA definition
73-
def.(Ssa::WriteDefinition).assigns(nodeFrom.asExpr()) and
74-
nodeTo.(SsaDefinitionNode).getDefinition() = def
75-
or
76-
// Flow from SSA definition to first read
77-
def = nodeFrom.(SsaDefinitionNode).getDefinition() and
78-
nodeTo.asExpr() = def.getAFirstRead()
79-
or
80-
// Flow from read to next read
81-
exists(
82-
CfgNodes::ExprNodes::VariableReadAccessCfgNode read1,
83-
CfgNodes::ExprNodes::VariableReadAccessCfgNode read2
84-
|
85-
def.hasAdjacentReads(read1, read2) and
86-
nodeTo.asExpr() = read2
87-
|
88-
nodeFrom.asExpr() = read1
79+
private predicate localSsaFlowStep(Node nodeFrom, Node nodeTo) {
80+
exists(Ssa::Definition def |
81+
// Flow from assignment into SSA definition
82+
def.(Ssa::WriteDefinition).assigns(nodeFrom.asExpr()) and
83+
nodeTo.(SsaDefinitionNode).getDefinition() = def
8984
or
90-
read1 = nodeFrom.(PostUpdateNode).getPreUpdateNode().asExpr()
91-
)
92-
or
93-
// Flow into phi node
94-
exists(Ssa::PhiNode phi |
95-
localFlowSsaInput(nodeFrom, def, phi) and
96-
phi = nodeTo.(SsaDefinitionNode).getDefinition() and
97-
def = phi.getAnInput()
85+
// Flow from SSA definition to first read
86+
def = nodeFrom.(SsaDefinitionNode).getDefinition() and
87+
nodeTo.asExpr() = def.getAFirstRead()
88+
or
89+
// Flow from read to next read
90+
localSsaFlowStepUseUse(def, nodeFrom.(PostUpdateNode).getPreUpdateNode(), nodeTo)
91+
or
92+
// Flow into phi node
93+
exists(Ssa::PhiNode phi |
94+
localFlowSsaInput(nodeFrom, def, phi) and
95+
phi = nodeTo.(SsaDefinitionNode).getDefinition() and
96+
def = phi.getAnInput()
97+
)
9898
)
9999
// TODO
100100
// or
@@ -105,6 +105,42 @@ module LocalFlow {
105105
// def = uncertain.getPriorDefinition()
106106
// )
107107
}
108+
109+
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
110+
localSsaFlowStep(nodeFrom, nodeTo)
111+
or
112+
nodeFrom.(SelfParameterNode).getMethod() = nodeTo.asExpr().getExpr().getEnclosingCallable() and
113+
nodeTo.asExpr().getExpr() instanceof Self
114+
or
115+
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::AssignExprCfgNode).getRhs()
116+
or
117+
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::BlockArgumentCfgNode).getValue()
118+
or
119+
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::StmtSequenceCfgNode).getLastStmt()
120+
or
121+
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::ConditionalExprCfgNode).getBranch(_)
122+
or
123+
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::CaseExprCfgNode).getBranch(_)
124+
or
125+
exists(CfgNodes::ExprCfgNode exprTo, ReturningStatementNode n |
126+
nodeFrom = n and
127+
exprTo = nodeTo.asExpr() and
128+
n.getReturningNode().getNode() instanceof BreakStmt and
129+
exprTo.getNode() instanceof Loop and
130+
nodeTo.asExpr().getAPredecessor(any(SuccessorTypes::BreakSuccessor s)) = n.getReturningNode()
131+
)
132+
or
133+
nodeFrom.asExpr() = nodeTo.(ReturningStatementNode).getReturningNode().getReturnedValueNode()
134+
or
135+
nodeTo.asExpr() =
136+
any(CfgNodes::ExprNodes::ForExprCfgNode for |
137+
exists(SuccessorType s |
138+
not s instanceof SuccessorTypes::BreakSuccessor and
139+
exists(for.getAPredecessor(s))
140+
) and
141+
nodeFrom.asExpr() = for.getValue()
142+
)
143+
}
108144
}
109145

110146
/** An argument of a call (including qualifier arguments, excluding block arguments). */
@@ -160,68 +196,37 @@ private module Cached {
160196
p.(KeywordParameter).getDefaultValue() = e.getExprNode().getExpr()
161197
}
162198

163-
private predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
164-
LocalFlow::localSsaFlowStep(_, nodeFrom, nodeTo)
165-
or
166-
nodeFrom.(SelfParameterNode).getMethod() = nodeTo.asExpr().getExpr().getEnclosingCallable() and
167-
nodeTo.asExpr().getExpr() instanceof Self
168-
or
169-
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::AssignExprCfgNode).getRhs()
170-
or
171-
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::BlockArgumentCfgNode).getValue()
172-
or
173-
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::StmtSequenceCfgNode).getLastStmt()
174-
or
175-
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::ConditionalExprCfgNode).getBranch(_)
176-
or
177-
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::CaseExprCfgNode).getBranch(_)
178-
or
179-
exists(CfgNodes::ExprCfgNode exprTo, ReturningStatementNode n |
180-
nodeFrom = n and
181-
exprTo = nodeTo.asExpr() and
182-
n.getReturningNode().getNode() instanceof BreakStmt and
183-
exprTo.getNode() instanceof Loop and
184-
nodeTo.asExpr().getAPredecessor(any(SuccessorTypes::BreakSuccessor s)) = n.getReturningNode()
185-
)
186-
or
187-
nodeFrom.asExpr() = nodeTo.(ReturningStatementNode).getReturningNode().getReturnedValueNode()
188-
or
189-
nodeTo.asExpr() =
190-
any(CfgNodes::ExprNodes::ForExprCfgNode for |
191-
exists(SuccessorType s |
192-
not s instanceof SuccessorTypes::BreakSuccessor and
193-
exists(for.getAPredecessor(s))
194-
) and
195-
nodeFrom.asExpr() = for.getValue()
196-
)
197-
}
198-
199199
/**
200200
* This is the local flow predicate that is used as a building block in global
201201
* data flow.
202202
*/
203203
cached
204204
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
205-
localFlowStepCommon(nodeFrom, nodeTo)
205+
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
206206
or
207207
defaultValueFlow(nodeTo.(ParameterNode).getParameter(), nodeFrom)
208208
or
209209
nodeTo = LocalFlow::getParameterDefNode(nodeFrom.(ParameterNode).getParameter())
210210
or
211211
nodeTo.(SynthReturnNode).getAnInput() = nodeFrom
212212
or
213+
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo) and
214+
not FlowSummaryImpl::Private::Steps::summaryClearsContentArg(nodeFrom, _)
215+
or
213216
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, true)
214217
}
215218

216219
/** This is the local flow predicate that is exposed. */
217220
cached
218221
predicate localFlowStepImpl(Node nodeFrom, Node nodeTo) {
219-
localFlowStepCommon(nodeFrom, nodeTo)
222+
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
220223
or
221224
defaultValueFlow(nodeTo.(ParameterNode).getParameter(), nodeFrom)
222225
or
223226
nodeTo = LocalFlow::getParameterDefNode(nodeFrom.(ParameterNode).getParameter())
224227
or
228+
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
229+
or
225230
// Simple flow through library code is included in the exposed local
226231
// step relation, even though flow is technically inter-procedural
227232
FlowSummaryImpl::Private::Steps::summaryThroughStep(nodeFrom, nodeTo, true)
@@ -230,12 +235,14 @@ private module Cached {
230235
/** This is the local flow predicate that is used in type tracking. */
231236
cached
232237
predicate localFlowStepTypeTracker(Node nodeFrom, Node nodeTo) {
233-
localFlowStepCommon(nodeFrom, nodeTo)
238+
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
234239
or
235240
exists(NamedParameter p |
236241
defaultValueFlow(p, nodeFrom) and
237242
nodeTo = LocalFlow::getParameterDefNode(p)
238243
)
244+
or
245+
LocalFlow::localSsaFlowStepUseUse(_, nodeFrom, nodeTo)
239246
}
240247

241248
cached

0 commit comments

Comments
 (0)