Skip to content

Commit 657686b

Browse files
authored
Merge pull request #317 from microsoft/api-graphs-improvements-for-chanel
PS: API graph coverage improvements
2 parents 74f46a9 + f299fef commit 657686b

File tree

6 files changed

+61
-12
lines changed

6 files changed

+61
-12
lines changed

powershell/ql/lib/semmle/code/powershell/ApiGraphs.qll

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -367,9 +367,11 @@ module API {
367367

368368
Node methodEdge(string name) { none() }
369369

370+
Node instanceEdge() { none() }
371+
370372
final predicate isImplicit() { not this.isExplicit(_) }
371373

372-
predicate isExplicit(DataFlow::TypeNameNode typeName) { none() }
374+
predicate isExplicit(DataFlow::Node node) { none() }
373375
}
374376

375377
final class TypeNameNode = AbstractTypeNameNode;
@@ -392,8 +394,8 @@ module API {
392394
)
393395
}
394396

395-
final override predicate isExplicit(DataFlow::TypeNameNode typeName) {
396-
Specific::needsExplicitTypeNameNode(typeName, prefix)
397+
final override predicate isExplicit(DataFlow::Node node) {
398+
Specific::needsExplicitTypeNameNode(node, prefix)
397399
}
398400
}
399401

@@ -424,6 +426,26 @@ module API {
424426
}
425427
}
426428

429+
class NewObjectTypeNameNode extends AbstractTypeNameNode, Impl::MkNewObjectTypeNameNode {
430+
NewObjectTypeNameNode() { this = Impl::MkNewObjectTypeNameNode(prefix) }
431+
432+
final override Node getSuccessor(string name) {
433+
result = Impl::MkNewObjectTypeNameNode(prefix + "." + name)
434+
}
435+
436+
final override Node instanceEdge() {
437+
exists(DataFlow::ObjectCreationNode creation |
438+
prefix = creation.getLowerCaseConstructedTypeName() and
439+
Specific::needsNewObjectTypeNameNode(creation, prefix) and
440+
result = getForwardStartNode(creation)
441+
)
442+
}
443+
444+
final override predicate isExplicit(DataFlow::Node node) {
445+
Specific::needsNewObjectTypeNameNode(node, prefix)
446+
}
447+
}
448+
427449
/**
428450
* An API entry point.
429451
*
@@ -517,6 +539,7 @@ module API {
517539
MkMethodAccessNode(DataFlow::CallNode call) or
518540
MkExplicitTypeNameNode(string prefix) { Specific::needsExplicitTypeNameNode(_, prefix) } or
519541
MkImplicitTypeNameNode(string prefix) { Specific::needsImplicitTypeNameNode(prefix) } or
542+
MkNewObjectTypeNameNode(string prefix) { Specific::needsNewObjectTypeNameNode(_, prefix) } or
520543
MkForwardNode(DataFlow::LocalSourceNode node, TypeTracker t) { isReachable(node, t) } or
521544
/** Intermediate node for following backward data flow. */
522545
MkBackwardNode(DataFlow::LocalSourceNode node, TypeTracker t) { isReachable(node, t) } or
@@ -565,7 +588,7 @@ module API {
565588
)
566589
or
567590
exists(DataFlow::Node qualifier | pred = getForwardEndNode(getALocalSourceStrict(qualifier)) |
568-
exists(CfgNodes::ExprNodes::MemberExprReadAccessCfgNode read |
591+
exists(CfgNodes::ExprNodes::MemberExprCfgNode read |
569592
read.getQualifier() = qualifier.asExpr() and
570593
read.getLowerCaseMemberName() = name and
571594
succ = getForwardStartNode(DataFlow::exprNode(read))
@@ -678,13 +701,28 @@ module API {
678701
positionalParameterEdge(pred, n, succ)
679702
}
680703

704+
pragma[nomagic]
705+
private DataFlow::CallNode getStaticConstructorLikeCall() {
706+
exists(string type |
707+
typeModel(type, type + "!", "Method[" + result.getLowerCaseName() + "].ReturnValue")
708+
)
709+
}
710+
681711
cached
682712
predicate instanceEdge(Node pred, Node succ) {
683713
// TODO: Also model parameters with a given type here
684714
exists(DataFlow::ObjectCreationNode objCreation |
685715
pred = getForwardEndNode(objCreation.getConstructedTypeNode()) and
686716
succ = getForwardStartNode(objCreation)
687717
)
718+
or
719+
exists(DataFlow::CallNode call |
720+
call = getStaticConstructorLikeCall() and
721+
pred = getForwardEndNode(call.getQualifier()) and
722+
succ = getForwardStartNode(call)
723+
)
724+
or
725+
pred.(TypeNameNode).instanceEdge() = succ
688726
}
689727

690728
cached

powershell/ql/lib/semmle/code/powershell/ast/internal/ObjectCreation.qll

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,11 @@ class DotNetObjectCreation extends AbstractObjectCreation, CmdCall {
4646

4747
final override Expr getConstructedTypeExpr() {
4848
// Either it's the named argument `TypeName`
49-
result = CmdCall.super.getNamedArgument("TypeName")
49+
result = CmdCall.super.getNamedArgument("typename")
5050
or
5151
// Or it's the first positional argument if that's the named argument
52-
not CmdCall.super.hasNamedArgument("TypeName") and
53-
result = CmdCall.super.getPositionalArgument(0) and
54-
result = CmdCall.super.getNamedArgument(["ArgumentList", "Property"])
52+
not CmdCall.super.hasNamedArgument("typename") and
53+
result = CmdCall.super.getPositionalArgument(0)
5554
}
5655
}
5756

powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,10 @@ class ObjectCreationNode extends CallNode {
500500
string getAConstructedTypeName() {
501501
result = this.getObjectCreationNode().getAConstructedTypeName()
502502
}
503+
504+
string getLowerCaseConstructedTypeName() {
505+
result = this.getObjectCreationNode().getLowerCaseConstructedTypeName()
506+
}
503507
}
504508

505509
/** A call, viewed as a node in a data flow graph. */

powershell/ql/lib/semmle/code/powershell/frameworks/data/internal/ApiGraphModelsSpecific.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,16 @@ predicate needsImplicitTypeNameNode(string component) {
101101
)
102102
}
103103

104+
predicate needsNewObjectTypeNameNode(DataFlow::ObjectCreationNode creation, string component) {
105+
creation.asExpr().getExpr() instanceof DotNetObjectCreation and
106+
exists(string type, int index |
107+
type = creation.getLowerCaseConstructedTypeName() and
108+
index = [0 .. strictcount(type.indexOf("."))] and
109+
component =
110+
strictconcat(int i, string s | s = type.splitAt(".", i) and i <= index | s, "." order by i)
111+
)
112+
}
113+
104114
/** Gets a Powershell-specific interpretation of the given `type`. */
105115
API::Node getExtraNodeFromType(string rawType) {
106116
exists(string type, string suffix, DataFlow::TypeNameNode typeName |
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +0,0 @@
1-
| test.ps1:15:20:15:36 | # $ type=PSObject | Missing result: type=PSObject |
2-
| test.ps1:19:25:19:41 | # $ type=PSObject | Missing result: type=PSObject |

powershell/ql/test/library-tests/dataflow/typetracking/test.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ Sink $myClass # $ type=myclass
1212

1313
$withNamedArg = New-Object -TypeName PSObject
1414

15-
Sink $withNamedArg # $ type=PSObject
15+
Sink $withNamedArg # $ type=psobject
1616

1717
$withPositionalArg = New-Object PSObject
1818

19-
Sink $withPositionalArg # $ type=PSObject
19+
Sink $withPositionalArg # $ type=psobject

0 commit comments

Comments
 (0)