@@ -10,6 +10,7 @@ private import semmle.code.powershell.dataflow.DataFlow
10
10
private import semmle.code.powershell.typetracking.ApiGraphShared
11
11
private import semmle.code.powershell.typetracking.internal.TypeTrackingImpl
12
12
private import semmle.code.powershell.controlflow.Cfg
13
+ private import frameworks.data.internal.ApiGraphModels
13
14
private import frameworks.data.internal.ApiGraphModelsExtensions as Extensions
14
15
private import frameworks.data.internal.ApiGraphModelsSpecific as Specific
15
16
private import semmle.code.powershell.dataflow.internal.DataFlowPrivate as DataFlowPrivate
@@ -204,18 +205,6 @@ module API {
204
205
Impl:: positionalParameterOrArgumentEdge ( this .getAnEpsilonSuccessor ( ) , n , result )
205
206
}
206
207
207
- /**
208
- * Gets the given keyword parameter of this callable, or keyword argument to this call.
209
- *
210
- * Note: for historical reasons, this predicate may refer to an argument of a call, but this may change in the future.
211
- * When referring to an argument, it is recommended to use `getKeywordArgument(n)` instead.
212
- */
213
- pragma [ inline]
214
- Node getKeywordParameter ( string name ) {
215
- // This predicate is currently not 'inline_late' because 'name' can be an input or output
216
- Impl:: keywordParameterOrArgumentEdge ( this .getAnEpsilonSuccessor ( ) , name , result )
217
- }
218
-
219
208
/**
220
209
* Gets the argument passed in argument position `pos` at this call.
221
210
*/
@@ -260,15 +249,6 @@ module API {
260
249
result = this .getContent ( contents .getAReadContent ( ) )
261
250
}
262
251
263
- /**
264
- * Gets a representative for the instance field of the given `name`.
265
- */
266
- pragma [ inline]
267
- Node getField ( string name ) {
268
- // This predicate is currently not 'inline_late' because 'name' can be an input or output
269
- Impl:: fieldEdge ( this .getAnEpsilonSuccessor ( ) , name , result )
270
- }
271
-
272
252
/**
273
253
* Gets a representative for an arbitrary element of this collection.
274
254
*/
@@ -283,8 +263,7 @@ module API {
283
263
this = Impl:: MkMethodAccessNode ( result ) or
284
264
this = Impl:: MkBackwardNode ( result , _) or
285
265
this = Impl:: MkForwardNode ( result , _) or
286
- this = Impl:: MkSinkNode ( result ) or
287
- this = Impl:: MkNamespaceOfTypeNameNode ( result )
266
+ this = Impl:: MkSinkNode ( result )
288
267
}
289
268
290
269
/** Gets the location of this node. */
@@ -293,6 +272,10 @@ module API {
293
272
or
294
273
this instanceof RootNode and
295
274
result instanceof EmptyLocation
275
+ or
276
+ not this instanceof RootNode and
277
+ not exists ( this .getInducingNode ( ) ) and
278
+ result instanceof EmptyLocation
296
279
}
297
280
298
281
/**
@@ -352,20 +335,84 @@ module API {
352
335
override string toString ( ) { result = "SinkNode(" + this .getInducingNode ( ) + ")" }
353
336
}
354
337
355
- private class UsingNode extends Node , Impl:: MkUsingNode {
356
- UsingStmt using ; // TODO: This should really be the cfg node, I think
338
+ abstract private class AbstractTypeNameNode extends Node {
339
+ string prefix ;
340
+
341
+ bindingset [ prefix]
342
+ AbstractTypeNameNode ( ) { any ( ) }
343
+
344
+ override string toString ( ) { result = "TypeNameNode(" + this .getTypeName ( ) + ")" }
345
+
346
+ string getComponent ( ) {
347
+ exists ( int n |
348
+ result = prefix .splitAt ( "." , n ) and
349
+ not exists ( prefix .splitAt ( "." , n + 1 ) )
350
+ )
351
+ }
352
+
353
+ string getTypeName ( ) { result = prefix }
354
+
355
+ abstract Node getSuccessor ( string name ) ;
356
+
357
+ Node memberEdge ( string name ) { none ( ) }
357
358
358
- UsingNode ( ) { this = Impl :: MkUsingNode ( using ) }
359
+ Node methodEdge ( string name ) { none ( ) }
359
360
360
- override string toString ( ) { result = "UsingNode(" + using + ")" }
361
+ final predicate isImplicit ( ) { not this .isExplicit ( _) }
362
+
363
+ predicate isExplicit ( DataFlow:: TypeNameNode typeName ) { none ( ) }
361
364
}
362
365
363
- private class NamespaceOfTypeNameNode extends Node , Impl:: MkNamespaceOfTypeNameNode {
364
- DataFlow:: QualifiedTypeNameNode typeName ;
366
+ final class TypeNameNode = AbstractTypeNameNode ;
367
+
368
+ private class ExplicitTypeNameNode extends AbstractTypeNameNode , Impl:: MkExplicitTypeNameNode {
369
+ ExplicitTypeNameNode ( ) { this = Impl:: MkExplicitTypeNameNode ( prefix ) }
370
+
371
+ final override Node getSuccessor ( string name ) {
372
+ exists ( ExplicitTypeNameNode succ |
373
+ succ = Impl:: MkExplicitTypeNameNode ( prefix + "." + name ) and
374
+ result = succ
375
+ )
376
+ or
377
+ exists ( DataFlow:: TypeNameNode typeName , int n , string lowerCaseName |
378
+ Specific:: needsExplicitTypeNameNode ( typeName , prefix ) and
379
+ lowerCaseName = typeName .getLowerCaseName ( ) and
380
+ name = lowerCaseName .splitAt ( "." , n ) and
381
+ not lowerCaseName .matches ( "%.%" ) and
382
+ result = getForwardStartNode ( typeName )
383
+ )
384
+ }
385
+
386
+ final override predicate isExplicit ( DataFlow:: TypeNameNode typeName ) {
387
+ Specific:: needsExplicitTypeNameNode ( typeName , prefix )
388
+ }
389
+ }
365
390
366
- NamespaceOfTypeNameNode ( ) { this = Impl :: MkNamespaceOfTypeNameNode ( typeName ) }
391
+ private string getAnAlias ( string cmdlet ) { Specific :: aliasModel ( cmdlet , result ) }
367
392
368
- override string toString ( ) { result = "NamespaceOfTypeNameNode(" + typeName + ")" }
393
+ predicate implicitCmdlet ( string mod , string cmdlet ) {
394
+ exists ( string cmdlet0 |
395
+ Specific:: cmdletModel ( mod , cmdlet0 ) and
396
+ cmdlet = [ cmdlet0 , getAnAlias ( cmdlet0 ) ]
397
+ )
398
+ }
399
+
400
+ private class ImplicitTypeNameNode extends AbstractTypeNameNode , Impl:: MkImplicitTypeNameNode {
401
+ ImplicitTypeNameNode ( ) { this = Impl:: MkImplicitTypeNameNode ( prefix ) }
402
+
403
+ final override Node getSuccessor ( string name ) {
404
+ result = Impl:: MkImplicitTypeNameNode ( prefix + "." + name )
405
+ }
406
+
407
+ final override Node memberEdge ( string name ) { result = this .methodEdge ( name ) }
408
+
409
+ final override Node methodEdge ( string name ) {
410
+ exists ( DataFlow:: CallNode call |
411
+ result = Impl:: MkMethodAccessNode ( call ) and
412
+ name = call .getLowerCaseName ( ) and
413
+ implicitCmdlet ( prefix , name )
414
+ )
415
+ }
369
416
}
370
417
371
418
/**
@@ -405,13 +452,6 @@ module API {
405
452
/** Gets the root node. */
406
453
Node root ( ) { result instanceof RootNode }
407
454
408
- bindingset [ name]
409
- pragma [ inline_late]
410
- Node namespace ( string name ) {
411
- // This predicate is currently not 'inline_late' because 'n' can be an input or output
412
- Impl:: namespace ( name , result )
413
- }
414
-
415
455
pragma [ inline]
416
456
Node getTopLevelMember ( string name ) { Impl:: topLevelMember ( name , result ) }
417
457
@@ -466,8 +506,8 @@ module API {
466
506
MkRoot ( ) or
467
507
/** The method accessed at `call`, synthetically treated as a separate object. */
468
508
MkMethodAccessNode ( DataFlow:: CallNode call ) or
469
- MkUsingNode ( UsingStmt using ) or
470
- MkNamespaceOfTypeNameNode ( DataFlow :: QualifiedTypeNameNode typeName ) or
509
+ MkExplicitTypeNameNode ( string prefix ) { Specific :: needsExplicitTypeNameNode ( _ , prefix ) } or
510
+ MkImplicitTypeNameNode ( string prefix ) { Specific :: needsImplicitTypeNameNode ( prefix ) } or
471
511
MkForwardNode ( DataFlow:: LocalSourceNode node , TypeTracker t ) { isReachable ( node , t ) } or
472
512
/** Intermediate node for following backward data flow. */
473
513
MkBackwardNode ( DataFlow:: LocalSourceNode node , TypeTracker t ) { isReachable ( node , t ) } or
@@ -483,27 +523,8 @@ module API {
483
523
node = any ( EntryPoint e ) .getASink ( )
484
524
}
485
525
486
- bindingset [ e]
487
- pragma [ inline_late]
488
- private DataFlow:: Node getNodeFromExpr ( Expr e ) { result .asExpr ( ) .getExpr ( ) = e }
489
-
490
526
private import frameworks.data.ModelsAsData
491
527
492
- cached
493
- predicate namespace ( string name , Node node ) {
494
- exists ( DataFlow:: QualifiedTypeNameNode typeName |
495
- typeName .getNamespace ( ) = name and
496
- node = MkNamespaceOfTypeNameNode ( typeName )
497
- )
498
- or
499
- exists ( UsingStmt using |
500
- using .getName ( ) .toLowerCase ( ) = name and
501
- node = MkUsingNode ( using )
502
- )
503
- or
504
- node = ModelOutput:: getATypeNode ( name )
505
- }
506
-
507
528
cached
508
529
predicate topLevelMember ( string name , Node node ) { memberEdge ( root ( ) , name , node ) }
509
530
@@ -516,83 +537,55 @@ module API {
516
537
)
517
538
}
518
539
519
- cached
520
- predicate callEdge ( Node pred , string name , Node succ ) {
521
- exists ( DataFlow:: CallNode call |
522
- // from receiver to method call node
523
- pred = getForwardEndNode ( getALocalSourceStrict ( call .getQualifier ( ) ) ) and
524
- succ = MkMethodAccessNode ( call ) and
525
- name = call .getLowerCaseName ( )
526
- )
527
- }
528
-
529
- bindingset [ name]
530
- private string memberOrMethodReturnValue ( string name ) {
531
- // This predicate is a bit ad-hoc, but it's okay for now.
532
- // We can delete it once we no longer use the typeModel and summaryModel
533
- // tables to represent implicit root members.
534
- result = "Method[" + name + "]"
535
- or
536
- result = "Method[" + name + "].ReturnValue"
537
- or
538
- result = "Member[" + name + "]"
539
- }
540
-
541
- private Node getAnImplicitRootMember ( string name ) {
542
- exists ( DataFlow:: CallNode call |
543
- Extensions:: typeModel ( _, Specific:: getAnImplicitImport ( ) , memberOrMethodReturnValue ( name ) )
544
- or
545
- Extensions:: summaryModel ( Specific:: getAnImplicitImport ( ) , memberOrMethodReturnValue ( name ) ,
546
- _, _, _, _)
547
- or
548
- Extensions:: sourceModel ( Specific:: getAnImplicitImport ( ) , memberOrMethodReturnValue ( name ) , _,
549
- _)
550
- |
551
- result = MkMethodAccessNode ( call ) and
552
- name = call .getLowerCaseName ( )
553
- )
554
- }
555
-
556
540
cached
557
541
predicate memberEdge ( Node pred , string name , Node succ ) {
558
542
pred = API:: root ( ) and
559
543
(
560
- exists ( StringConstExpr read |
561
- succ = getForwardStartNode ( getNodeFromExpr ( read ) ) and
562
- name = read .getValueString ( )
563
- )
544
+ succ .( TypeNameNode ) .getTypeName ( ) = name
564
545
or
565
546
exists ( DataFlow:: AutomaticVariableNode automatic |
566
547
automatic .getLowerCaseName ( ) = name and
567
548
succ = getForwardStartNode ( automatic )
568
549
)
569
- or
570
- succ = getAnImplicitRootMember ( name )
571
550
)
572
551
or
573
- exists ( DataFlow :: QualifiedTypeNameNode typeName |
574
- typeName .getLowerCaseName ( ) = name and
575
- pred = MkNamespaceOfTypeNameNode ( typeName ) and
576
- succ = getForwardStartNode ( typeName )
552
+ exists ( TypeNameNode typeName | pred = typeName |
553
+ typeName .getSuccessor ( name ) = succ
554
+ or
555
+ typeName . memberEdge ( name ) = succ
577
556
)
578
557
or
579
- exists ( MemberExprReadAccess read |
580
- read .getLowerCaseMemberName ( ) .toLowerCase ( ) = name and
581
- pred = getForwardEndNode ( getALocalSourceStrict ( getNodeFromExpr ( read .getQualifier ( ) ) ) ) and
582
- succ = getForwardStartNode ( getNodeFromExpr ( read ) )
558
+ exists ( DataFlow:: Node qualifier | pred = getForwardEndNode ( getALocalSourceStrict ( qualifier ) ) |
559
+ exists ( CfgNodes:: ExprNodes:: MemberExprReadAccessCfgNode read |
560
+ read .getQualifier ( ) = qualifier .asExpr ( ) and
561
+ read .getLowerCaseMemberName ( ) = name and
562
+ succ = getForwardStartNode ( DataFlow:: exprNode ( read ) )
563
+ )
564
+ or
565
+ exists ( DataFlow:: CallNode call |
566
+ call .getLowerCaseName ( ) = name and
567
+ call .getQualifier ( ) = qualifier and
568
+ succ = MkMethodAccessNode ( call )
569
+ )
583
570
)
584
571
}
585
572
586
573
cached
587
574
predicate methodEdge ( Node pred , string name , Node succ ) {
588
575
exists ( DataFlow:: CallNode call |
589
- succ = MkMethodAccessNode ( call ) and name = call . getLowerCaseName ( )
590
- |
576
+ succ = MkMethodAccessNode ( call ) and
577
+ name = call . getLowerCaseName ( ) and
591
578
pred = getForwardEndNode ( getALocalSourceStrict ( call .getQualifier ( ) ) )
592
579
)
593
580
or
581
+ pred .( TypeNameNode ) .methodEdge ( name ) = succ
582
+ or
594
583
pred = API:: root ( ) and
595
- succ = getAnImplicitRootMember ( name )
584
+ exists ( DataFlow:: CallNode call |
585
+ not exists ( call .getQualifier ( ) ) and
586
+ succ = MkMethodAccessNode ( call ) and
587
+ name = call .getLowerCaseName ( )
588
+ )
596
589
}
597
590
598
591
cached
@@ -617,11 +610,6 @@ module API {
617
610
)
618
611
}
619
612
620
- cached
621
- predicate fieldEdge ( Node pred , string name , Node succ ) {
622
- Impl:: contentEdge ( pred , DataFlowPrivate:: TFieldContent ( name ) , succ )
623
- }
624
-
625
613
cached
626
614
predicate elementEdge ( Node pred , Node succ ) {
627
615
contentEdge ( pred , any ( DataFlow:: ContentSet set | set .isAnyElement ( ) ) .getAReadContent ( ) , succ )
@@ -665,24 +653,13 @@ module API {
665
653
) , succ )
666
654
}
667
655
668
- private predicate keywordParameterEdge ( Node pred , string name , Node succ ) {
669
- parameterEdge ( pred , any ( DataFlowDispatch:: ParameterPosition pos | pos .isKeyword ( name ) ) , succ )
670
- }
671
-
672
656
cached
673
657
predicate positionalParameterOrArgumentEdge ( Node pred , int n , Node succ ) {
674
658
positionalArgumentEdge ( pred , n , succ )
675
659
or
676
660
positionalParameterEdge ( pred , n , succ )
677
661
}
678
662
679
- cached
680
- predicate keywordParameterOrArgumentEdge ( Node pred , string name , Node succ ) {
681
- keywordArgumentEdge ( pred , name , succ )
682
- or
683
- keywordParameterEdge ( pred , name , succ )
684
- }
685
-
686
663
cached
687
664
predicate instanceEdge ( Node pred , Node succ ) {
688
665
// TODO: Also model parameters with a given type here
0 commit comments