New points-to and object model for Python.#1277
Conversation
5278da6 to
a7029ab
Compare
…n functions. Move attribute lookup handling to objects.
… Tweak API to be a bit more backward-compatible.
taus-semmle
left a comment
There was a problem hiding this comment.
First part of review.
taus-semmle
left a comment
There was a problem hiding this comment.
Finished review of ObjectInternal.qll.
…arifying a few comments.
taus-semmle
left a comment
There was a problem hiding this comment.
This completes the review of everything in /objects (and also includes a bunch of comments in PointsTo.qll, as there was no easy way to separate these).
| /** Gets the `n`th item of this sequence, if one exists. */ | ||
| abstract ObjectInternal getItem(int n); | ||
|
|
||
| /** The boolean value of this object, this may be both |
There was a problem hiding this comment.
This and all other docstrings that are identical to the ones on the classes they extend would be better if removed altogether. As I understand it, the docstring on the base class will be shown instead.
| override string toString() { | ||
| this.length() = 0 and result = "()" | ||
| or | ||
| result = "(" + this.contents(0) + ")" |
There was a problem hiding this comment.
Minor comment, but should we show 1-element tuples as (foo,) the way Python does it? I know it's not the prettiest syntax, but it is unambiguous (and possibly more familiar to Python users).
|
|
||
| override predicate calleeAndOffset(Function scope, int paramOffset) { none() } | ||
|
|
||
| override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() } |
There was a problem hiding this comment.
Would we need to extend this in order to support e.g. sys.version_info.major, or is that handled through some other means?
There was a problem hiding this comment.
Yes.
I've not seen any tests on sys.version_info.major, so I doubt it matters in practice.
We want to treat sys.version_info as an opaque object, to prevent premature pruning and
false positives when we are unsure of the actual version of Python that the code is expecting.
I've added a QL comment.
| reverse_step(this, Empty(), result) | ||
| } | ||
|
|
||
| boolean isSpecial() { |
There was a problem hiding this comment.
This should maybe be called containsSpecial or hasSpecial, and have an explanatory comment?
|
|
||
| /** Holds if this is a subclass of the `Iterable` abstract base class. */ | ||
| boolean isIterableSubclass() { | ||
| this = ObjectInternal::builtin("list") and result = true |
There was a problem hiding this comment.
Minor point, but this could be written more succinctly by putting result = true in a conjunction outside the first three disjuncts. This way is probably better for readability, though.
| origin = CfgOrigin::unknown() | ||
| } | ||
|
|
||
| pragma [noinline] override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) { |
There was a problem hiding this comment.
cls should be named instance in order to match up with the inherited docstring. (Alternatively this could have its own docstring.)
| exists(Module init | | ||
| init = this.getSourceModule() and | ||
| ( | ||
| not exists(EssaVariable var | var.getAUse() = init.getANormalExit() and var.getSourceVariable().getName() = name) |
There was a problem hiding this comment.
This line seems somewhat mysterious. Could you add an explanatory comment?
|
|
||
| /** Gets a call to this object */ | ||
| CallNode getACall() { | ||
| PointsToInternal::pointsTo(result.getFunction(), _, this, _) |
There was a problem hiding this comment.
It looks to me like this body could be replaced with simply result = this.getACall(_).
| * @classmethod | ||
| * def f(cls): pass | ||
| * ``` | ||
| * `this.lookup("f")` is equivent to `C.__dict__['f']`, which is the class-method |
taus-semmle
left a comment
There was a problem hiding this comment.
Done with the review of the test files.
| @@ -1,3 +1,5 @@ | |||
| WARNING: Predicate points_to has been deprecated and may be removed in future (BooleanConstants.ql:8,5-24) | |||
There was a problem hiding this comment.
This should probably not be in the .expected file.
There was a problem hiding this comment.
qltest emits the warning so it has to be in the expected output.
We could update the test to use the new API, but I want to keep the diff on expected outputs small for this PR.
| @@ -0,0 +1,27 @@ | |||
| | 2 | bool False | | |||
There was a problem hiding this comment.
This seems to be a false positive.
There was a problem hiding this comment.
It is. Let me see if it is feasible to fix.
| @@ -1,3 +1,6 @@ | |||
| WARNING: Type CustomPointsToAttribute has been deprecated and may be removed in future (Extend.ql:26,35-58) | |||
There was a problem hiding this comment.
I think it would be better if our tests did not rely on deprecated features (and emit warnings about this). Would rewriting these to use PointsToExtension be too time-consuming?
(If so, I'm happy to accept these warnings temporarily, given the time constraints.)
There was a problem hiding this comment.
We still need to test the deprecated API, so we have to endure the warnings.
| @@ -1,2 +1 @@ | |||
| | expressions_test.py:51:4:51:11 | Compare | The result of this comparison with 'is' may differ between implementations of Python. | | |||
| | expressions_test.py:56:4:56:16 | Compare | The result of this comparison with 'is' may differ between implementations of Python. | | |||
There was a problem hiding this comment.
This looks to (now) be a false negative, but it doesn't look terribly serious. Is this right?
There was a problem hiding this comment.
That was arguably a false positive and is now correct.
The assumption being that if an object is declared locally then an is comparison is OK as it is testing for identity. E.g.
SENTINEL = object()
...
if x is SENTINEL:
...
5e64b9b to
71ae61c
Compare
taus-semmle
left a comment
There was a problem hiding this comment.
Finished review of PointsTo.qll. I believe this completes the reviewing.
| /** Helper for `scope_entry_value_transfer`. */ | ||
| private predicate class_entry_value_transfer(EssaVariable pred_var, ScopeEntryDefinition succ_def) { | ||
| exists(ImportTimeScope scope, ControlFlowNode class_def | | ||
| class_def = pred_var. |
b4eae7f to
b63d031
Compare
b63d031 to
8e2d6c4
Compare
New points-to and object model for Python.