Skip to content

Commit bc92c26

Browse files
committed
Python: Add BoundMethodValue
1 parent 96fdb7a commit bc92c26

File tree

4 files changed

+46
-3
lines changed

4 files changed

+46
-3
lines changed

python/ql/src/semmle/python/objects/Callables.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,8 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
448448

449449
override predicate functionAndOffset(CallableObjectInternal function, int offset) {
450450
function = this.getFunction() and offset = 1
451+
or
452+
function = this and offset = 0
451453
}
452454

453455
override predicate useOriginAsLegacyObject() { any() }

python/ql/src/semmle/python/objects/ObjectAPI.qll

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,11 @@ class CallableValue extends Value {
363363
or
364364
exists(string name |
365365
call.getArgByName(name) = result and
366-
this.(PythonFunctionObjectInternal).getScope().getArg(n).getName() = name
366+
(
367+
this.(PythonFunctionObjectInternal).getScope().getArg(n).getName() = name
368+
or
369+
this.(BoundMethodObjectInternal).getFunction().getScope().getArg(n+1).getName() = name
370+
)
367371
)
368372
or
369373
called instanceof BoundMethodObjectInternal and
@@ -382,11 +386,19 @@ class CallableValue extends Value {
382386
|
383387
exists(int n |
384388
call.getArg(n) = result and
385-
this.(PythonFunctionObjectInternal).getScope().getArg(n + offset).getName() = name
389+
exists(PythonFunctionObjectInternal py |
390+
py = this or py = this.(BoundMethodObjectInternal).getFunction()
391+
|
392+
py.getScope().getArg(n + offset).getName() = name
393+
)
386394
)
387395
or
388396
call.getArgByName(name) = result and
389-
exists(this.(PythonFunctionObjectInternal).getScope().getArgByName(name))
397+
exists(PythonFunctionObjectInternal py |
398+
py = this or py = this.(BoundMethodObjectInternal).getFunction()
399+
|
400+
exists(py.getScope().getArgByName(name))
401+
)
390402
or
391403
called instanceof BoundMethodObjectInternal and
392404
offset = 1 and
@@ -396,6 +408,26 @@ class CallableValue extends Value {
396408
}
397409
}
398410

411+
/**
412+
* Class representing bound-methods, such as `o.func`, where `o` is an instance
413+
* of a class that has a callable attribute `func`.
414+
*/
415+
class BoundMethodValue extends CallableValue {
416+
BoundMethodValue() { this instanceof BoundMethodObjectInternal }
417+
418+
/**
419+
* Gets the callable that will be used when `this` called.
420+
* The actual callable for `func` in `o.func`.
421+
*/
422+
CallableValue getFunction() { result = this.(BoundMethodObjectInternal).getFunction() }
423+
424+
/**
425+
* Gets the value that will be used for the `self` parameter when `this` is called.
426+
* The value for `o` in `o.func`.
427+
*/
428+
Value getSelf() { result = this.(BoundMethodObjectInternal).getSelf() }
429+
}
430+
399431
/**
400432
* Class representing classes in the Python program, both Python and built-in.
401433
*/

python/ql/test/library-tests/PointsTo/calls/getArgumentForCall.expected

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@
77
| 23 | ControlFlowNode for Attribute() | Function f | 0 | ControlFlowNode for c |
88
| 23 | ControlFlowNode for Attribute() | Function f | 1 | ControlFlowNode for w |
99
| 23 | ControlFlowNode for Attribute() | Function f | 2 | ControlFlowNode for z |
10+
| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | 0 | ControlFlowNode for w |
11+
| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | 1 | ControlFlowNode for z |
1012
| 24 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for c |
1113
| 24 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for x |
14+
| 24 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | 0 | ControlFlowNode for x |
1215
| 25 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for y |
1316
| 25 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for z |
1417
| 33 | ControlFlowNode for Attribute() | Function D.foo | 0 | ControlFlowNode for IntegerLiteral |
1518
| 34 | ControlFlowNode for Attribute() | Function D.foo | 0 | ControlFlowNode for IntegerLiteral |
19+
| 37 | ControlFlowNode for Attribute() | Method(builtin method append, List) | 0 | ControlFlowNode for IntegerLiteral |
1620
| 37 | ControlFlowNode for Attribute() | builtin method append | 0 | ControlFlowNode for l |
1721
| 37 | ControlFlowNode for Attribute() | builtin method append | 1 | ControlFlowNode for IntegerLiteral |
1822
| 38 | ControlFlowNode for len() | Builtin-function len | 0 | ControlFlowNode for l |
@@ -21,3 +25,4 @@
2125
| 40 | ControlFlowNode for f() | Function f | 2 | ControlFlowNode for IntegerLiteral |
2226
| 42 | ControlFlowNode for Attribute() | Function C.n | 0 | ControlFlowNode for c |
2327
| 42 | ControlFlowNode for Attribute() | Function C.n | 1 | ControlFlowNode for IntegerLiteral |
28+
| 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | 0 | ControlFlowNode for IntegerLiteral |

python/ql/test/library-tests/PointsTo/calls/getNamedArgumentForCall.expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
| 23 | ControlFlowNode for Attribute() | Function f | arg1 | ControlFlowNode for w |
88
| 23 | ControlFlowNode for Attribute() | Function f | arg2 | ControlFlowNode for z |
99
| 23 | ControlFlowNode for Attribute() | Function f | self | ControlFlowNode for c |
10+
| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | arg0 | ControlFlowNode for w |
11+
| 23 | ControlFlowNode for Attribute() | Method(Function f, C()) | arg1 | ControlFlowNode for z |
1012
| 24 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for x |
1113
| 24 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c |
14+
| 24 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | self | ControlFlowNode for x |
1215
| 25 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for z |
1316
| 25 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for y |
1417
| 33 | ControlFlowNode for Attribute() | Function D.foo | arg | ControlFlowNode for IntegerLiteral |
@@ -19,3 +22,4 @@
1922
| 40 | ControlFlowNode for f() | Function f | arg2 | ControlFlowNode for IntegerLiteral |
2023
| 42 | ControlFlowNode for Attribute() | Function C.n | arg1 | ControlFlowNode for IntegerLiteral |
2124
| 42 | ControlFlowNode for Attribute() | Function C.n | self | ControlFlowNode for c |
25+
| 42 | ControlFlowNode for Attribute() | Method(Function C.n, C()) | arg1 | ControlFlowNode for IntegerLiteral |

0 commit comments

Comments
 (0)