Python points-to: Improve handling of subscripts and sequence inequalities.

This commit is contained in:
Mark Shannon
2019-04-24 16:50:54 +01:00
parent 674a3da4b8
commit 3bb61e7410
12 changed files with 169 additions and 19 deletions

View File

@@ -54,6 +54,8 @@ abstract class CallableObjectInternal extends ObjectInternal {
abstract predicate neverReturns();
override predicate subscriptUnknown() { none() }
}

View File

@@ -75,6 +75,7 @@ abstract class ClassObjectInternal extends ObjectInternal {
result = false
}
override predicate subscriptUnknown() { none() }
}
class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject {

View File

@@ -43,6 +43,8 @@ abstract class ConstantObjectInternal extends ObjectInternal {
pragma [noinline] override predicate attributesUnknown() { none() }
override predicate subscriptUnknown() { none() }
override boolean isDescriptor() { result = false }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }

View File

@@ -53,6 +53,8 @@ class PropertyInternal extends ObjectInternal, TProperty {
pragma [noinline] override predicate attributesUnknown() { none() }
override predicate subscriptUnknown() { none() }
override boolean isDescriptor() { result = true }
override int length() { none() }
@@ -133,6 +135,8 @@ class ClassMethodObjectInternal extends ObjectInternal, TClassMethod {
pragma [noinline] override predicate attributesUnknown() { none() }
override predicate subscriptUnknown() { none() }
override boolean isDescriptor() { result = true }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) {
@@ -207,6 +211,8 @@ class StaticMethodObjectInternal extends ObjectInternal, TStaticMethod {
pragma [noinline] override predicate attributesUnknown() { none() }
override predicate subscriptUnknown() { none() }
override boolean isDescriptor() { result = true }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) {

View File

@@ -102,6 +102,8 @@ class SpecificInstanceInternal extends TSpecificInstance, ObjectInternal {
pragma [noinline] override predicate attributesUnknown() { any() }
override predicate subscriptUnknown() { any() }
override boolean isDescriptor() { result = false }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
@@ -203,6 +205,8 @@ class SelfInstanceInternal extends TSelfInstance, ObjectInternal {
pragma [noinline] override predicate attributesUnknown() { any() }
override predicate subscriptUnknown() { any() }
override boolean isDescriptor() { result = false }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
@@ -305,6 +309,8 @@ class UnknownInstanceInternal extends TUnknownInstance, ObjectInternal {
pragma [noinline] override predicate attributesUnknown() { any() }
override predicate subscriptUnknown() { any() }
override boolean isDescriptor() { result = false }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
@@ -385,6 +391,8 @@ class SuperInstance extends TSuperInstance, ObjectInternal {
pragma [noinline] override predicate attributesUnknown() { none() }
override predicate subscriptUnknown() { any() }
override boolean isDescriptor() { result = false }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }

View File

@@ -45,6 +45,8 @@ abstract class ModuleObjectInternal extends ObjectInternal {
override int length() { none() }
override predicate subscriptUnknown() { any() }
}
class BuiltinModuleObjectInternal extends ModuleObjectInternal, TBuiltinModuleObject {

View File

@@ -63,7 +63,7 @@ class ObjectInternal extends TObject {
*/
abstract int intValue();
/** The integer value of things that have integer values.
/** The string value of things that have string values.
* That is, strings.
*/
abstract string strValue();
@@ -78,6 +78,8 @@ class ObjectInternal extends TObject {
abstract predicate attributesUnknown();
abstract predicate subscriptUnknown();
/** For backwards compatibility shim -- Not all objects have a "source".
* Objects (except unknown and undefined values) should attempt to return
* exactly one result for this method.
@@ -174,6 +176,10 @@ class BuiltinOpaqueObjectInternal extends ObjectInternal, TBuiltinOpaqueObject {
pragma [noinline] override predicate attributesUnknown() { none() }
override predicate subscriptUnknown() {
exists(this.getBuiltin().getItem(_))
}
override boolean isDescriptor() { result = false }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
@@ -247,6 +253,8 @@ class UnknownInternal extends ObjectInternal, TUnknown {
pragma [noinline] override predicate attributesUnknown() { any() }
override predicate subscriptUnknown() { any() }
override boolean isDescriptor() { result = false }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
@@ -321,6 +329,8 @@ class UndefinedInternal extends ObjectInternal, TUndefined {
pragma [noinline] override predicate attributesUnknown() { none() }
override predicate subscriptUnknown() { none() }
override boolean isDescriptor() { none() }
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
@@ -378,7 +388,10 @@ module ObjectInternal {
ObjectInternal fromBuiltin(Builtin b) {
b = result.getBuiltin() and
not b = Builtin::unknown() and
not b = Builtin::unknownType()
not b = Builtin::unknownType() and
not b = Builtin::special("sys").getMember("version_info")
or
b = Builtin::special("sys").getMember("version_info") and result = TSysVersionInfo()
}
ObjectInternal classMethod() {

View File

@@ -87,6 +87,8 @@ abstract class TupleObjectInternal extends SequenceObjectInternal {
pragma [noinline] override predicate attributesUnknown() { none() }
override predicate subscriptUnknown() { none() }
}
class BuiltinTupleObjectInternal extends TBuiltinTuple, TupleObjectInternal {
@@ -146,4 +148,80 @@ class PythonTupleObjectInternal extends TPythonTuple, TupleObjectInternal {
}
class SysVersionInfoObjectInternal extends TSysVersionInfo, SequenceObjectInternal {
override string toString() {
result = "sys.version_info"
}
override ObjectInternal getItem(int n) {
n = 0 and result = TInt(major_version())
or
n = 1 and result = TInt(minor_version())
}
override predicate introduced(ControlFlowNode node, PointsToContext context) { none() }
/** Gets the class declaration for this object, if it is a declared class. */
override ClassDecl getClassDeclaration() {
result = Builtin::special("sys").getMember("version_info").getClass()
}
/** True if this "object" is a class. */
override boolean isClass() { result = false }
override ObjectInternal getClass() {
result.getBuiltin() = this.getClassDeclaration()
}
override boolean isComparable() {
result = true
}
/** Gets the `Builtin` for this object, if any.
* Objects (except unknown and undefined values) should attempt to return
* exactly one result for either this method or `getOrigin()`.
*/
override Builtin getBuiltin() { none() }
/** Gets a control flow node that represents the source origin of this
* objects.
*/
override ControlFlowNode getOrigin() { none() }
/** Holds if `obj` is the result of calling `this` and `origin` is
* the origin of `obj`.
*/
override predicate callResult(ObjectInternal obj, CfgOrigin origin) { none() }
/** Holds if `obj` is the result of calling `this` and `origin` is
* the origin of `obj` with callee context `callee`.
*/
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { none() }
/** The integer value of things that have integer values.
* That is, ints and bools.
*/
override int intValue() { none() }
/** The integer value of things that have integer values.
* That is, strings.
*/
override string strValue() { none() }
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
override predicate attributesUnknown() { none() }
override predicate subscriptUnknown() { none() }
/** Gets the length of the sequence that this "object" represents.
* Always returns a value for a sequence, will be -1 if object has no fixed length.
*/
override int length() { result = 5 }
override predicate functionAndOffset(CallableObjectInternal function, int offset) { none() }
}

View File

@@ -136,6 +136,8 @@ newtype TObject =
not count(instantiation.getAnArg()) = 1 and
Types::getMro(metacls).contains(TType())
}
or
TSysVersionInfo()
private predicate is_power_2(int n) {
n = 1 or

View File

@@ -1096,8 +1096,17 @@ module Expressions {
predicate subscriptPointsTo(SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode origin, ControlFlowNode obj, ObjectInternal objvalue) {
subscr.isLoad() and
obj = subscr.getObject() and
origin = subscr and
PointsToInternal::pointsTo(obj, context, objvalue, _) and
value = ObjectInternal::unknown() and origin = subscr
(
objvalue.subscriptUnknown() and
value = ObjectInternal::unknown()
or
exists(int n |
PointsToInternal::pointsTo(subscr.getIndex(), context, TInt(n), _) and
value = objvalue.(SequenceObjectInternal).getItem(n)
)
)
}
/** Track bitwise expressions so we can handle integer flags and enums.
@@ -1256,17 +1265,11 @@ module Expressions {
exists(boolean strict, boolean sense, ObjectInternal other |
inequalityTest(comp, context, use, val, other, strict, sense)
|
val.intValue() < other.intValue() and result = sense
or
val.intValue() > other.intValue() and result = sense.booleanNot()
compare(val, other) = -1 and result = sense
or
val.intValue() = other.intValue() and result = strict.booleanXor(sense)
compare(val, other) = 0 and result = strict.booleanNot()
or
val.strValue() < other.strValue() and result = sense
or
val.strValue() > other.strValue() and result = sense.booleanNot()
or
val.strValue() = other.strValue() and result = strict.booleanXor(sense)
compare(val, other) = 1 and result = sense.booleanNot()
or
val.isComparable() = false and result = maybe()
or
@@ -1274,6 +1277,43 @@ module Expressions {
)
}
private int compare(ObjectInternal val, ObjectInternal other) {
inequalityTest(_, _, _, val, other, _, _) and
result = compare_unbound(val, other)
or
result = compare_sequence(val, other, 0)
}
bindingset[val, other]
private int compare_unbound(ObjectInternal val, ObjectInternal other) {
val.intValue() < other.intValue() and result = -1
or
val.intValue() > other.intValue() and result = 1
or
val.intValue() = other.intValue() and result = 0
or
val.strValue() < other.strValue() and result = -1
or
val.strValue() > other.strValue() and result = 0
or
val.strValue() = other.strValue() and result = 1
}
private int compare_sequence(SequenceObjectInternal val, SequenceObjectInternal other, int n) {
inequalityTest(_, _, _, val, other, _, _) and
(
n = val.length() and other.length() > n and result = -1
or
n = other.length() and val.length() > n and result = 1
or
n = other.length() and n = val.length() and result = 0
or
result != 0 and result = compare_unbound(val.getItem(n), val.getItem(n))
or
compare_unbound(val.getItem(n), val.getItem(n)) = 0 and result = compare_sequence(val, other, n+1)
)
}
pragma [noinline]
private predicate inequalityTest(CompareNode comp, PointsToContext context, ControlFlowNode operand, ObjectInternal opvalue, ObjectInternal other, boolean strict, boolean sense) {
exists(ControlFlowNode r |