Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bf78c62

Browse files
committed
Python points-to: Add objects representing missing modules and their attributes.
1 parent b10a7cd commit bf78c62

19 files changed

Lines changed: 252 additions & 18 deletions

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

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,156 @@ class PythonModuleObjectInternal extends ModuleObjectInternal, TPythonModule {
250250

251251
}
252252

253+
class AbsentModuleObjectInternal extends ModuleObjectInternal, TAbsentModule {
254+
255+
override Builtin getBuiltin() {
256+
none()
257+
}
258+
259+
override string toString() {
260+
if exists(Module m, SyntaxError se | se.getFile() = m.getFile() and m.getName() = this.getName()) then
261+
result = "Unparsable module " + this.getName()
262+
else
263+
result = "Missing module " + this.getName()
264+
}
265+
266+
override string getName() {
267+
this = TAbsentModule(result)
268+
}
269+
270+
override predicate introduced(ControlFlowNode node, PointsToContext context) {
271+
missing_imported_module(node, context, this.getName())
272+
}
273+
274+
override ClassDecl getClassDeclaration() {
275+
none()
276+
}
277+
278+
override Module getSourceModule() {
279+
none()
280+
}
281+
282+
PythonModuleObjectInternal getInitModule() {
283+
none()
284+
}
285+
286+
override int intValue() {
287+
none()
288+
}
289+
290+
override string strValue() {
291+
none()
292+
}
293+
294+
override predicate calleeAndOffset(Function scope, int paramOffset) {
295+
none()
296+
}
297+
298+
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
299+
value = TAbsentModuleAttribute(this, name) and origin = CfgOrigin::unknown()
300+
}
301+
302+
pragma [noinline] override predicate attributesUnknown() { none() }
303+
304+
override ControlFlowNode getOrigin() {
305+
none()
306+
}
307+
308+
override predicate isMissing() {
309+
any()
310+
}
311+
312+
}
313+
314+
class AbsentModuleAttributeObjectInternal extends ObjectInternal, TAbsentModuleAttribute {
315+
316+
override Builtin getBuiltin() {
317+
none()
318+
}
319+
320+
override string toString() {
321+
exists(ModuleObjectInternal mod, string name |
322+
this = TAbsentModuleAttribute(mod, name) and
323+
result = "Missing module attribute " + mod.getName() + "." + name
324+
)
325+
}
326+
327+
override predicate introduced(ControlFlowNode node, PointsToContext context) {
328+
exists(ModuleObjectInternal mod, string name |
329+
this = TAbsentModuleAttribute(mod, name) |
330+
PointsToInternal::pointsTo(node.(AttrNode).getObject(name), context, mod, _)
331+
or
332+
PointsToInternal::pointsTo(node.(ImportMemberNode).getModule(name), context, mod, _)
333+
)
334+
}
335+
336+
override ClassDecl getClassDeclaration() {
337+
none()
338+
}
339+
340+
PythonModuleObjectInternal getInitModule() {
341+
none()
342+
}
343+
344+
override int intValue() {
345+
none()
346+
}
347+
348+
override string strValue() {
349+
none()
350+
}
351+
352+
override predicate calleeAndOffset(Function scope, int paramOffset) {
353+
none()
354+
}
355+
356+
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
357+
none()
358+
}
359+
360+
pragma [noinline] override predicate attributesUnknown() { any() }
361+
362+
override ControlFlowNode getOrigin() {
363+
none()
364+
}
365+
366+
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
367+
// Don't know, assume not callable.
368+
none()
369+
}
370+
371+
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) {
372+
// Don't know, assume not callable.
373+
none()
374+
}
375+
376+
override boolean isClass() { result = maybe() }
377+
378+
override boolean isComparable() { result = false }
379+
380+
override boolean booleanValue() {
381+
result = maybe()
382+
}
383+
384+
override ObjectInternal getClass() {
385+
result = ObjectInternal::unknownClass()
386+
}
387+
388+
override boolean isDescriptor() { result = false }
389+
390+
override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
391+
392+
override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
393+
394+
override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
395+
396+
override int length() { none() }
397+
398+
override predicate subscriptUnknown() { any() }
399+
400+
override predicate isMissing() {
401+
any()
402+
}
403+
404+
}
405+

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,15 @@ class Value extends TObject {
5656
predicate isBuiltin() {
5757
this.(ObjectInternal).isBuiltin()
5858
}
59+
60+
/** Holds if this value represents an entity that is inferred to exist,
61+
* but missing from the database.
62+
* Most commonly, this is a module that is imported, but wasn't present during extraction.
63+
*/
64+
predicate isMissing() {
65+
this.(ObjectInternal).isMissing()
66+
}
67+
5968
}
6069

6170
class ModuleValue extends Value {

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ class ObjectInternal extends TObject {
111111

112112
predicate functionAndOffset(CallableObjectInternal function, int offset) { none() }
113113

114+
/** Holds if this 'object' represents an entity that is inferred to exist
115+
* but is missing from the database */
116+
predicate isMissing() {
117+
none()
118+
}
119+
114120
}
115121

116122

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

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ newtype TObject =
3939
exists(moduleNameFromFile(f))
4040
}
4141
or
42-
TPythonModule(Module m) { not m.isPackage() }
42+
TPythonModule(Module m) {
43+
not m.isPackage() and not exists(SyntaxError se | se.getFile() = m.getFile())
44+
}
4345
or
4446
TTrue()
4547
or
@@ -160,6 +162,23 @@ newtype TObject =
160162
}
161163
or
162164
TSysVersionInfo()
165+
or
166+
TAbsentModule(string name) {
167+
missing_imported_module(_, _, name)
168+
}
169+
or
170+
TAbsentModuleAttribute(AbsentModuleObjectInternal mod, string attrname) {
171+
(
172+
PointsToInternal::pointsTo(any(AttrNode attr).getObject(attrname), _, mod, _)
173+
or
174+
PointsToInternal::pointsTo(any(ImportMemberNode imp).getModule(attrname), _, mod, _)
175+
)
176+
and
177+
exists(string modname |
178+
modname = mod.getName() and
179+
not common_module_name(modname + "." + attrname)
180+
)
181+
}
163182

164183
private predicate is_power_2(int n) {
165184
n = 1 or
@@ -327,6 +346,30 @@ private predicate neither_class_nor_static_method(Function f) {
327346
)
328347
}
329348

349+
predicate missing_imported_module(ControlFlowNode imp, Context ctx, string name) {
350+
ctx.isImport() and imp.(ImportExprNode).getNode().getAnImportedModuleName() = name and
351+
(
352+
not exists(Module m | m.getName() = name) and
353+
not exists(Builtin b | b.isModule() and b.getName() = name)
354+
or
355+
exists(Module m, SyntaxError se |
356+
m.getName() = name and
357+
se.getFile() = m.getFile()
358+
)
359+
)
360+
or
361+
exists(AbsentModuleObjectInternal mod |
362+
PointsToInternal::pointsTo(imp.(ImportMemberNode).getModule(name), ctx, mod, _) and
363+
common_module_name(mod.getName() + "." + name)
364+
)
365+
}
366+
367+
predicate common_module_name(string name) {
368+
name = "zope.interface"
369+
or
370+
name = "six.moves"
371+
}
372+
330373
library class ClassDecl extends @py_object {
331374

332375
ClassDecl() {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ module PointsTo {
130130
PointsToInternal::pointsTo(f, context, value, origin) and
131131
cls = value.getClass().getSource() |
132132
obj = value.getSource() or
133-
not exists(value.getSource()) and obj = origin
133+
not exists(value.getSource()) and not value.isMissing() and obj = origin
134134
)
135135
or
136136
/* Backwards compatibility for *args and **kwargs */

python/ql/src/semmle/python/security/Exceptions.qll

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,8 @@ import python
77
import semmle.python.security.TaintTracking
88
import semmle.python.security.strings.Basic
99

10-
private ModuleObject theTracebackModule() {
11-
result.getName() = "traceback"
12-
}
13-
14-
private FunctionObject traceback_function(string name) {
15-
result = theTracebackModule().attr(name)
10+
private Value traceback_function(string name) {
11+
result = Module::named("traceback").attr(name)
1612
}
1713

1814
/**
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
| absent.py:3:8:3:11 | ControlFlowNode for ImportExpr | Missing module xxxx |
2+
| absent.py:4:1:4:4 | ControlFlowNode for xxxx | Missing module xxxx |
3+
| absent.py:6:6:6:9 | ControlFlowNode for ImportExpr | Missing module xxxx |
4+
| absent.py:6:18:6:21 | ControlFlowNode for ImportMember | Missing module attribute xxxx.open |
5+
| absent.py:8:1:8:4 | ControlFlowNode for open | Missing module attribute xxxx.open |
6+
| absent.py:12:8:12:13 | ControlFlowNode for ImportExpr | Module module |
7+
| absent.py:14:1:14:6 | ControlFlowNode for module | Module module |
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
import python
3+
import semmle.python.objects.Modules
4+
5+
from Value val, ControlFlowNode f
6+
where //val = Value::named(name) and
7+
f.pointsTo(val)
8+
select f, val
9+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#There is no xxxx, rely on AbsentModule
2+
3+
import xxxx
4+
xxxx
5+
6+
from xxxx import open
7+
8+
open()
9+
10+
11+
#This is be present, so shouldn't be missing
12+
import module
13+
14+
module

python/ql/test/library-tests/PointsTo/absent/module.py

Whitespace-only changes.

0 commit comments

Comments
 (0)