@@ -7,6 +7,7 @@ private import codeql.ssa.Ssa as SsaImplCommon
77private import AssignableDefinitions
88private import semmle.code.csharp.controlflow.Guards as Guards
99private import semmle.code.csharp.dataflow.internal.BaseSSA
10+ private import semmle.code.csharp.internal.Location
1011
1112private module SsaInput implements SsaImplCommon:: InputSig< Location , BasicBlock > {
1213 class SourceVariable = Ssa:: SourceVariable ;
@@ -126,7 +127,6 @@ private module SourceVariableImpl {
126127 */
127128 predicate variableDefinition ( BasicBlock bb , int i , Ssa:: SourceVariable v , AssignableDefinition ad ) {
128129 ad = v .getADefinition ( ) and
129- ad .getExpr ( ) .getControlFlowNode ( ) = bb .getNode ( i ) and
130130 // In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
131131 not exists ( TupleAssignmentDefinition first , TupleAssignmentDefinition second | first = ad |
132132 second .getAssignment ( ) = first .getAssignment ( ) and
@@ -136,7 +136,13 @@ private module SourceVariableImpl {
136136 // In cases like `M(out x, out x)`, there is no inherent evaluation order, so we
137137 // collapse the two definitions of `x`, using the first access as the representative,
138138 // and expose both definitions in `ExplicitDefinition.getADefinition()`
139- not ad = getASameOutRefDefAfter ( v , _)
139+ not ad = getASameOutRefDefAfter ( v , _) and
140+ (
141+ ad .getExpr ( ) .getControlFlowNode ( ) = bb .getNode ( i )
142+ or
143+ ad .( AssignableDefinitions:: ImplicitParameterDefinition ) .getParameter ( ) .getControlFlowNode ( ) =
144+ bb .getNode ( i )
145+ )
140146 }
141147
142148 /**
@@ -243,6 +249,15 @@ private module SourceVariableImpl {
243249private import SourceVariableImpl
244250private import Ssa:: SourceVariables
245251
252+ pragma [ nomagic]
253+ predicate localScopeSourceVariable (
254+ Ssa:: SourceVariables:: LocalScopeSourceVariable sv , LocalScopeVariable v , Callable c1 , Callable c2
255+ ) {
256+ sv .getAssignable ( ) = v and
257+ sv .getEnclosingCallable ( ) = c1 and
258+ v .getCallable ( ) = c2
259+ }
260+
246261private module CallGraph {
247262 private import semmle.code.csharp.dispatch.Dispatch
248263
@@ -767,9 +782,10 @@ private module Cached {
767782 v instanceof PlainFieldOrPropSourceVariable
768783 )
769784 or
770- // In case `c` has multiple bodies, we want each body to get its own implicit
771- // entry definition, so we use the basic block containing the body instead of
772- // the entry block.
785+ // In case `c` has multiple bodies, we want each body to get its own set of
786+ // parameter definitions, so we add special writes to the start of the basic
787+ // blocks containing the bodies
788+ strictcount ( c .getBody ( ) ) > 1 and
773789 v .getAssignable ( ) instanceof Parameter and
774790 bb .getANode ( ) .isBefore ( c .getBody ( ) )
775791 )
@@ -962,7 +978,7 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
962978 predicate ssaDefHasSource ( WriteDefinition def ) {
963979 // exclude flow directly from RHS to SSA definition, as we instead want to
964980 // go from RHS to matching assignable definition, and from there to SSA definition
965- def instanceof Ssa:: ImplicitParameterDefinition
981+ def instanceof Ssa:: ParameterDefinition
966982 }
967983
968984 /**
@@ -994,3 +1010,56 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
9941010}
9951011
9961012private module DataFlowIntegrationImpl = Impl:: DataFlowIntegration< DataFlowIntegrationInput > ;
1013+
1014+ private module MultiBodyNearestLocationInput implements NearestLocationInputSig {
1015+ class C = MultiBodyParameterDefinition ;
1016+
1017+ predicate relevantLocations ( MultiBodyParameterDefinition def , Location l1 , Location l2 ) {
1018+ exists ( Callable c , ControlFlowNode n |
1019+ l1 = def .getParameter ( ) .getALocation ( ) and
1020+ n = def .getBasicBlock ( ) .getANode ( ) and
1021+ n .isBefore ( c .getBody ( ) ) and
1022+ l2 = n .getLocation ( )
1023+ )
1024+ }
1025+ }
1026+
1027+ pragma [ nomagic]
1028+ private predicate implicitEntryDef (
1029+ Ssa:: ImplicitEntryDefinition def , Ssa:: SourceVariable v , Callable c
1030+ ) {
1031+ v = def .getSourceVariable ( ) and
1032+ c = def .getCallable ( )
1033+ }
1034+
1035+ /**
1036+ * An SSA definition representing the implicit initialization of a parameter
1037+ * at the beginning of a callable.
1038+ */
1039+ abstract class ParameterDefinitionImpl extends Ssa:: Definition {
1040+ /** Gets the parameter that this definition represents. */
1041+ abstract Parameter getParameter ( ) ;
1042+
1043+ override string toString ( ) {
1044+ result = "SSA param(" + pragma [ only_bind_out ] ( this .getParameter ( ) ) + ")"
1045+ }
1046+ }
1047+
1048+ class MultiBodyParameterDefinition extends ParameterDefinitionImpl , Ssa:: ImplicitEntryDefinition {
1049+ private Parameter p ;
1050+
1051+ MultiBodyParameterDefinition ( ) {
1052+ exists ( Ssa:: SourceVariable sv , Callable c |
1053+ implicitEntryDef ( this , sv , c ) and
1054+ localScopeSourceVariable ( sv , p , _, c )
1055+ )
1056+ }
1057+
1058+ override Parameter getParameter ( ) { result = p }
1059+
1060+ override string toString ( ) { result = ParameterDefinitionImpl .super .toString ( ) }
1061+
1062+ override Location getLocation ( ) {
1063+ NearestLocation< MultiBodyNearestLocationInput > :: nearestLocation ( this , result , _)
1064+ }
1065+ }
0 commit comments