Skip to content

Commit 8e26fa1

Browse files
committed
Go: Avoid combinatorial explosion in mostRecentSideEffect when there are multiple entry points
1 parent c64223a commit 8e26fa1

1 file changed

Lines changed: 41 additions & 34 deletions

File tree

go/ql/lib/semmle/go/dataflow/GlobalValueNumbering.qll

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,11 @@ private predicate sideEffectCfg(ControlFlow::Node src, ControlFlow::Node dst) {
127127

128128
/**
129129
* Holds if `dominator` is the immediate dominator of `node` in
130-
* the side-effect CFG.
130+
* the side-effect CFG belonging to `entry`.
131131
*/
132-
private predicate iDomEffect(ControlFlow::Node dominator, ControlFlow::Node node) =
133-
idominance(entryNode/1, sideEffectCfg/2)(_, dominator, node)
132+
private predicate iDomEffect(
133+
ControlFlow::Node entry, ControlFlow::Node dominator, ControlFlow::Node node
134+
) = idominance(entryNode/1, sideEffectCfg/2)(entry, dominator, node)
134135

135136
/**
136137
* Gets the most recent side effect. To be more precise, `result` is a
@@ -181,15 +182,21 @@ private predicate iDomEffect(ControlFlow::Node dominator, ControlFlow::Node node
181182
* The immediate dominator path to line 015 is 000 - 009 - 012 - 015.
182183
* Therefore, the most recent side effect for line 015 is line 009.
183184
*/
184-
cached
185-
private ControlFlow::Node mostRecentSideEffect(ControlFlow::Node node) {
186-
exists(ControlFlow::Node entry |
187-
entryNode(entry) and
188-
iDomEffect(entry, result) and
189-
iDomEffect*(result, node)
185+
private ControlFlow::Node mostRecentSideEffect(ControlFlow::Node entry, ControlFlow::Node node) {
186+
iDomEffect(entry, entry, result) and
187+
result = node
188+
or
189+
exists(ControlFlow::Node mid |
190+
result = mostRecentSideEffect(entry, mid) and
191+
iDomEffect(entry, mid, node)
190192
)
191193
}
192194

195+
cached
196+
private ControlFlow::Node mostRecentSideEffectUnique(ControlFlow::Node node) {
197+
result = unique( | | mostRecentSideEffect(_, node))
198+
}
199+
193200
/** Used to represent the "global value number" of an expression. */
194201
cached
195202
private newtype GvnBase =
@@ -369,10 +376,12 @@ private predicate mkMethodAccess(DataFlow::Node access, GVN qualifier, Method m)
369376
)
370377
}
371378

372-
private predicate analyzableFieldRead(Read fread, DataFlow::Node base, Field f) {
379+
private predicate analyzableFieldRead(
380+
Read fread, DataFlow::Node base, Field f, ControlFlow::Node dominator
381+
) {
373382
exists(IR::ReadInstruction r | r = fread.asInstruction() |
374383
r.readsField(base.asInstruction(), f) and
375-
strictcount(mostRecentSideEffect(r)) = 1 and
384+
dominator = mostRecentSideEffectUnique(r) and
376385
not r.isConst()
377386
)
378387
}
@@ -381,9 +390,8 @@ private predicate mkFieldRead(
381390
DataFlow::Node fread, GVN qualifier, Field v, ControlFlow::Node dominator
382391
) {
383392
exists(DataFlow::Node base |
384-
analyzableFieldRead(fread, base, v) and
385-
qualifier = globalValueNumber(base) and
386-
dominator = mostRecentSideEffect(fread.asInstruction())
393+
analyzableFieldRead(fread, base, v, dominator) and
394+
qualifier = globalValueNumber(base)
387395
)
388396
}
389397

@@ -421,18 +429,17 @@ private predicate incompleteSsa(ValueEntity v) {
421429
/**
422430
* Holds if `access` is an access to a variable `target` for which SSA information is incomplete.
423431
*/
424-
private predicate analyzableOtherVariable(DataFlow::Node access, ValueEntity target) {
432+
private predicate analyzableOtherVariable(
433+
DataFlow::Node access, ValueEntity target, ControlFlow::Node dominator
434+
) {
425435
access.asInstruction().reads(target) and
426436
incompleteSsa(target) and
427-
strictcount(mostRecentSideEffect(access.asInstruction())) = 1 and
437+
dominator = mostRecentSideEffectUnique(access.asInstruction()) and
428438
not access.isConst() and
429439
not target instanceof Function
430440
}
431441

432-
private predicate mkOtherVariable(DataFlow::Node access, ValueEntity x, ControlFlow::Node dominator) {
433-
analyzableOtherVariable(access, x) and
434-
dominator = mostRecentSideEffect(access.asInstruction())
435-
}
442+
private predicate mkOtherVariable = analyzableOtherVariable/3;
436443

437444
private predicate analyzableBinaryOp(
438445
DataFlow::BinaryOperationNode op, string opname, DataFlow::Node lhs, DataFlow::Node rhs
@@ -463,29 +470,29 @@ private predicate mkUnaryOp(DataFlow::UnaryOperationNode op, GVN child, string o
463470
opname = op.getOperator()
464471
}
465472

466-
private predicate analyzableIndexExpr(DataFlow::ElementReadNode ae) {
467-
strictcount(mostRecentSideEffect(ae.asInstruction())) = 1 and
473+
private predicate analyzableIndexExpr(DataFlow::ElementReadNode ae, ControlFlow::Node dominator) {
474+
dominator = mostRecentSideEffectUnique(ae.asInstruction()) and
468475
not ae.isConst()
469476
}
470477

471478
private predicate mkIndex(
472479
DataFlow::ElementReadNode ae, GVN base, GVN offset, ControlFlow::Node dominator
473480
) {
474-
analyzableIndexExpr(ae) and
481+
analyzableIndexExpr(ae, dominator) and
475482
base = globalValueNumber(ae.getBase()) and
476-
offset = globalValueNumber(ae.getIndex()) and
477-
dominator = mostRecentSideEffect(ae.asInstruction())
483+
offset = globalValueNumber(ae.getIndex())
478484
}
479485

480-
private predicate analyzablePointerDereferenceExpr(DataFlow::PointerDereferenceNode deref) {
481-
strictcount(mostRecentSideEffect(deref.asInstruction())) = 1 and
486+
private predicate analyzablePointerDereferenceExpr(
487+
DataFlow::PointerDereferenceNode deref, ControlFlow::Node dominator
488+
) {
489+
dominator = mostRecentSideEffectUnique(deref.asInstruction()) and
482490
not deref.isConst()
483491
}
484492

485493
private predicate mkDeref(DataFlow::PointerDereferenceNode deref, GVN p, ControlFlow::Node dominator) {
486-
analyzablePointerDereferenceExpr(deref) and
487-
p = globalValueNumber(deref.getOperand()) and
488-
dominator = mostRecentSideEffect(deref.asInstruction())
494+
analyzablePointerDereferenceExpr(deref, dominator) and
495+
p = globalValueNumber(deref.getOperand())
489496
}
490497

491498
private predicate ssaInit(SsaExplicitDefinition ssa, DataFlow::Node rhs) {
@@ -587,12 +594,12 @@ private predicate analyzableExpr(DataFlow::Node e) {
587594
analyzableConst(e) or
588595
any(DataFlow::SsaNode ssa).getAUse() = e or
589596
e instanceof DataFlow::SsaNode or
590-
analyzableOtherVariable(e, _) or
597+
analyzableOtherVariable(e, _, _) or
591598
analyzableMethodAccess(e, _, _) or
592-
analyzableFieldRead(e, _, _) or
599+
analyzableFieldRead(e, _, _, _) or
593600
analyzableCall(e, _) or
594601
analyzableBinaryOp(e, _, _, _) or
595602
analyzableUnaryOp(e) or
596-
analyzableIndexExpr(e) or
597-
analyzablePointerDereferenceExpr(e)
603+
analyzableIndexExpr(e, _) or
604+
analyzablePointerDereferenceExpr(e, _)
598605
}

0 commit comments

Comments
 (0)