@@ -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,52 @@ 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+ l1 = def .getParameter ( ) .getALocation ( ) and
1019+ l2 = def .getBasicBlock ( ) .getLocation ( )
1020+ }
1021+ }
1022+
1023+ pragma [ nomagic]
1024+ private predicate implicitEntryDef (
1025+ Ssa:: ImplicitEntryDefinition def , Ssa:: SourceVariable v , Callable c
1026+ ) {
1027+ v = def .getSourceVariable ( ) and
1028+ c = def .getCallable ( )
1029+ }
1030+
1031+ /**
1032+ * An SSA definition representing the implicit initialization of a parameter
1033+ * at the beginning of a callable.
1034+ */
1035+ abstract class ParameterDefinitionImpl extends Ssa:: Definition {
1036+ /** Gets the parameter that this definition represents. */
1037+ abstract Parameter getParameter ( ) ;
1038+
1039+ override string toString ( ) {
1040+ result = "SSA param(" + pragma [ only_bind_out ] ( this .getParameter ( ) ) + ")"
1041+ }
1042+ }
1043+
1044+ class MultiBodyParameterDefinition extends ParameterDefinitionImpl , Ssa:: ImplicitEntryDefinition {
1045+ private Parameter p ;
1046+
1047+ MultiBodyParameterDefinition ( ) {
1048+ exists ( Ssa:: SourceVariable sv , Callable c |
1049+ implicitEntryDef ( this , sv , c ) and
1050+ localScopeSourceVariable ( sv , p , _, c )
1051+ )
1052+ }
1053+
1054+ override Parameter getParameter ( ) { result = p }
1055+
1056+ override string toString ( ) { result = ParameterDefinitionImpl .super .toString ( ) }
1057+
1058+ override Location getLocation ( ) {
1059+ NearestLocation< MultiBodyNearestLocationInput > :: nearestLocation ( this , result , _)
1060+ }
1061+ }
0 commit comments