Skip to content

Conversation

@markshannon
Copy link
Contributor

@markshannon markshannon commented Apr 24, 2019

New points-to and object model for Python.

  • Well factored object model separating internal and external API for objects
  • Points-to is simplified a bit as it is more focussed on flow and inheritance and less on object semantics.
  • Minimal changes to queries and query tests, queries still use old API which is almost completely backwards compatible

@markshannon markshannon added WIP This is a work-in-progress, do not merge yet! Python labels Apr 24, 2019
@markshannon markshannon force-pushed the python-ipa-objects-bottom-up branch from 5278da6 to a7029ab Compare April 24, 2019 13:20
…n functions. Move attribute lookup handling to objects.
… Tweak API to be a bit more backward-compatible.
@markshannon markshannon removed the WIP This is a work-in-progress, do not merge yet! label May 16, 2019
Copy link
Contributor

@taus-semmle taus-semmle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First part of review.

Copy link
Contributor

@taus-semmle taus-semmle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finished review of ObjectInternal.qll.

Copy link
Contributor

@taus-semmle taus-semmle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) + ")"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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() }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would we need to extend this in order to support e.g. sys.version_info.major, or is that handled through some other means?

Copy link
Contributor Author

@markshannon markshannon May 28, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line seems somewhat mysterious. Could you add an explanatory comment?


/** Gets a call to this object */
CallNode getACall() {
PointsToInternal::pointsTo(result.getFunction(), _, this, _)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

equivalent

@taus-semmle taus-semmle added this to the 1.21.0 milestone May 28, 2019
Copy link
Contributor

@taus-semmle taus-semmle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably not be in the .expected file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be a false positive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is. Let me see if it is feasible to fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -1,3 +1,6 @@
WARNING: Type CustomPointsToAttribute has been deprecated and may be removed in future (Extend.ql:26,35-58)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks to (now) be a false negative, but it doesn't look terribly serious. Is this right?

Copy link
Contributor Author

@markshannon markshannon May 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:
    ...

@markshannon markshannon force-pushed the python-ipa-objects-bottom-up branch from 5e64b9b to 71ae61c Compare May 29, 2019 14:05
Copy link
Contributor

@taus-semmle taus-semmle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

base classes

@markshannon markshannon force-pushed the python-ipa-objects-bottom-up branch from b4eae7f to b63d031 Compare May 30, 2019 16:49
@markshannon markshannon force-pushed the python-ipa-objects-bottom-up branch from b63d031 to 8e2d6c4 Compare May 31, 2019 14:59
@taus-semmle taus-semmle merged commit 8e2d6c4 into github:master Jun 3, 2019
@markshannon markshannon deleted the python-ipa-objects-bottom-up branch June 3, 2019 17:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants