Skip to content

Commit 8f6721e

Browse files
committed
add explanation for purity-check in getANodeAfterWrite/getANodeBeforeWrite and move them into an internal module
1 parent 9e76837 commit 8f6721e

File tree

1 file changed

+54
-45
lines changed

1 file changed

+54
-45
lines changed

javascript/ql/src/Declarations/DeadStoreOfProperty.ql

Lines changed: 54 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -132,61 +132,70 @@ predicate maybeAssignsAccessedPropInBlock(DataFlow::PropWrite assign, boolean af
132132
or
133133
// impure expression that might access the property before/after assign
134134
exists(ReachableBasicBlock block | assign.getWriteNode().getBasicBlock() = block |
135-
after = true and isBeforeImpure(assign, block)
135+
after = true and PurityCheck::isBeforeImpure(assign, block)
136136
or
137-
after = false and isAfterImpure(assign, block)
137+
after = false and PurityCheck::isAfterImpure(assign, block)
138138
)
139139
)
140140
}
141141

142142
/**
143-
* Holds if a ControlFlowNode `c` is before an impure expression inside `bb`.
143+
* Predicates to check if a property-write comes after/before an impure expression within the same basicblock.
144144
*/
145-
predicate isBeforeImpure(DataFlow::PropWrite write, ReachableBasicBlock bb) {
146-
getANodeAfterWrite(write, bb).(Expr).isImpure()
147-
}
145+
private module PurityCheck {
146+
/**
147+
* Holds if a ControlFlowNode `c` is before an impure expression inside `bb`.
148+
*/
149+
predicate isBeforeImpure(DataFlow::PropWrite write, ReachableBasicBlock bb) {
150+
getANodeAfterWrite(write, bb).(Expr).isImpure()
151+
}
148152

149-
/**
150-
* Gets a ControlFlowNode that comes after `write` inside `bb`.
151-
* Stops after finding the first impure expression
152-
*/
153-
ControlFlowNode getANodeAfterWrite(DataFlow::PropWrite write, ReachableBasicBlock bb) {
154-
// base case
155-
result.getBasicBlock() = bb and
156-
postDominatedPropWrite(_, write, _, false) and // early pruning - manual magic
157-
result = write.getWriteNode().getASuccessor()
158-
or
159-
// recursive case
160-
exists(ControlFlowNode prev | prev = getANodeAfterWrite(write, bb) |
161-
not result instanceof BasicBlock and
162-
not prev.(Expr).isImpure() and
163-
result = prev.getASuccessor()
164-
)
165-
}
153+
/**
154+
* Gets a ControlFlowNode that comes after `write` inside `bb`.
155+
* Stops after finding the first impure expression.
156+
*
157+
* This predicate is used as a helper to check if one of the successors to `write` inside `bb` is impure (see `isBeforeImpure`).
158+
*/
159+
private ControlFlowNode getANodeAfterWrite(DataFlow::PropWrite write, ReachableBasicBlock bb) {
160+
// base case
161+
result.getBasicBlock() = bb and
162+
postDominatedPropWrite(_, write, _, false) and // early pruning - manual magic
163+
result = write.getWriteNode().getASuccessor()
164+
or
165+
// recursive case
166+
exists(ControlFlowNode prev | prev = getANodeAfterWrite(write, bb) |
167+
not result instanceof BasicBlock and
168+
not prev.(Expr).isImpure() and
169+
result = prev.getASuccessor()
170+
)
171+
}
166172

167-
/**
168-
* Holds if a ControlFlowNode `c` is after an impure expression inside `bb`.
169-
*/
170-
predicate isAfterImpure(DataFlow::PropWrite write, ReachableBasicBlock bb) {
171-
getANodeBeforeWrite(write, bb).(Expr).isImpure()
172-
}
173+
/**
174+
* Holds if a ControlFlowNode `c` is after an impure expression inside `bb`.
175+
*/
176+
predicate isAfterImpure(DataFlow::PropWrite write, ReachableBasicBlock bb) {
177+
getANodeBeforeWrite(write, bb).(Expr).isImpure()
178+
}
173179

174-
/**
175-
* Gets a ControlFlowNode that comes before `write` inside `bb`.
176-
* Stops after finding the first impure expression.
177-
*/
178-
ControlFlowNode getANodeBeforeWrite(DataFlow::PropWrite write, ReachableBasicBlock bb) {
179-
// base case
180-
result.getBasicBlock() = bb and
181-
postDominatedPropWrite(_, _, write, false) and // early pruning - manual magic
182-
result = write.getWriteNode().getAPredecessor()
183-
or
184-
// recursive case
185-
exists(ControlFlowNode prev | prev = getANodeBeforeWrite(write, bb) |
186-
not prev instanceof BasicBlock and
187-
not prev.(Expr).isImpure() and
188-
result = prev.getAPredecessor()
189-
)
180+
/**
181+
* Gets a ControlFlowNode that comes before `write` inside `bb`.
182+
* Stops after finding the first impure expression.
183+
*
184+
* This predicate is used as a helper to check if one of the predecessors to `write` inside `bb` is impure (see `isAfterImpure`).
185+
*/
186+
private ControlFlowNode getANodeBeforeWrite(DataFlow::PropWrite write, ReachableBasicBlock bb) {
187+
// base case
188+
result.getBasicBlock() = bb and
189+
postDominatedPropWrite(_, _, write, false) and // early pruning - manual magic
190+
result = write.getWriteNode().getAPredecessor()
191+
or
192+
// recursive case
193+
exists(ControlFlowNode prev | prev = getANodeBeforeWrite(write, bb) |
194+
not prev instanceof BasicBlock and
195+
not prev.(Expr).isImpure() and
196+
result = prev.getAPredecessor()
197+
)
198+
}
190199
}
191200

192201
/**

0 commit comments

Comments
 (0)