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

Skip to content

Commit 6bbbb85

Browse files
committed
Python: Remove some negation from points-to, in preparation for ADT Objects.
1 parent 821a7bf commit 6bbbb85

4 files changed

Lines changed: 89 additions & 47 deletions

File tree

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

Lines changed: 69 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,15 @@ module PointsTo {
139139
var.getSourceVariable().getName() = name and
140140
ssa_variable_points_to(var, imp, obj, cls, orig) and
141141
imp.isImport() and
142-
not obj = undefinedVariable() |
142+
obj != undefinedVariable() |
143143
origin = origin_from_object_or_here(orig, exit)
144144
)
145145
or
146146
not exists(EssaVariable var | var.getAUse() = m.getANormalExit() and var.getSourceVariable().getName() = name) and
147147
exists(EssaVariable var, PointsToContext imp |
148148
var.getAUse() = m.getANormalExit() and var.getSourceVariable().getName() = "*" |
149149
SSA::ssa_variable_named_attribute_points_to(var, imp, name, obj, cls, origin) and
150-
imp.isImport() and not obj = undefinedVariable()
150+
imp.isImport() and obj != undefinedVariable()
151151
)
152152
}
153153

@@ -257,7 +257,7 @@ module PointsTo {
257257
/** Holds if `f` is the instantiation of an object, `cls(...)`. */
258258
cached predicate instantiation(CallNode f, PointsToContext context, ClassObject cls) {
259259
points_to(f.getFunction(), context, cls, _, _) and
260-
not cls = theTypeType() and
260+
cls != theTypeType() and
261261
Types::callToClassWillReturnInstance(cls)
262262
}
263263

@@ -313,7 +313,7 @@ module PointsTo {
313313
)
314314
or
315315
exists(Object obj |
316-
not obj = undefinedVariable() and
316+
obj != undefinedVariable() and
317317
py_module_attributes(mod.getModule(), name, obj, _, _)
318318
) and result = true
319319
or
@@ -346,7 +346,7 @@ module PointsTo {
346346
private boolean package_exports_boolean(PackageObject pack, string name) {
347347
explicitly_imported(pack.submodule(name)) and
348348
(
349-
not exists(pack.getInitModule())
349+
pack.hasNoInitModule()
350350
or
351351
exists(ModuleObject init |
352352
pack.getInitModule() = init |
@@ -382,9 +382,11 @@ module PointsTo {
382382
exists(Object value |
383383
points_to(guard.getLastNode(), context, value, _, _)
384384
|
385-
guard.controls(b, true) and not value.booleanValue() = false
385+
guard.controls(b, _) and value.maybe()
386386
or
387-
guard.controls(b, false) and not value.booleanValue() = true
387+
guard.controls(b, true) and value.booleanValue() = true
388+
or
389+
guard.controls(b, false) and value.booleanValue() = false
388390
)
389391
or
390392
/* Assume the true edge of an assert is reachable (except for assert 0/False) */
@@ -403,9 +405,11 @@ module PointsTo {
403405
exists(ConditionBlock guard, Object value |
404406
points_to(guard.getLastNode(), context, value, _, _)
405407
|
406-
guard.controlsEdge(pred, succ, true) and not value.booleanValue() = false
408+
guard.controlsEdge(pred, succ, _) and value.maybe()
409+
or
410+
guard.controlsEdge(pred, succ, true) and value.booleanValue() = true
407411
or
408-
guard.controlsEdge(pred, succ, false) and not value.booleanValue() = true
412+
guard.controlsEdge(pred, succ, false) and value.booleanValue() = false
409413
)
410414
}
411415

@@ -554,7 +558,7 @@ module PointsTo {
554558
/** Gets an object pointed to by a use (of a variable). */
555559
private predicate use_points_to(NameNode f, PointsToContext context, Object value, ClassObject cls, ControlFlowNode origin) {
556560
exists(ObjectOrCfg origin_or_obj |
557-
not value = undefinedVariable() and
561+
value != undefinedVariable() and
558562
use_points_to_maybe_origin(f, context, value, cls, origin_or_obj) |
559563
origin = origin_from_object_or_here(origin_or_obj, f)
560564
)
@@ -578,7 +582,7 @@ module PointsTo {
578582
pragma [noinline]
579583
private predicate class_or_module_attribute(Object obj, string name, Object value, ClassObject cls, ObjectOrCfg orig) {
580584
/* Normal class attributes */
581-
Types::class_attribute_lookup(obj, name, value, cls, orig) and not cls = theStaticMethodType() and not cls = theClassMethodType()
585+
Types::class_attribute_lookup(obj, name, value, cls, orig) and cls != theStaticMethodType() and cls != theClassMethodType()
582586
or
583587
/* Static methods of the class */
584588
exists(CallNode sm | Types::class_attribute_lookup(obj, name, sm, theStaticMethodType(), _) and sm.getArg(0) = value and cls = thePyFunctionType() and orig = value)
@@ -849,9 +853,13 @@ module PointsTo {
849853
exists(Object operand |
850854
points_to(f.getOperand(), context, operand, _, _)
851855
|
852-
not operand.booleanValue() = true and value = theTrueObject()
856+
operand.maybe() and value = theTrueObject()
857+
or
858+
operand.maybe() and value = theFalseObject()
859+
or
860+
operand.booleanValue() = false and value = theTrueObject()
853861
or
854-
not operand.booleanValue() = false and value = theFalseObject()
862+
operand.booleanValue() = true and value = theFalseObject()
855863
)
856864
}
857865

@@ -999,17 +1007,18 @@ module PointsTo {
9991007
pragma [noinline]
10001008
predicate call_points_to_builtin_function(CallNode f, PointsToContext context, Object value, ClassObject cls, ControlFlowNode origin) {
10011009
exists(BuiltinCallable b |
1002-
not b = builtin_object("isinstance") and
1003-
not b = builtin_object("issubclass") and
1004-
not b = builtin_object("callable") and
1010+
b != builtin_object("isinstance") and
1011+
b != builtin_object("issubclass") and
1012+
b != builtin_object("callable") and
10051013
f = get_a_call(b, context) and
10061014
cls = b.getAReturnType()
10071015
) and
10081016
f = origin and
1009-
if cls = theNoneType() then
1010-
value = theNoneObject()
1011-
else
1012-
value = f
1017+
(
1018+
cls = theNoneType() and value = theNoneObject()
1019+
or
1020+
cls != theNoneType() and value = f
1021+
)
10131022
}
10141023

10151024
/** Holds if call is to an object that always returns its first argument.
@@ -1156,7 +1165,7 @@ module PointsTo {
11561165
cls != theSuperType() and
11571166
exists(Object o |
11581167
/* list.__init__() is not a call to type.__init__() */
1159-
not o instanceof ClassObject |
1168+
o.notClass() |
11601169
points_to(n.(AttrNode).getObject(name), context, o, cls, _)
11611170
)
11621171
or
@@ -1199,12 +1208,14 @@ module PointsTo {
11991208

12001209
/** Holds if `func` implicitly returns the `None` object */
12011210
predicate implicitly_returns(PyFunctionObject func, Object none_, ClassObject noneType) {
1202-
noneType = theNoneType() and not func.getFunction().isGenerator() and none_ = theNoneObject() and
1203-
(
1204-
not exists(func.getAReturnedNode()) and exists(func.getFunction().getANormalExit())
1205-
or
1206-
exists(Return ret | ret.getScope() = func.getFunction() and not exists(ret.getValue()))
1207-
)
1211+
noneType = theNoneType() and none_ = theNoneObject() and
1212+
exists(Function f |
1213+
f = func.getFunction() and not f.isGenerator()
1214+
|
1215+
not exists(Return ret | ret.getScope() = f) and exists(f.getANormalExit())
1216+
or
1217+
exists(Return ret | ret.getScope() = f and not exists(ret.getValue()))
1218+
)
12081219
}
12091220

12101221
}
@@ -1240,7 +1251,10 @@ module PointsTo {
12401251
* is available to all functions. Although not strictly true, this gives less surprising
12411252
* results in practice. */
12421253
pred_context.isMain() and pred_scope instanceof Module and succ_context.fromRuntime() and
1243-
not strictcount(pred_var.getSourceVariable().(Variable).getAStore()) > 1
1254+
exists(Variable v |
1255+
v = pred_var.getSourceVariable() and
1256+
not strictcount(v.getAStore()) > 1
1257+
)
12441258
)
12451259
or
12461260
exists(NonEscapingGlobalVariable var |
@@ -1567,8 +1581,8 @@ module PointsTo {
15671581
deco = f.getADecorator().getAFlowNode() |
15681582
exists(Object o |
15691583
points_to(deco, _, o, _, _) |
1570-
not o = theStaticMethodType() and
1571-
not o = theClassMethodType()
1584+
o != theStaticMethodType() and
1585+
o != theClassMethodType()
15721586
)
15731587
or not deco instanceof NameNode
15741588
)
@@ -1585,7 +1599,7 @@ module PointsTo {
15851599
|
15861600
obj instanceof ClassObject and value = obj and cls = objcls
15871601
or
1588-
not obj instanceof ClassObject and value = objcls and cls = Types::class_get_meta_class(objcls)
1602+
obj.notClass() and value = objcls and cls = Types::class_get_meta_class(objcls)
15891603
)
15901604
}
15911605

@@ -1703,16 +1717,17 @@ module PointsTo {
17031717
call = def.getCall() and
17041718
var = def.getSourceVariable() and
17051719
context.untrackableCall(call) and
1706-
exists(PyFunctionObject modifier |
1720+
exists(PyFunctionObject modifier, Function f |
1721+
f = modifier.getFunction() and
17071722
call = get_a_call(modifier, context) and
1708-
not modifies_escaping_variable(modifier, var)
1723+
not modifies_escaping_variable(f, var)
17091724
)
17101725
)
17111726
}
17121727

1713-
private predicate modifies_escaping_variable(FunctionObject modifier, PythonSsaSourceVariable var) {
1728+
private predicate modifies_escaping_variable(Function modifier, PythonSsaSourceVariable var) {
17141729
exists(var.redefinedAtCallSite()) and
1715-
modifier.getFunction().getBody().contains(var.(Variable).getAStore())
1730+
modifier.getBody().contains(var.(Variable).getAStore())
17161731
}
17171732

17181733
pragma [noinline]
@@ -2316,7 +2331,7 @@ module PointsTo {
23162331
or
23172332
cls = theObjectType() and result = 0
23182333
or
2319-
exists(builtin_base_type(cls)) and not cls = theObjectType() and result = 1
2334+
exists(builtin_base_type(cls)) and cls != theObjectType() and result = 1
23202335
or
23212336
cls = theUnknownType() and result = 1
23222337
}
@@ -2472,7 +2487,7 @@ module PointsTo {
24722487
/** INTERNAL -- Use `ClassObject.declaredAttribute(name). instead. */
24732488
cached predicate class_declared_attribute(ClassObject owner, string name, Object value, ClassObject vcls, ObjectOrCfg origin) {
24742489
/* Note that src_var must be a local variable, we aren't interested in the value that any global variable may hold */
2475-
not value = undefinedVariable() and
2490+
value != undefinedVariable() and
24762491
exists(EssaVariable var, LocalVariable src_var |
24772492
var.getSourceVariable() = src_var and
24782493
src_var.getId() = name and
@@ -2557,7 +2572,12 @@ module PointsTo {
25572572
or
25582573
exists(int i | failed_inference(class_base_type(cls, i), _) and reason = "Failed inference for base class at position " + i)
25592574
or
2560-
exists(int i | strictcount(class_base_type(cls, i)) > 1 and reason = "Multiple bases at position " + i)
2575+
exists(int i, Object base1, Object base2 |
2576+
base1 = class_base_type(cls, i) and
2577+
base2 = class_base_type(cls, i) and
2578+
base1 != base2 and
2579+
reason = "Multiple bases at position " + i
2580+
)
25612581
or
25622582
exists(int i, int j | class_base_type(cls, i) = class_base_type(cls, j) and i != j and reason = "Duplicate bases classes")
25632583
or
@@ -2577,7 +2597,7 @@ module PointsTo {
25772597

25782598
private ClassObject declared_meta_class(ClassObject cls) {
25792599
exists(Object obj |
2580-
ssa_variable_points_to(metaclass_var(cls), _, obj, _, _) |
2600+
ssa_variable_points_to(metaclass_var(cls.getPyClass()), _, obj, _, _) |
25812601
result = obj
25822602
or
25832603
obj = unknownValue() and result = theUnknownType()
@@ -2593,28 +2613,30 @@ module PointsTo {
25932613

25942614
private boolean has_metaclass_var_metaclass(ClassObject cls) {
25952615
exists(Object obj |
2596-
ssa_variable_points_to(metaclass_var(cls), _, obj, _, _) |
2616+
ssa_variable_points_to(metaclass_var(cls.getPyClass()), _, obj, _, _) |
25972617
obj = undefinedVariable() and result = false
25982618
or
25992619
obj != undefinedVariable() and result = true
26002620
)
26012621
or
2602-
not exists(metaclass_var(cls)) and result = false
2622+
exists(Class pycls |
2623+
pycls = cls.getPyClass() and
2624+
not exists(metaclass_var(pycls)) and result = false
2625+
)
26032626
}
26042627

26052628
private boolean has_declared_metaclass(ClassObject cls) {
26062629
py_cobjecttypes(cls, _) and result = true
26072630
or
2608-
not cls.isBuiltin() and
26092631
result = has_six_add_metaclass(cls).booleanOr(has_metaclass_var_metaclass(cls))
26102632
}
26112633

2612-
private EssaVariable metaclass_var(ClassObject cls) {
2613-
result.getASourceUse() = cls.getPyClass().getMetaClass().getAFlowNode()
2634+
private EssaVariable metaclass_var(Class cls) {
2635+
result.getASourceUse() = cls.getMetaClass().getAFlowNode()
26142636
or
2615-
major_version() = 2 and not exists(cls.getPyClass().getMetaClass()) and
2637+
major_version() = 2 and not exists(cls.getMetaClass()) and
26162638
result.getName() = "__metaclass__" and
2617-
cls.getPyClass().(ImportTimeScope).entryEdge(result.getAUse(), _)
2639+
cls.(ImportTimeScope).entryEdge(result.getAUse(), _)
26182640
}
26192641

26202642
private ClassObject get_inherited_metaclass(ClassObject cls) {
@@ -2624,7 +2646,7 @@ module PointsTo {
26242646
exists(Object base |
26252647
base = class_base_type(cls, _) and
26262648
result = theUnknownType() |
2627-
not base instanceof ClassObject
2649+
base.notClass()
26282650
or
26292651
base = theUnknownType()
26302652
)

python/ql/src/semmle/python/types/ClassObject.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,10 @@ class ClassObject extends Object {
392392
result.getFunction().refersTo(this)
393393
}
394394

395+
predicate notClass() {
396+
none()
397+
}
398+
395399
}
396400

397401
/** The 'str' class. This is the same as the 'bytes' class for

python/ql/src/semmle/python/types/ModuleObject.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,14 @@ class PackageObject extends ModuleObject {
226226
result.getModule() = this.getModule().getInitModule()
227227
}
228228

229+
/** Holds if this package has no `__init__.py` file. */
230+
predicate hasNoInitModule() {
231+
not exists(Module m |
232+
m.isPackageInit() and
233+
m.getFile().getParent() = this.getPath()
234+
)
235+
}
236+
229237
override predicate exportsComplete() {
230238
not exists(this.getInitModule())
231239
or

python/ql/src/semmle/python/types/Object.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,14 @@ class Object extends @py_object {
151151
)
152152
}
153153

154+
final predicate maybe() {
155+
not exists(this.booleanValue())
156+
}
157+
158+
predicate notClass() {
159+
any()
160+
}
161+
154162
/** Holds if this object can be referred to by `longName`
155163
* For example, the modules `dict` in the `sys` module
156164
* has the long name `sys.modules` and the name `os.path.join`

0 commit comments

Comments
 (0)