Skip to content

Commit 547047e

Browse files
committed
add self parameters to API-graphs, and add support for self parameters in MaD
1 parent dc38aa8 commit 547047e

5 files changed

Lines changed: 44 additions & 3 deletions

File tree

python/ql/lib/semmle/python/ApiGraphs.qll

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ module API {
136136
result = this.getASuccessor(Label::keywordParameter(name))
137137
}
138138

139+
/** Gets the node representing the self parameter */
140+
Node getSelfParameter() { result = this.getASuccessor(Label::selfParameter()) }
141+
139142
/**
140143
* Gets the number of parameters of the function represented by this node.
141144
*/
@@ -315,6 +318,12 @@ module API {
315318
/** Gets the API node for a parameter of this invocation. */
316319
Node getAParameter() { result = this.getParameter(_) }
317320

321+
/** Gets the object that this method-call is being called on, if this is a method-call */
322+
Node getSelfParameter() {
323+
result.getARhs() = this.(DataFlow::MethodCallNode).getObject() and
324+
result = callee.getSelfParameter()
325+
}
326+
318327
/** Gets the API node for the keyword parameter `name` of this invocation. */
319328
Node getKeywordParameter(string name) {
320329
result = callee.getKeywordParameter(name) and
@@ -595,6 +604,9 @@ module API {
595604
lbl = Label::keywordParameter(name) and
596605
ref.asExpr() = fn.getInnerScope().getArgByName(name)
597606
)
607+
or
608+
lbl = Label::selfParameter() and
609+
ref.asExpr() = any(PY::Parameter p | p = fn.getInnerScope().getAnArg() and p.isSelf())
598610
)
599611
or
600612
// Built-ins, treated as members of the module `builtins`
@@ -661,6 +673,9 @@ module API {
661673
exists(string name | lbl = Label::keywordParameter(name) |
662674
arg = pred.getACall().getArgByName(name)
663675
)
676+
or
677+
lbl = Label::selfParameter() and
678+
arg = pred.getACall().(DataFlow::MethodCallNode).getObject()
664679
)
665680
}
666681

@@ -777,6 +792,7 @@ module API {
777792
or
778793
exists(any(PY::Function f).getArgByName(name))
779794
} or
795+
MkLabelSelfParameter() or
780796
MkLabelReturn() or
781797
MkLabelSubclass() or
782798
MkLabelAwait()
@@ -834,6 +850,11 @@ module API {
834850
string getName() { result = name }
835851
}
836852

853+
/** A label for the self parameter. */
854+
class LabelSelfParameter extends ApiLabel, MkLabelSelfParameter {
855+
override string toString() { result = "getSelfParameter()" }
856+
}
857+
837858
/** A label that gets the return value of a function. */
838859
class LabelReturn extends ApiLabel, MkLabelReturn {
839860
override string toString() { result = "getReturn()" }
@@ -873,6 +894,9 @@ module API {
873894
/** Gets the `parameter` edge label for the keyword parameter `name`. */
874895
LabelKeywordParameter keywordParameter(string name) { result.getName() = name }
875896

897+
/** Gets the edge label for the self parameter. */
898+
LabelSelfParameter selfParameter() { any() }
899+
876900
/** Gets the `return` edge label. */
877901
LabelReturn return() { any() }
878902

python/ql/lib/semmle/python/frameworks/data/internal/ApiGraphModelsSpecific.qll

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ API::Node getExtraSuccessorFromNode(API::Node node, AccessPathToken token) {
6363
or
6464
token.getName() = "Method" and
6565
result = node.getMember(token.getAnArgument()).getReturn()
66+
or
67+
token.getName() = ["Argument", "Parameter"] and
68+
token.getAnArgument() = "self" and
69+
result = node.getSelfParameter()
6670
// Some features don't have MaD tokens yet, they would need to be added to API-graphs first.
6771
// - decorators ("DecoratedClass", "DecoratedMember", "DecoratedParameter")
6872
// - Array/Map elements ("ArrayElement", "Element", "MapKey", "MapValue")
@@ -78,7 +82,7 @@ API::Node getExtraSuccessorFromInvoke(API::CallNode node, AccessPathToken token)
7882
or
7983
token.getName() = "Argument" and
8084
token.getAnArgument() = "self" and
81-
result.getARhs() = node.(DataFlow::MethodCallNode).getObject() // TODO: Get proper support for this in API-graphs?
85+
result = node.getSelfParameter()
8286
or
8387
token.getName() = "Argument" and
8488
exists(string arg | arg + ":" = token.getAnArgument() | result = node.getKeywordParameter(arg))

python/ql/test/library-tests/frameworks/data/test.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ isSink
2323
| test.py:33:22:33:24 | ControlFlowNode for one | test-source |
2424
| test.py:33:27:33:29 | ControlFlowNode for two | test-source |
2525
| test.py:33:32:33:36 | ControlFlowNode for three | test-source |
26+
| test.py:57:7:57:12 | ControlFlowNode for ArgPos | test-source |
2627
isSource
2728
| test.py:3:5:3:15 | ControlFlowNode for getSource() | test-source |
2829
| test.py:9:8:9:14 | ControlFlowNode for alias() | test-source |
@@ -43,6 +44,7 @@ isSource
4344
| test.py:46:7:46:16 | ControlFlowNode for SubClass() | test-source |
4445
| test.py:51:8:51:18 | ControlFlowNode for Sub2Class() | test-source |
4546
| test.py:53:7:53:16 | ControlFlowNode for Attribute() | test-source |
47+
| test.py:60:13:60:16 | ControlFlowNode for self | test-source |
4648
syntaxErrors
4749
| Member[foo |
4850
| Member[foo] .Member[bar] |

python/ql/test/library-tests/frameworks/data/test.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,12 @@ class Sub2Class (CommonTokens.Class):
5050

5151
sub2 = Sub2Class()
5252

53-
val = inst.foo()
53+
val = inst.foo()
54+
55+
from testlib import ArgPos
56+
57+
val = ArgPos.selfThing(arg, named=2)
58+
59+
class SubClass (ArgPos.MyClass):
60+
def foo(self, arg, named=2):
61+
pass

python/ql/test/library-tests/frameworks/data/test.ql

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,12 @@ class Sinks extends ModelInput::SinkModelCsv {
4949
// callsite filter.
5050
"testlib;;Member[CallFilter].Member[arityOne].WithArity[1].Argument[0..];test-source", //
5151
"testlib;;Member[CallFilter].Member[twoOrMore].WithArity[2..].Argument[0..];test-source", //
52+
// testing non-positional arguments
53+
"testlib;;Member[ArgPos].Member[selfThing].Argument[self];test-source", //
5254
]
5355
}
5456
}
5557

56-
// TODO: Uniform tokens for fields
5758
// TODO: Non-positional arguments (including Named parameters)
5859
// TODO: Any argument
5960
// TODO: Test taint steps.
@@ -75,6 +76,8 @@ class Sources extends ModelInput::SourceModelCsv {
7576
"testlib;;Member[CommonTokens].Member[Super].Subclass.Instance;test-source", //
7677
// method
7778
"testlib;;Member[CommonTokens].Member[Class].Instance.Method[foo];test-source", //
79+
// testing non-positional arguments
80+
"testlib;;Member[ArgPos].Member[MyClass].Subclass.Member[foo].Parameter[self];test-source", //
7881
]
7982
}
8083
}

0 commit comments

Comments
 (0)