@@ -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