Skip to content

Commit 33b7ba4

Browse files
authored
Merge pull request github#17535 from asgerf/jss/use-use-flow
JS: Follow use-use flow after a post-update
2 parents 443987b + 80ee372 commit 33b7ba4

File tree

38 files changed

+1214
-622
lines changed

38 files changed

+1214
-622
lines changed

javascript/ql/lib/qlpack.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ dependencies:
99
codeql/dataflow: ${workspace}
1010
codeql/mad: ${workspace}
1111
codeql/regex: ${workspace}
12+
codeql/ssa: ${workspace}
1213
codeql/tutorial: ${workspace}
1314
codeql/util: ${workspace}
1415
codeql/xml: ${workspace}

javascript/ql/lib/semmle/javascript/BasicBlocks.qll

Lines changed: 1 addition & 353 deletions
Original file line numberDiff line numberDiff line change
@@ -3,356 +3,4 @@
33
* liveness information for local variables.
44
*/
55

6-
import javascript
7-
private import internal.StmtContainers
8-
private import semmle.javascript.internal.CachedStages
9-
10-
/**
11-
* Holds if `nd` starts a new basic block.
12-
*/
13-
private predicate startsBB(ControlFlowNode nd) {
14-
not exists(nd.getAPredecessor()) and exists(nd.getASuccessor())
15-
or
16-
nd.isJoin()
17-
or
18-
nd.getAPredecessor().isBranch()
19-
}
20-
21-
/**
22-
* Holds if the first node of basic block `succ` is a control flow
23-
* successor of the last node of basic block `bb`.
24-
*/
25-
private predicate succBB(BasicBlock bb, BasicBlock succ) { succ = bb.getLastNode().getASuccessor() }
26-
27-
/**
28-
* Holds if the first node of basic block `bb` is a control flow
29-
* successor of the last node of basic block `pre`.
30-
*/
31-
private predicate predBB(BasicBlock bb, BasicBlock pre) { succBB(pre, bb) }
32-
33-
/** Holds if `bb` is an entry basic block. */
34-
private predicate entryBB(BasicBlock bb) { bb.getFirstNode() instanceof ControlFlowEntryNode }
35-
36-
/** Holds if `bb` is an exit basic block. */
37-
private predicate exitBB(BasicBlock bb) { bb.getLastNode() instanceof ControlFlowExitNode }
38-
39-
cached
40-
private module Internal {
41-
/**
42-
* Holds if `succ` is a control flow successor of `nd` within the same basic block.
43-
*/
44-
private predicate intraBBSucc(ControlFlowNode nd, ControlFlowNode succ) {
45-
succ = nd.getASuccessor() and
46-
not succ instanceof BasicBlock
47-
}
48-
49-
/**
50-
* Holds if `nd` is the `i`th node in basic block `bb`.
51-
*
52-
* In other words, `i` is the shortest distance from a node `bb`
53-
* that starts a basic block to `nd` along the `intraBBSucc` relation.
54-
*/
55-
cached
56-
predicate bbIndex(BasicBlock bb, ControlFlowNode nd, int i) =
57-
shortestDistances(startsBB/1, intraBBSucc/2)(bb, nd, i)
58-
59-
cached
60-
int bbLength(BasicBlock bb) { result = strictcount(ControlFlowNode nd | bbIndex(bb, nd, _)) }
61-
62-
cached
63-
predicate useAt(BasicBlock bb, int i, Variable v, VarUse u) {
64-
Stages::BasicBlocks::ref() and
65-
v = u.getVariable() and
66-
bbIndex(bb, u, i)
67-
}
68-
69-
cached
70-
predicate defAt(BasicBlock bb, int i, Variable v, VarDef d) {
71-
exists(VarRef lhs |
72-
lhs = d.getTarget().(BindingPattern).getABindingVarRef() and
73-
v = lhs.getVariable()
74-
|
75-
lhs = d.getTarget() and
76-
bbIndex(bb, d, i)
77-
or
78-
exists(PropertyPattern pp |
79-
lhs = pp.getValuePattern() and
80-
bbIndex(bb, pp, i)
81-
)
82-
or
83-
exists(ObjectPattern op |
84-
lhs = op.getRest() and
85-
bbIndex(bb, lhs, i)
86-
)
87-
or
88-
exists(ArrayPattern ap |
89-
lhs = ap.getAnElement() and
90-
bbIndex(bb, lhs, i)
91-
)
92-
)
93-
}
94-
95-
cached
96-
predicate reachableBB(BasicBlock bb) {
97-
entryBB(bb)
98-
or
99-
exists(BasicBlock predBB | succBB(predBB, bb) | reachableBB(predBB))
100-
}
101-
}
102-
103-
private import Internal
104-
105-
/** Holds if `dom` is an immediate dominator of `bb`. */
106-
cached
107-
private predicate bbIDominates(BasicBlock dom, BasicBlock bb) =
108-
idominance(entryBB/1, succBB/2)(_, dom, bb)
109-
110-
/** Holds if `dom` is an immediate post-dominator of `bb`. */
111-
cached
112-
private predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) =
113-
idominance(exitBB/1, predBB/2)(_, dom, bb)
114-
115-
/**
116-
* A basic block, that is, a maximal straight-line sequence of control flow nodes
117-
* without branches or joins.
118-
*
119-
* At the database level, a basic block is represented by its first control flow node.
120-
*/
121-
class BasicBlock extends @cfg_node, NodeInStmtContainer {
122-
cached
123-
BasicBlock() { Stages::BasicBlocks::ref() and startsBB(this) }
124-
125-
/** Gets a basic block succeeding this one. */
126-
BasicBlock getASuccessor() { succBB(this, result) }
127-
128-
/** Gets a basic block preceding this one. */
129-
BasicBlock getAPredecessor() { result.getASuccessor() = this }
130-
131-
/** Gets a node in this block. */
132-
ControlFlowNode getANode() { result = this.getNode(_) }
133-
134-
/** Gets the node at the given position in this block. */
135-
ControlFlowNode getNode(int pos) { bbIndex(this, result, pos) }
136-
137-
/** Gets the first node in this block. */
138-
ControlFlowNode getFirstNode() { result = this }
139-
140-
/** Gets the last node in this block. */
141-
ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) }
142-
143-
/** Gets the length of this block. */
144-
int length() { result = bbLength(this) }
145-
146-
/** Holds if this basic block uses variable `v` in its `i`th node `u`. */
147-
predicate useAt(int i, Variable v, VarUse u) { useAt(this, i, v, u) }
148-
149-
/** Holds if this basic block defines variable `v` in its `i`th node `d`. */
150-
predicate defAt(int i, Variable v, VarDef d) { defAt(this, i, v, d) }
151-
152-
/**
153-
* Holds if `v` is live at entry to this basic block and `u` is a use of `v`
154-
* witnessing the liveness.
155-
*
156-
* In other words, `u` is a use of `v` that is reachable from the
157-
* entry node of this basic block without going through a redefinition
158-
* of `v`. The use `u` may either be in this basic block, or in another
159-
* basic block reachable from this one.
160-
*/
161-
predicate isLiveAtEntry(Variable v, VarUse u) {
162-
// restrict `u` to be reachable from this basic block
163-
u = this.getASuccessor*().getANode() and
164-
(
165-
// shortcut: if `v` is never defined, then it must be live
166-
this.isDefinedInSameContainer(v)
167-
implies
168-
// otherwise, do full liveness computation
169-
this.isLiveAtEntryImpl(v, u)
170-
)
171-
}
172-
173-
/**
174-
* Holds if `v` is live at entry to this basic block and `u` is a use of `v`
175-
* witnessing the liveness, where `v` is defined at least once in the enclosing
176-
* function or script.
177-
*/
178-
private predicate isLiveAtEntryImpl(Variable v, VarUse u) {
179-
this.isLocallyLiveAtEntry(v, u)
180-
or
181-
this.isDefinedInSameContainer(v) and
182-
not this.defAt(_, v, _) and
183-
this.getASuccessor().isLiveAtEntryImpl(v, u)
184-
}
185-
186-
/**
187-
* Holds if `v` is defined at least once in the function or script to which
188-
* this basic block belongs.
189-
*/
190-
private predicate isDefinedInSameContainer(Variable v) {
191-
exists(VarDef def | def.getAVariable() = v and def.getContainer() = this.getContainer())
192-
}
193-
194-
/**
195-
* Holds if `v` is a variable that is live at entry to this basic block.
196-
*
197-
* Note that this is equivalent to `bb.isLiveAtEntry(v, _)`, but may
198-
* be more efficient on large databases.
199-
*/
200-
predicate isLiveAtEntry(Variable v) {
201-
this.isLocallyLiveAtEntry(v, _)
202-
or
203-
not this.defAt(_, v, _) and this.getASuccessor().isLiveAtEntry(v)
204-
}
205-
206-
/**
207-
* Holds if local variable `v` is live at entry to this basic block and
208-
* `u` is a use of `v` witnessing the liveness.
209-
*/
210-
predicate localIsLiveAtEntry(LocalVariable v, VarUse u) {
211-
this.isLocallyLiveAtEntry(v, u)
212-
or
213-
not this.defAt(_, v, _) and this.getASuccessor().localIsLiveAtEntry(v, u)
214-
}
215-
216-
/**
217-
* Holds if local variable `v` is live at entry to this basic block.
218-
*/
219-
predicate localIsLiveAtEntry(LocalVariable v) {
220-
this.isLocallyLiveAtEntry(v, _)
221-
or
222-
not this.defAt(_, v, _) and this.getASuccessor().localIsLiveAtEntry(v)
223-
}
224-
225-
/**
226-
* Holds if `d` is a definition of `v` that is reachable from the beginning of
227-
* this basic block without going through a redefinition of `v`.
228-
*/
229-
predicate localMayBeOverwritten(LocalVariable v, VarDef d) {
230-
this.isLocallyOverwritten(v, d)
231-
or
232-
not this.defAt(_, v, _) and this.getASuccessor().localMayBeOverwritten(v, d)
233-
}
234-
235-
/**
236-
* Gets the next index after `i` in this basic block at which `v` is
237-
* defined or used, provided that `d` is a definition of `v` at index `i`.
238-
* If there are no further uses or definitions of `v` after `i`, the
239-
* result is the length of this basic block.
240-
*/
241-
private int nextDefOrUseAfter(PurelyLocalVariable v, int i, VarDef d) {
242-
this.defAt(i, v, d) and
243-
result =
244-
min(int j |
245-
(this.defAt(j, v, _) or this.useAt(j, v, _) or j = this.length()) and
246-
j > i
247-
)
248-
}
249-
250-
/**
251-
* Holds if `d` defines variable `v` at the `i`th node of this basic block, and
252-
* the definition is live, that is, the variable may be read after this
253-
* definition and before a re-definition.
254-
*/
255-
predicate localLiveDefAt(PurelyLocalVariable v, int i, VarDef d) {
256-
exists(int j | j = this.nextDefOrUseAfter(v, i, d) |
257-
this.useAt(j, v, _)
258-
or
259-
j = this.length() and this.getASuccessor().localIsLiveAtEntry(v)
260-
)
261-
}
262-
263-
/**
264-
* Holds if `u` is a use of `v` in this basic block, and there are
265-
* no definitions of `v` before it.
266-
*/
267-
private predicate isLocallyLiveAtEntry(Variable v, VarUse u) {
268-
exists(int n | this.useAt(n, v, u) | not exists(int m | m < n | this.defAt(m, v, _)))
269-
}
270-
271-
/**
272-
* Holds if `d` is a definition of `v` in this basic block, and there are
273-
* no other definitions of `v` before it.
274-
*/
275-
private predicate isLocallyOverwritten(Variable v, VarDef d) {
276-
exists(int n | this.defAt(n, v, d) | not exists(int m | m < n | this.defAt(m, v, _)))
277-
}
278-
279-
/**
280-
* Gets the basic block that immediately dominates this basic block.
281-
*/
282-
ReachableBasicBlock getImmediateDominator() { bbIDominates(result, this) }
283-
}
284-
285-
/**
286-
* An unreachable basic block, that is, a basic block
287-
* whose first node is unreachable.
288-
*/
289-
class UnreachableBlock extends BasicBlock {
290-
UnreachableBlock() { this.getFirstNode().isUnreachable() }
291-
}
292-
293-
/**
294-
* An entry basic block, that is, a basic block
295-
* whose first node is the entry node of a statement container.
296-
*/
297-
class EntryBasicBlock extends BasicBlock {
298-
EntryBasicBlock() { entryBB(this) }
299-
}
300-
301-
/**
302-
* A basic block that is reachable from an entry basic block.
303-
*/
304-
class ReachableBasicBlock extends BasicBlock {
305-
ReachableBasicBlock() { reachableBB(this) }
306-
307-
/**
308-
* Holds if this basic block strictly dominates `bb`.
309-
*/
310-
pragma[inline]
311-
predicate strictlyDominates(ReachableBasicBlock bb) { bbIDominates+(this, bb) }
312-
313-
/**
314-
* Holds if this basic block dominates `bb`.
315-
*
316-
* This predicate is reflexive: each reachable basic block dominates itself.
317-
*/
318-
pragma[inline]
319-
predicate dominates(ReachableBasicBlock bb) { bbIDominates*(this, bb) }
320-
321-
/**
322-
* Holds if this basic block strictly post-dominates `bb`.
323-
*/
324-
pragma[inline]
325-
predicate strictlyPostDominates(ReachableBasicBlock bb) { bbIPostDominates+(this, bb) }
326-
327-
/**
328-
* Holds if this basic block post-dominates `bb`.
329-
*
330-
* This predicate is reflexive: each reachable basic block post-dominates itself.
331-
*/
332-
pragma[inline]
333-
predicate postDominates(ReachableBasicBlock bb) { bbIPostDominates*(this, bb) }
334-
}
335-
336-
/**
337-
* A reachable basic block with more than one predecessor.
338-
*/
339-
class ReachableJoinBlock extends ReachableBasicBlock {
340-
ReachableJoinBlock() { this.getFirstNode().isJoin() }
341-
342-
/**
343-
* Holds if this basic block belongs to the dominance frontier of `b`, that is
344-
* `b` dominates a predecessor of this block, but not this block itself.
345-
*
346-
* Algorithm from Cooper et al., "A Simple, Fast Dominance Algorithm" (Figure 5),
347-
* who in turn attribute it to Ferrante et al., "The program dependence graph and
348-
* its use in optimization".
349-
*/
350-
predicate inDominanceFrontierOf(ReachableBasicBlock b) {
351-
b = this.getAPredecessor() and not b = this.getImmediateDominator()
352-
or
353-
exists(ReachableBasicBlock prev | this.inDominanceFrontierOf(prev) |
354-
b = prev.getImmediateDominator() and
355-
not b = this.getImmediateDominator()
356-
)
357-
}
358-
}
6+
import internal.BasicBlockInternal::Public

0 commit comments

Comments
 (0)