Skip to content

Commit 6f1399b

Browse files
committed
Python: Better handle calls on edge of context.
1 parent 927d724 commit 6f1399b

File tree

14 files changed

+197
-9
lines changed

14 files changed

+197
-9
lines changed

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFuncti
156156
function = this and offset = 0
157157
}
158158

159+
override predicate contextSensitiveCallee() { any() }
160+
159161
}
160162

161163

@@ -277,6 +279,8 @@ class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunc
277279
function = this and offset = 0
278280
}
279281

282+
override predicate contextSensitiveCallee() { none() }
283+
280284
}
281285

282286
/** Class representing methods of built-in classes (otherwise known as method-descriptors) such as `list.append`.
@@ -367,6 +371,8 @@ class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethod
367371
function = this and offset = 0
368372
}
369373

374+
override predicate contextSensitiveCallee() { none() }
375+
370376
}
371377

372378
/** Class representing bound-methods.
@@ -422,7 +428,6 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
422428
result = this.getFunction().getName()
423429
}
424430

425-
426431
override Function getScope() {
427432
result = this.getFunction().getScope()
428433
}
@@ -453,8 +458,9 @@ class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
453458
function = this.getFunction() and offset = 1
454459
}
455460

456-
}
457-
458-
461+
override predicate contextSensitiveCallee() {
462+
this.getFunction().contextSensitiveCallee()
463+
}
459464

465+
}
460466

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ abstract class ClassObjectInternal extends ObjectInternal {
8989
}
9090

9191
override predicate subscriptUnknown() { none() }
92+
93+
override predicate contextSensitiveCallee() { none() }
94+
9295
}
9396

9497
/** Class representing Python source classes */

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ abstract class ConstantObjectInternal extends ObjectInternal {
6969

7070
override string getName() { none() }
7171

72+
override predicate contextSensitiveCallee() { none() }
73+
7274
}
7375

7476
private abstract class BooleanObjectInternal extends ConstantObjectInternal {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ class PropertyInternal extends ObjectInternal, TProperty {
9191
)
9292
}
9393

94+
override predicate contextSensitiveCallee() { none() }
95+
9496
}
9597

9698
/** A class representing classmethods in Python */
@@ -176,6 +178,8 @@ class ClassMethodObjectInternal extends ObjectInternal, TClassMethod {
176178
result = this.getFunction().getName()
177179
}
178180

181+
override predicate contextSensitiveCallee() { none() }
182+
179183
}
180184

181185
class StaticMethodObjectInternal extends ObjectInternal, TStaticMethod {
@@ -247,4 +251,6 @@ class StaticMethodObjectInternal extends ObjectInternal, TStaticMethod {
247251
result = this.getFunction().getName()
248252
}
249253

254+
override predicate contextSensitiveCallee() { none() }
255+
250256
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ abstract class InstanceObject extends ObjectInternal {
5151

5252
override string getName() { none() }
5353

54+
override predicate contextSensitiveCallee() { none() }
55+
5456
}
5557

5658
private predicate self_variable_reaching_init_exit(EssaVariable self) {
@@ -366,6 +368,8 @@ class UnknownInstanceInternal extends TUnknownInstance, ObjectInternal {
366368

367369
override string getName() { none() }
368370

371+
override predicate contextSensitiveCallee() { none() }
372+
369373
}
370374

371375
private int lengthFromClass(ClassObjectInternal cls) {
@@ -472,5 +476,7 @@ class SuperInstance extends TSuperInstance, ObjectInternal {
472476

473477
override string getName() { none() }
474478

479+
override predicate contextSensitiveCallee() { none() }
480+
475481
}
476482

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ abstract class ModuleObjectInternal extends ObjectInternal {
5252
any(PackageObjectInternal package).getInitModule() = this
5353
}
5454

55+
override predicate contextSensitiveCallee() { none() }
56+
5557
}
5658

5759
/** A class representing built-in modules */
@@ -408,5 +410,7 @@ class AbsentModuleAttributeObjectInternal extends ObjectInternal, TAbsentModuleA
408410
/* We know what this is called, but not its innate name */
409411
override string getName() { none() }
410412

413+
override predicate contextSensitiveCallee() { none() }
414+
411415
}
412416

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ class ObjectInternal extends TObject {
167167
*/
168168
abstract string getName();
169169

170+
abstract predicate contextSensitiveCallee();
171+
170172
}
171173

172174

@@ -249,6 +251,9 @@ class BuiltinOpaqueObjectInternal extends ObjectInternal, TBuiltinOpaqueObject {
249251
override string getName() {
250252
result = this.getBuiltin().getName()
251253
}
254+
255+
override predicate contextSensitiveCallee() { none() }
256+
252257
}
253258

254259

@@ -326,6 +331,8 @@ class UnknownInternal extends ObjectInternal, TUnknown {
326331

327332
override string getName() { none() }
328333

334+
override predicate contextSensitiveCallee() { none() }
335+
329336
}
330337

331338
class UndefinedInternal extends ObjectInternal, TUndefined {
@@ -404,6 +411,8 @@ class UndefinedInternal extends ObjectInternal, TUndefined {
404411

405412
override string getName() { none() }
406413

414+
override predicate contextSensitiveCallee() { none() }
415+
407416
}
408417

409418
module ObjectInternal {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ abstract class SequenceObjectInternal extends ObjectInternal {
3232

3333
override string getName() { none() }
3434

35+
override predicate contextSensitiveCallee() { none() }
36+
3537
}
3638

3739
abstract class TupleObjectInternal extends SequenceObjectInternal {

python/ql/src/semmle/python/pointsto/PointsTo.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,7 @@ module InterProceduralPointsTo {
839839
)
840840
or
841841
context.untrackableCall(f) and
842+
func.contextSensitiveCallee() and
842843
value = ObjectInternal::unknown() and origin = f
843844
or
844845
exists(CfgOrigin orig |
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,52 @@
1+
| 1 | ControlFlowNode for functools | Module functools | test.py:1 |
2+
| 3 | ControlFlowNode for annotate | Function annotate | test.py:3 |
3+
| 4 | ControlFlowNode for inner | Function inner | test.py:4 |
4+
| 5 | ControlFlowNode for func | Function func1 | test.py:23 |
5+
| 6 | ControlFlowNode for func | Function func1 | test.py:23 |
6+
| 7 | ControlFlowNode for inner | Function inner | test.py:4 |
7+
| 9 | ControlFlowNode for wraps1 | Function wraps1 | test.py:9 |
8+
| 10 | ControlFlowNode for args | args | test.py:10 |
9+
| 10 | ControlFlowNode for wrapper | Function wrapper | test.py:10 |
10+
| 11 | ControlFlowNode for args | args | test.py:10 |
11+
| 13 | ControlFlowNode for wrapper | Function wrapper | test.py:10 |
12+
| 15 | ControlFlowNode for wraps2 | Function wraps2 | test.py:15 |
13+
| 16 | ControlFlowNode for func | Function func3 | test.py:31 |
14+
| 16 | ControlFlowNode for functools | Module functools | test.py:1 |
15+
| 17 | ControlFlowNode for args | args | test.py:17 |
16+
| 17 | ControlFlowNode for wrapper | Function wrapper | test.py:17 |
17+
| 18 | ControlFlowNode for args | args | test.py:17 |
18+
| 20 | ControlFlowNode for wrapper | Function wrapper | test.py:17 |
19+
| 22 | ControlFlowNode for annotate | Function annotate | test.py:3 |
20+
| 23 | ControlFlowNode for func1 | Function func1 | test.py:23 |
21+
| 26 | ControlFlowNode for wraps1 | Function wraps1 | test.py:9 |
22+
| 27 | ControlFlowNode for func2 | Function wrapper | test.py:10 |
23+
| 30 | ControlFlowNode for wraps2 | Function wraps2 | test.py:15 |
24+
| 31 | ControlFlowNode for func3 | Function wrapper | test.py:17 |
125
| 41 | ControlFlowNode for func1 | Function func1 | test.py:23 |
226
| 42 | ControlFlowNode for func2 | Function wrapper | test.py:10 |
327
| 43 | ControlFlowNode for func3 | Function wrapper | test.py:17 |
28+
| 48 | ControlFlowNode for None | NoneType None | test.py:48 |
29+
| 48 | ControlFlowNode for register | Function register | test.py:48 |
30+
| 49 | ControlFlowNode for decorator | Function decorator | test.py:49 |
31+
| 50 | ControlFlowNode for callable | Builtin-function callable | test.py:50 |
32+
| 50 | ControlFlowNode for func | Function baz | test.py:72 |
33+
| 50 | ControlFlowNode for func | Function foo | test.py:60 |
34+
| 51 | ControlFlowNode for ValueError | builtin-class ValueError | test.py:51 |
35+
| 52 | ControlFlowNode for func | Function baz | test.py:72 |
36+
| 52 | ControlFlowNode for func | Function foo | test.py:60 |
37+
| 54 | ControlFlowNode for callable | Builtin-function callable | test.py:54 |
38+
| 54 | ControlFlowNode for name | Function bar | test.py:66 |
39+
| 54 | ControlFlowNode for name | NoneType None | test.py:48 |
40+
| 54 | ControlFlowNode for name | int 17 | test.py:59 |
41+
| 55 | ControlFlowNode for decorator | Function decorator | test.py:49 |
42+
| 55 | ControlFlowNode for name | Function bar | test.py:66 |
43+
| 57 | ControlFlowNode for decorator | Function decorator | test.py:49 |
44+
| 59 | ControlFlowNode for register | Function register | test.py:48 |
45+
| 60 | ControlFlowNode for foo | Function foo | test.py:60 |
46+
| 63 | ControlFlowNode for foo | Function foo | test.py:60 |
47+
| 65 | ControlFlowNode for register | Function register | test.py:48 |
48+
| 66 | ControlFlowNode for bar | Function bar | test.py:66 |
49+
| 69 | ControlFlowNode for bar | Function bar | test.py:66 |
50+
| 71 | ControlFlowNode for register | Function register | test.py:48 |
51+
| 72 | ControlFlowNode for baz | Function baz | test.py:72 |
52+
| 75 | ControlFlowNode for baz | Function baz | test.py:72 |

0 commit comments

Comments
 (0)