Skip to content

Commit d912383

Browse files
committed
JS: Avoid misoptimization in mayReturnImplicitValue
1 parent eddbdff commit d912383

2 files changed

Lines changed: 20 additions & 8 deletions

File tree

javascript/ql/src/semmle/javascript/CFG.qll

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,11 +299,21 @@ class ControlFlowNode extends @cfg_node, Locatable, NodeInStmtContainer {
299299
*/
300300
predicate isStart() { this = any(StmtContainer sc).getStart() }
301301

302+
/**
303+
* Holds if this is a final node of the given container, that is, a CFG node where execution
304+
* of that toplevel or function terminates.
305+
*/
306+
predicate isAFinalNodeOfContainer(StmtContainer container) {
307+
getASuccessor().(SyntheticControlFlowNode).isAFinalNodeOfContainer(container)
308+
}
309+
302310
/**
303311
* Holds if this is a final node, that is, a CFG node where execution of a
304312
* toplevel or function terminates.
305313
*/
306-
predicate isAFinalNode() { getASuccessor().(SyntheticControlFlowNode).isAFinalNode() }
314+
final predicate isAFinalNode() {
315+
isAFinalNodeOfContainer(_)
316+
}
307317

308318
/**
309319
* Holds if this node is unreachable, that is, it has no predecessors in the CFG.
@@ -361,7 +371,7 @@ class ControlFlowEntryNode extends SyntheticControlFlowNode, @entry_node {
361371

362372
/** A synthetic CFG node marking the exit of a function or toplevel script. */
363373
class ControlFlowExitNode extends SyntheticControlFlowNode, @exit_node {
364-
override predicate isAFinalNode() { any() }
374+
override predicate isAFinalNodeOfContainer(StmtContainer container) { exit_cfg_node(this, container) }
365375

366376
override string toString() { result = "exit node of " + getContainer().toString() }
367377
}

javascript/ql/src/semmle/javascript/dataflow/TypeInference.qll

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -256,15 +256,17 @@ class AnalyzedFunction extends DataFlow::AnalyzedValueNode {
256256
* account for `finally` blocks and does not check reachability.
257257
*/
258258
private predicate mayReturnImplicitly() {
259-
exists(ConcreteControlFlowNode final |
260-
final.getContainer() = astNode and
261-
final.isAFinalNode() and
262-
not final instanceof ReturnStmt and
263-
not final instanceof ThrowStmt
264-
)
259+
terminalNode(astNode, any(ExprOrStmt st))
265260
}
266261
}
267262

263+
pragma[noinline]
264+
private predicate terminalNode(Function f, ControlFlowNode final) {
265+
final.isAFinalNodeOfContainer(f) and
266+
not final instanceof ReturnStmt and
267+
not final instanceof ThrowStmt
268+
}
269+
268270
/**
269271
* Flow analysis for generator functions.
270272
*/

0 commit comments

Comments
 (0)