From 6ff35a31f2fe9fd0169f0e161a0fbc74d6196b95 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 3 Oct 2024 22:17:44 +0100 Subject: [PATCH] Further join order optimisations --- go/ql/lib/semmle/go/Expr.qll | 1 + go/ql/lib/semmle/go/controlflow/IR.qll | 2 +- .../semmle/go/dataflow/internal/DataFlowDispatch.qll | 4 ++-- .../lib/semmle/go/dataflow/internal/DataFlowNodes.qll | 1 + go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll | 8 +++++--- .../semmle/go/dataflow/internal/TaintTrackingUtil.qll | 10 +++++----- 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/go/ql/lib/semmle/go/Expr.qll b/go/ql/lib/semmle/go/Expr.qll index ce6c7d4cf1f6b..4a4ab00f0538a 100644 --- a/go/ql/lib/semmle/go/Expr.qll +++ b/go/ql/lib/semmle/go/Expr.qll @@ -2137,6 +2137,7 @@ private predicate isTypeExprBottomUp(Expr e) { * it may be the latter and so this predicate does not consider the expression to be * a type expression. */ +pragma[nomagic] private predicate isTypeExprTopDown(Expr e) { e = any(CompositeLit cl).getTypeExpr() or diff --git a/go/ql/lib/semmle/go/controlflow/IR.qll b/go/ql/lib/semmle/go/controlflow/IR.qll index 59060e4065583..b036ddf6d0f58 100644 --- a/go/ql/lib/semmle/go/controlflow/IR.qll +++ b/go/ql/lib/semmle/go/controlflow/IR.qll @@ -1481,7 +1481,7 @@ module IR { override predicate refersTo(ValueEntity e) { this instanceof MkLhs and - loc = e.getAReference() + pragma[only_bind_out](loc) = e.getAReference() or exists(WriteResultInstruction wr | this = MkResultWriteTarget(wr) | e = wr.getResultVariable() diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowDispatch.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowDispatch.qll index b045d6dc5522f..a06edad0be2c5 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowDispatch.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowDispatch.qll @@ -8,9 +8,9 @@ private import DataFlowPrivate private predicate isInterfaceCallReceiver( DataFlow::CallNode call, DataFlow::Node recv, InterfaceType tp, string m ) { - call.getReceiver() = recv and + pragma[only_bind_out](call).getReceiver() = recv and recv.getType().getUnderlyingType() = tp and - m = call.getACalleeIncludingExternals().asFunction().getName() + m = pragma[only_bind_out](call).getACalleeIncludingExternals().asFunction().getName() } /** Gets a data-flow node that may flow into the receiver value of `call`, which is an interface value. */ diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll index 6b088f44e73a2..0aa517b3fdadd 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll @@ -525,6 +525,7 @@ module Public { * As `getACalleeIncludingExternals`, except excluding external functions (those for which * we lack a definition, such as standard library functions). */ + pragma[nomagic] FuncDef getACallee() { result = this.getACalleeIncludingExternals().getFuncDef() } /** diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll index 9f76e7c7c95b3..75ab4dbb2ebd5 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowUtil.qll @@ -284,9 +284,11 @@ signature predicate guardChecksSig(Node g, Expr e, boolean branch); module BarrierGuard { /** Gets a node that is safely guarded by the given guard check. */ Node getABarrierNode() { - exists(ControlFlow::ConditionGuardNode guard, SsaWithFields var | result = var.getAUse() | + exists(ControlFlow::ConditionGuardNode guard, SsaWithFields var | + result = pragma[only_bind_out](var).getAUse() + | guards(_, guard, _, var) and - guard.dominates(result.getBasicBlock()) + pragma[only_bind_out](guard).dominates(result.getBasicBlock()) ) } @@ -353,7 +355,7 @@ module BarrierGuard { ) { exists(FuncDecl fd, Node arg, Node ret | fd.getFunction() = f and - localFlow(inp.getExitNode(fd), arg) and + localFlow(inp.getExitNode(fd), pragma[only_bind_out](arg)) and ret = outp.getEntryNode(fd) and ( // Case: a function like "if someBarrierGuard(arg) { return true } else { return false }" diff --git a/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll b/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll index 281e283890adb..85f6bb0874f50 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/TaintTrackingUtil.qll @@ -203,8 +203,8 @@ abstract class FunctionModel extends Function { predicate taintStepForCall(DataFlow::Node pred, DataFlow::Node succ, DataFlow::CallNode c) { c = this.getACall() and exists(FunctionInput inp, FunctionOutput outp | this.hasTaintFlow(inp, outp) | - pred = inp.getNode(c) and - succ = outp.getNode(c) + pred = pragma[only_bind_out](inp).getNode(c) and + succ = pragma[only_bind_out](outp).getNode(c) ) } @@ -383,9 +383,9 @@ predicate inputIsConstantIfOutputHasProperty( ) { exists(Function f, FunctionInput inp, FunctionOutput outp, DataFlow::CallNode call | functionEnsuresInputIsConstant(f, inp, outp, p) and - call = f.getACall() and - inputNode = inp.getNode(call) and - DataFlow::localFlow(outp.getNode(call), outputNode) + call = pragma[only_bind_out](f).getACall() and + inputNode = pragma[only_bind_out](inp).getNode(call) and + DataFlow::localFlow(pragma[only_bind_out](outp).getNode(call), outputNode) ) }