@@ -11,6 +11,61 @@ private import semmle.code.csharp.dispatch.Dispatch
1111private import semmle.code.csharp.frameworks.EntityFramework
1212private import semmle.code.csharp.frameworks.NHibernate
1313
14+ /** Calculation of the relative order in which `this` references are read. */
15+ private module ThisFlow {
16+ class BasicBlock = ControlFlow:: BasicBlock ;
17+
18+ /** Holds if `n` is a `this` access at control flow node `cfn`. */
19+ private predicate thisAccess ( Node n , ControlFlow:: Node cfn ) {
20+ n .( InstanceParameterNode ) .getCallable ( ) = cfn .( ControlFlow:: Nodes:: EntryNode ) .getCallable ( )
21+ or
22+ n .asExprAtNode ( cfn ) = any ( Expr e | e instanceof ThisAccess or e instanceof BaseAccess )
23+ }
24+
25+ private predicate thisAccess ( Node n , BasicBlock bb , int i ) { thisAccess ( n , bb .getNode ( i ) ) }
26+
27+ private predicate thisRank ( Node n , BasicBlock bb , int rankix ) {
28+ exists ( int i |
29+ i = rank [ rankix ] ( int j | thisAccess ( _, bb , j ) ) and
30+ thisAccess ( n , bb , i )
31+ )
32+ }
33+
34+ private int lastRank ( BasicBlock bb ) { result = max ( int rankix | thisRank ( _, bb , rankix ) ) }
35+
36+ private predicate blockPrecedesThisAccess ( BasicBlock bb ) { thisAccess ( _, bb .getASuccessor * ( ) , _) }
37+
38+ private predicate thisAccessBlockReaches ( BasicBlock bb1 , BasicBlock bb2 ) {
39+ thisAccess ( _, bb1 , _) and bb2 = bb1 .getASuccessor ( )
40+ or
41+ exists ( BasicBlock mid |
42+ thisAccessBlockReaches ( bb1 , mid ) and
43+ bb2 = mid .getASuccessor ( ) and
44+ not thisAccess ( _, mid , _) and
45+ blockPrecedesThisAccess ( bb2 )
46+ )
47+ }
48+
49+ private predicate thisAccessBlockStep ( BasicBlock bb1 , BasicBlock bb2 ) {
50+ thisAccessBlockReaches ( bb1 , bb2 ) and
51+ thisAccess ( _, bb2 , _)
52+ }
53+
54+ /** Holds if `n1` and `n2` are control-flow adjacent references to `this`. */
55+ predicate adjacentThisRefs ( Node n1 , Node n2 ) {
56+ exists ( int rankix , BasicBlock bb |
57+ thisRank ( n1 , bb , rankix ) and
58+ thisRank ( n2 , bb , rankix + 1 )
59+ )
60+ or
61+ exists ( BasicBlock bb1 , BasicBlock bb2 |
62+ thisRank ( n1 , bb1 , lastRank ( bb1 ) ) and
63+ thisAccessBlockStep ( bb1 , bb2 ) and
64+ thisRank ( n2 , bb2 , 1 )
65+ )
66+ }
67+ }
68+
1469/** Provides predicates related to local data flow. */
1570module LocalFlow {
1671 class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration {
@@ -173,6 +228,14 @@ module DataFlowPrivateCached {
173228 or
174229 any ( ArgumentNode n ) .argumentOf ( _, _)
175230 or
231+ exists ( any ( Node n ) .getEnclosingCallable ( ) )
232+ or
233+ exists ( any ( Node n ) .getControlFlowNode ( ) )
234+ or
235+ exists ( any ( Node n ) .getType ( ) )
236+ or
237+ exists ( any ( Node n ) .getLocation ( ) )
238+ or
176239 exists ( any ( Node n ) .toString ( ) )
177240 or
178241 exists ( any ( OutNode n ) .getCall ( ) )
@@ -183,6 +246,7 @@ module DataFlowPrivateCached {
183246 TExprNode ( ControlFlow:: Nodes:: ElementNode cfn ) { cfn .getElement ( ) instanceof Expr } or
184247 TCilExprNode ( CIL:: Expr e ) { e .getImplementation ( ) instanceof CIL:: BestImplementation } or
185248 TSsaDefinitionNode ( Ssa:: Definition def ) or
249+ TInstanceParameterNode ( Callable c ) { c .hasBody ( ) and not c .( Modifiable ) .isStatic ( ) } or
186250 TCilParameterNode ( CIL:: Parameter p ) { p .getMethod ( ) .hasBody ( ) } or
187251 TTaintedParameterNode ( Parameter p ) { p .getCallable ( ) .hasBody ( ) } or
188252 TTaintedReturnNode ( ControlFlow:: Nodes:: ElementNode cfn ) {
@@ -198,97 +262,8 @@ module DataFlowPrivateCached {
198262 ) {
199263 cfn .getElement ( ) instanceof DelegateArgumentToLibraryCallable and
200264 any ( DelegateArgumentConfiguration x ) .hasExprPath ( _, cfn , _, call )
201- }
202-
203- cached
204- DotNet:: Callable getEnclosingCallable ( Node node ) {
205- result = node .( ExprNode ) .getExpr ( ) .getEnclosingCallable ( )
206- or
207- result = node .( SsaDefinitionNode ) .getDefinition ( ) .getEnclosingCallable ( )
208- or
209- exists ( CIL:: Parameter p | node = TCilParameterNode ( p ) | result = p .getCallable ( ) )
210- or
211- result = getEnclosingCallable ( node .( TaintedParameterNode ) .getUnderlyingNode ( ) )
212- or
213- result = getEnclosingCallable ( node .( TaintedReturnNode ) .getUnderlyingNode ( ) )
214- or
215- exists ( ControlFlow:: Nodes:: ElementNode cfn | node = TImplicitCapturedArgumentNode ( cfn , _) |
216- result = cfn .getEnclosingCallable ( )
217- )
218- or
219- exists ( ControlFlow:: Nodes:: ElementNode cfn | node = TImplicitDelegateOutNode ( cfn , _) |
220- result = cfn .getEnclosingCallable ( )
221- )
222- }
223-
224- cached
225- DotNet:: Type getType ( Node node ) {
226- result = node .( ExprNode ) .getExpr ( ) .getType ( )
227- or
228- result = node .( SsaDefinitionNode ) .getDefinition ( ) .getSourceVariable ( ) .getType ( )
229- or
230- exists ( CIL:: Parameter p | node = TCilParameterNode ( p ) | result = p .getType ( ) )
231- or
232- result = getType ( node .( TaintedParameterNode ) .getUnderlyingNode ( ) )
233- or
234- result = getType ( node .( TaintedReturnNode ) .getUnderlyingNode ( ) )
235- or
236- exists ( LocalScopeVariable v | node = TImplicitCapturedArgumentNode ( _, v ) | result = v .getType ( ) )
237- or
238- exists ( ControlFlow:: Nodes:: ElementNode cfn | node = TImplicitDelegateOutNode ( cfn , _) |
239- result = cfn .getElement ( ) .( Expr ) .getType ( )
240- )
241- }
242-
243- cached
244- Location getLocation ( Node node ) {
245- result = node .( ExprNode ) .getExpr ( ) .getLocation ( )
246- or
247- result = node .( SsaDefinitionNode ) .getDefinition ( ) .getLocation ( )
248- or
249- exists ( CIL:: Parameter p | node = TCilParameterNode ( p ) | result = p .getLocation ( ) )
250- or
251- result = getLocation ( node .( TaintedParameterNode ) .getUnderlyingNode ( ) )
252- or
253- result = getLocation ( node .( TaintedReturnNode ) .getUnderlyingNode ( ) )
254- or
255- exists ( ControlFlow:: Nodes:: ElementNode cfn | node = TImplicitCapturedArgumentNode ( cfn , _) |
256- result = cfn .getLocation ( )
257- )
258- or
259- exists ( ControlFlow:: Nodes:: ElementNode cfn | node = TImplicitDelegateOutNode ( cfn , _) |
260- result = cfn .getLocation ( )
261- )
262- }
263-
264- cached
265- string toString ( Node node ) {
266- exists ( ControlFlow:: Nodes:: ElementNode cfn | node = TExprNode ( cfn ) | result = cfn .toString ( ) )
267- or
268- node = TCilExprNode ( _) and
269- result = "CIL expression"
270- or
271- exists ( Parameter p | explicitParameterNode ( node , p ) | result = p .toString ( ) )
272- or
273- exists ( Ssa:: Definition def | def = node .( SsaDefinitionNode ) .getDefinition ( ) |
274- not explicitParameterNode ( node , _) and
275- result = def .toString ( )
276- )
277- or
278- exists ( CIL:: Parameter p | node = TCilParameterNode ( p ) | result = p .toString ( ) )
279- or
280- result = toString ( node .( TaintedParameterNode ) .getUnderlyingNode ( ) )
281- or
282- result = toString ( node .( TaintedReturnNode ) .getUnderlyingNode ( ) )
283- or
284- exists ( LocalScopeVariable v | node = TImplicitCapturedArgumentNode ( _, v ) |
285- result = "[implicit argument] " + v
286- )
287- or
288- exists ( ControlFlow:: Nodes:: ElementNode cfn | node = TImplicitDelegateOutNode ( cfn , _) |
289- result = "[output] " + cfn
290- )
291- }
265+ } or
266+ TMallocNode ( ControlFlow:: Nodes:: ElementNode cfn ) { cfn .getElement ( ) instanceof ObjectCreation }
292267
293268 /**
294269 * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
@@ -313,6 +288,8 @@ module DataFlowPrivateCached {
313288 nodeTo = TExprNode ( cfnTo )
314289 )
315290 or
291+ ThisFlow:: adjacentThisRefs ( nodeFrom , nodeTo )
292+ or
316293 // Flow into SSA pseudo definition
317294 exists ( Ssa:: Definition def , Ssa:: PseudoDefinition pseudo |
318295 LocalFlow:: localFlowSsaInput ( nodeFrom , def )
@@ -358,6 +335,17 @@ class SsaDefinitionNode extends Node, TSsaDefinitionNode {
358335
359336 /** Gets the underlying SSA definition. */
360337 Ssa:: Definition getDefinition ( ) { result = def }
338+
339+ override Callable getEnclosingCallable ( ) { result = def .getEnclosingCallable ( ) }
340+
341+ override Type getType ( ) { result = def .getSourceVariable ( ) .getType ( ) }
342+
343+ override Location getLocation ( ) { result = def .getLocation ( ) }
344+
345+ override string toString ( ) {
346+ not explicitParameterNode ( this , _) and
347+ result = def .toString ( )
348+ }
361349}
362350
363351private module ParameterNodes {
@@ -388,14 +376,42 @@ private module ParameterNodes {
388376 override DotNet:: Parameter getParameter ( ) { result = parameter }
389377
390378 override predicate isParameterOf ( DotNet:: Callable c , int i ) { c .getParameter ( i ) = parameter }
379+
380+ override DotNet:: Callable getEnclosingCallable ( ) { result = parameter .getCallable ( ) }
381+
382+ override DotNet:: Type getType ( ) { result = parameter .getType ( ) }
383+
384+ override Location getLocation ( ) { result = parameter .getLocation ( ) }
385+
386+ override string toString ( ) { result = parameter .toString ( ) }
387+ }
388+
389+ /** An implicit instance (`this`) parameter. */
390+ class InstanceParameterNode extends ParameterNode , TInstanceParameterNode {
391+ private Callable callable ;
392+
393+ InstanceParameterNode ( ) { this = TInstanceParameterNode ( callable ) }
394+
395+ /** Gets the callable containing this implicit instance parameter. */
396+ Callable getCallable ( ) { result = callable }
397+
398+ override predicate isParameterOf ( DotNet:: Callable c , int pos ) { callable = c and pos = - 1 }
399+
400+ override Callable getEnclosingCallable ( ) { result = callable }
401+
402+ override Type getType ( ) { result = callable .getDeclaringType ( ) }
403+
404+ override Location getLocation ( ) { result = callable .getLocation ( ) }
405+
406+ override string toString ( ) { result = "this" }
391407 }
392408
393409 /**
394410 * A tainted parameter. Tainted parameters are a mere implementation detail, used
395411 * to restrict tainted flow into callables to just taint tracking (just like flow
396412 * out of `TaintedReturnNode`s is restricted to taint tracking).
397413 */
398- class TaintedParameterNode extends ParameterNode {
414+ class TaintedParameterNode extends ParameterNode , TTaintedParameterNode {
399415 private Parameter parameter ;
400416
401417 TaintedParameterNode ( ) { this = TTaintedParameterNode ( parameter ) }
@@ -412,6 +428,16 @@ private module ParameterNodes {
412428 // the actual parameters
413429 i = parameter .getPosition ( ) + c .getNumberOfParameters ( )
414430 }
431+
432+ override Callable getEnclosingCallable ( ) {
433+ result = this .getUnderlyingNode ( ) .getEnclosingCallable ( )
434+ }
435+
436+ override Type getType ( ) { result = this .getUnderlyingNode ( ) .getType ( ) }
437+
438+ override Location getLocation ( ) { result = this .getUnderlyingNode ( ) .getLocation ( ) }
439+
440+ override string toString ( ) { result = this .getUnderlyingNode ( ) .toString ( ) }
415441 }
416442
417443 module ImplicitCapturedParameterNodeImpl {
@@ -539,7 +565,11 @@ private module ArgumentNodes {
539565 }
540566
541567 private DotNet:: Expr getArgument ( DotNet:: Expr call , int i ) {
542- call = any ( DispatchCall dc | result = dc .getArgument ( i ) ) .getCall ( )
568+ call = any ( DispatchCall dc |
569+ result = dc .getArgument ( i )
570+ or
571+ result = dc .getQualifier ( ) and i = - 1 and not dc .getAStaticTarget ( ) .( Modifiable ) .isStatic ( )
572+ ) .getCall ( )
543573 or
544574 result = call .( DelegateCall ) .getArgument ( i )
545575 or
@@ -649,6 +679,39 @@ private module ArgumentNodes {
649679 )
650680 )
651681 }
682+
683+ override Callable getEnclosingCallable ( ) { result = cfn .getEnclosingCallable ( ) }
684+
685+ override Type getType ( ) { result = v .getType ( ) }
686+
687+ override Location getLocation ( ) { result = cfn .getLocation ( ) }
688+
689+ override string toString ( ) { result = "[implicit argument] " + v }
690+ }
691+
692+ /**
693+ * A node that corresponds to the value of an object creation (`new C()`) before
694+ * the constructor has run.
695+ */
696+ class MallocNode extends ArgumentNode , TMallocNode {
697+ private ControlFlow:: Nodes:: ElementNode cfn ;
698+
699+ MallocNode ( ) { this = TMallocNode ( cfn ) }
700+
701+ override predicate argumentOf ( DataFlowCall call , int pos ) {
702+ call = TNonDelegateCall ( cfn , _) and
703+ pos = - 1
704+ }
705+
706+ override ControlFlow:: Node getControlFlowNode ( ) { result = cfn }
707+
708+ override Callable getEnclosingCallable ( ) { result = cfn .getEnclosingCallable ( ) }
709+
710+ override Type getType ( ) { result = cfn .getElement ( ) .( Expr ) .getType ( ) }
711+
712+ override Location getLocation ( ) { result = cfn .getLocation ( ) }
713+
714+ override string toString ( ) { result = "malloc" }
652715 }
653716}
654717import ArgumentNodes
@@ -712,6 +775,16 @@ private module ReturnNodes {
712775 ExprReturnNode getUnderlyingNode ( ) { result .getControlFlowNode ( ) = cfn }
713776
714777 override YieldReturnKind getKind ( ) { any ( ) }
778+
779+ override Callable getEnclosingCallable ( ) {
780+ result = this .getUnderlyingNode ( ) .getEnclosingCallable ( )
781+ }
782+
783+ override Type getType ( ) { result = this .getUnderlyingNode ( ) .getType ( ) }
784+
785+ override Location getLocation ( ) { result = this .getUnderlyingNode ( ) .getLocation ( ) }
786+
787+ override string toString ( ) { result = this .getUnderlyingNode ( ) .toString ( ) }
715788 }
716789
717790 /**
@@ -849,6 +922,14 @@ private module OutNodes {
849922 override ControlFlow:: Nodes:: ElementNode getControlFlowNode ( ) { result = cfn }
850923
851924 override ImplicitDelegateDataFlowCall getCall ( ) { result .getNode ( ) = this }
925+
926+ override Callable getEnclosingCallable ( ) { result = cfn .getEnclosingCallable ( ) }
927+
928+ override Type getType ( ) { result = cfn .getElement ( ) .( Expr ) .getType ( ) }
929+
930+ override Location getLocation ( ) { result = cfn .getLocation ( ) }
931+
932+ override string toString ( ) { result = "[output] " + cfn }
852933 }
853934}
854935import OutNodes
0 commit comments