Skip to content

Python: Add type tracker and step summary implementation.#3961

Merged
calumgrant merged 13 commits intogithub:mainfrom
tausbn:python-add-typetracker
Sep 2, 2020
Merged

Python: Add type tracker and step summary implementation.#3961
calumgrant merged 13 commits intogithub:mainfrom
tausbn:python-add-typetracker

Conversation

@tausbn
Copy link
Contributor

@tausbn tausbn commented Jul 17, 2020

WIP (Can be merged for further development, but the tests don't currently yield the correct results.)

This represents a first stab at using the TypeTracker interface for tracking custom types. It reuses the underlying implementation of local flow steps that is defined in DataFlowPrivate. (This should probably be split out into a more public part, but for now we're just importing it directly.)

There are a few issues that still need to be fixed before this can be used fully:

Type tracking into and out of attributes.

When we've tracked some custom type to x and we do foo.bar = x, we want to continue tracking the fact that foo is an object whose bar property has the type associated with x. Likewise, a read of foo.bar now results in a node that tracks this same custom type. These steps are handled by basicStoreStep and basicLoadStep which are currently not implemented.

Missing flow

Although it appears that we are correctly resolving calls and returns, in the given test file we do not manage to track the custom type into the use_tracked function correctly. It's not clear to me where this flow is going missing.

Spurious flow

Looking at the StepSummary::step function, we see flow from e.g. the SSA variable x that is assigned in baz, to the exit node for the function baz itself. This does not seem entirely right to me (and I think the issue here is in simpleLocalFlowStep -- @yoff may want to take a look at this case).

@tausbn tausbn added the Python label Jul 17, 2020
@adityasharad adityasharad changed the base branch from master to main August 14, 2020 18:33
Copy link
Contributor

@yoff yoff left a comment

Choose a reason for hiding this comment

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

Got curious, looks like a good start :-)

module StepSummary {
cached
predicate step(Node pred, Node succ, StepSummary summary) {
exists(Node mid | simpleLocalFlowStep(pred, mid) and smallstep(mid, succ, summary))
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 a little odd, are you requiring a local step in between all other steps (even local ones)?

tausbn added 4 commits August 27, 2020 17:05
Nodes to which we track type tracking flow from the source (any
identifier named `tracked`) are indicated with a `$tracked` tag, and
`$tracked=attr_name` if the attribute is for the specified attribute
of the given node.

For nodes that do have flow from `tracked`, I indicate this in one of
two ways:

- If it's expected due to the design of type tracking, I omit the
  `$tracked tag.
- If it's flow that _ought_ to be there, I indicate it as a false
  negative: `$f-:tracked`

Currently, only an instance of global flow is in the latter category.
@tausbn tausbn marked this pull request as ready for review August 28, 2020 18:01
@tausbn tausbn requested a review from a team as a code owner August 28, 2020 18:01
It is subsumed by `tracked.ql` anyway.
Copy link
Member

@RasmusWL RasmusWL left a comment

Choose a reason for hiding this comment

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

Overall looks good and well documented 👍

From my understanding, the current state only supports attribute access for a single depth. So x.foo.bar = tracked wouldn't work right? (if you could add a test case showing this, that would be super sweet)


General observation:

Most of the (new) dataflow library uses predicate someStep(Node nodeFrom, Node nodeTo). I'm not specifically confused by this code using pred and succ as the names, but I thought it might be cool to be consistent across the new library code we are writing? 😊

*
* A description of a step on an inter-procedural data flow path.
*/
class StepSummary extends TStepSummary {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
class StepSummary extends TStepSummary {
private class StepSummary extends TStepSummary {

Not sure whether this class needs to be used by other ql files, but marking it as private would be an easy way to ensure it's only used internally 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the JS libs, these files are in an internal directory, and generally I don't see any reason to expose them, so yeah, private makes a lot of sense here.

}

/**
* A utility class that is equivalent to `boolean` but does not require type joining.
Copy link
Member

Choose a reason for hiding this comment

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

Can you expand the comment to explain what the problem is? I don't quite understand it at least 😐

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This comes straight from the JavaScript libraries, so I'm not 100% what the intent is, but I think the issue is that if you write

private newtype TTypeTracker = MkTypeTracker(boolean hasCall, OptionalAttributeName prop)

(note lowercase boolean) the compiler will complain about hasCall not being sufficiently bound. This is because boolean is treated the same way as, say, int or string for the purposes of checking binding, even though boolean only has two possible values. By encapsulating it in a utility class, we avoid having to specify hasCall = true or hasCall = false in the above definition. (Which, in isolation, is probably not a large gain, but I imagine it could be useful if we start using booleans elsewhere.)

Copy link
Member

@RasmusWL RasmusWL Aug 31, 2020

Choose a reason for hiding this comment

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

right, I see. Thanks. If you could add some of that nice explanation into the comment in the code that could be really good! 💪

/**
* A utility class that is equivalent to `boolean` but does not require type joining.
*/
private class Boolean extends boolean {
Copy link
Contributor

Choose a reason for hiding this comment

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

Could put this into a util 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.

Sure. I was going to wait until we get another place where Boolean is useful, and then find a good home for it then. 🙂 (In the JS libs, it's just unceremoniously plopped in the middle of FlowSteps.qll.)

Copy link
Contributor

@calumgrant calumgrant left a comment

Choose a reason for hiding this comment

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

Great work @tausbn!

@calumgrant calumgrant dismissed RasmusWL’s stale review September 2, 2020 08:42

Comments addressed.

@calumgrant calumgrant merged commit 29b3759 into github:main Sep 2, 2020

/** Holds if `nodeFrom` steps to `nodeTo` by being passed as a parameter in a call. */
predicate callStep(ArgumentNode nodeFrom, ParameterNode nodeTo) {
// TODO: Support special methods?
Copy link
Contributor

Choose a reason for hiding this comment

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

Has this been resolved?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not to the extent that type tracking through special method invocations currently works correctly, but we're also still in the process of making sure special methods are supported in the rest of the dataflow framework. Once this has been done, we can start adding type tracking support for this as well.

@tausbn tausbn deleted the python-add-typetracker branch February 12, 2021 18:03
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.

5 participants