@@ -5,6 +5,8 @@ private import DataFlowDispatch
55private import DataFlowImplConsistency
66private import semmle.code.cpp.ir.internal.IRCppLanguage
77private import SsaInternals as Ssa
8+ private import DataFlowImplCommon
9+ private import semmle.code.cpp.ir.ValueNumbering
810
911cached
1012private module Cached {
@@ -890,11 +892,81 @@ private class MyConsistencyConfiguration extends Consistency::ConsistencyConfigu
890892 }
891893}
892894
895+ /**
896+ * Gets the basic block of `node`.
897+ */
898+ IRBlock getBasicBlock(Node node) {
899+ node.asInstruction().getBlock() = result
900+ or
901+ node.asOperand().getUse().getBlock() = result
902+ or
903+ node.(SsaPhiNode).getPhiNode().getBasicBlock() = result
904+ or
905+ node.(RawIndirectOperand).getOperand().getUse().getBlock() = result
906+ or
907+ node.(RawIndirectInstruction).getInstruction().getBlock() = result
908+ or
909+ result = getBasicBlock(node.(PostUpdateNode).getPreUpdateNode())
910+ }
911+
893912/**
894913 * Gets an additional term that is added to the `join` and `branch` computations to reflect
895914 * an additional forward or backwards branching factor that is not taken into account
896915 * when calculating the (virtual) dispatch cost.
897916 *
898917 * Argument `arg` is part of a path from a source to a sink, and `p` is the target parameter.
899918 */
900- int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) { none() }
919+ pragma[nomagic]
920+ int getAdditionalFlowIntoCallNodeTerm(ArgumentNode arg, ParameterNode p) {
921+ exists(ParameterNode switchee, SwitchInstruction switch, ConditionOperand op, DataFlowCall call |
922+ viableParamArg(call, p, arg) and
923+ viableParamArg(call, switchee, _) and
924+ switch.getExpressionOperand() = op and
925+ valueNumber(switchee.asInstruction()).getAUse() = op and
926+ result = countNumberOfBranchesUsingParameter(switch, p)
927+ )
928+ }
929+
930+ /** Gets the `IRVariable` associated with the parameter node `p`. */
931+ pragma[nomagic]
932+ private IRVariable getIRVariableForParameterNode(ParameterNode p) {
933+ result = p.(DirectParameterNode).getIRVariable()
934+ or
935+ result.getAst() = p.(IndirectParameterNode).getParameter()
936+ }
937+
938+ /** Holds if `v` is the source variable corresponding to the parameter represented by `p`. */
939+ pragma[nomagic]
940+ private predicate parameterNodeHasSourceVariable(ParameterNode p, Ssa::SourceIRVariable v) {
941+ v.getIRVariable() = getIRVariableForParameterNode(p) and
942+ exists(Position pos | p.isParameterOf(_, pos) |
943+ pos instanceof DirectPosition and
944+ v.getIndirection() = 1
945+ or
946+ pos.(IndirectionPosition).getIndirectionIndex() + 1 = v.getIndirection()
947+ )
948+ }
949+
950+ private EdgeKind caseOrDefaultEdge() {
951+ result instanceof CaseEdge or
952+ result instanceof DefaultEdge
953+ }
954+
955+ /**
956+ * Gets the number of switch branches that that read from (or write to) the parameter `p`.
957+ */
958+ int countNumberOfBranchesUsingParameter(SwitchInstruction switch, ParameterNode p) {
959+ exists(Ssa::SourceVariable sv |
960+ parameterNodeHasSourceVariable(p, sv) and
961+ // Count the number of cases that use the parameter. We do this by finding the phi node
962+ // that merges the uses/defs of the parameter. There might be multiple such phi nodes, so
963+ // we pick the one with the highest edge count.
964+ result =
965+ max(SsaPhiNode phi |
966+ switch.getSuccessor(caseOrDefaultEdge()).getBlock().dominanceFrontier() = getBasicBlock(phi) and
967+ phi.getSourceVariable() = sv
968+ |
969+ strictcount(phi.getAnInput())
970+ )
971+ )
972+ }
0 commit comments