Skip to content

Conversation

@asger-semmle
Copy link
Contributor

Spin-off from #760

@asger-semmle asger-semmle requested a review from a team as a code owner January 14, 2019 15:42
Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

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

LGTM. Two minor documentation concerns.
This requires a change note and a thorough evaluation.
If the taint tracking experiments with this change are inconclusive, you could try porting js/mixed-static-instance-this-access to get an additional data point.

* A data flow node corresponding to a class definition or a function definition
* acting as a class.
*
* The following patterns are recognized as classes and methods:
Copy link

Choose a reason for hiding this comment

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

Do we want a note here about how to extend the set of recognized patterns?

/**
* Gets an instance method with the given name, if any.
*/
abstract FunctionNode getAnInstanceMethod(string name);
Copy link

Choose a reason for hiding this comment

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

I think we should mention that the prototype chains are not traversed for these lookups.
I am not sure if the prototype traversal should be implicit or explicit one day.

@asger-semmle
Copy link
Contributor Author

asger-semmle commented Jan 15, 2019

To clarify, this PR just contains the ClassNode as you requested it be split into its own PR. There is no code using it, so it can't be evaluated on its own.

And this is exactly why I included it in #760.

you could try porting js/mixed-static-instance-this-access to get an additional data point.

I don't see why I should first put this in its own PR and then bundle it something else? If we wanted it bundled with the use-case, we had #760.

Copy link

@xiemaisi xiemaisi left a comment

Choose a reason for hiding this comment

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

LGTM, with minor suggestion for simplification.

result = method.getBody().flow()
)
or
result = getAPropertyWrite(name).getRhs().getALocalSource()

Choose a reason for hiding this comment

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

Suggested change
result = getAPropertyWrite(name).getRhs().getALocalSource()
result = getAPropertySource(name)

Choose a reason for hiding this comment

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

Ditto below.

@ghost
Copy link

ghost commented Jan 15, 2019

I don't see why I should first put this in its own PR and then bundle it something else? If we wanted it bundled with the use-case, we had #760.

To clarify:
I agree that the performance for this change probably is fine, but:

The performance of #760 was characterized as:

Evaluation shows no result changes but a little bit of performance to investigate.

I suspect the performance hiccups are mainly caused by to the two other commits of #760 then. The suggested port of js/mixed-static-instance-this-access would have produced a cleaner data point.
(Furthermore, this is even a significant rewrite of the ClassNode compared to the version used in the evaluation of #760.)

@asger-semmle
Copy link
Contributor Author

asger-semmle commented Jan 16, 2019

I tried integrating it with js/mixed-static-instance-this-access but we get a large number of false positives.
Edit: this commit was used for the evaluation.

One particular problem is that we can't tell if a static member is intended to be used as a "named constructor", like here.

@ghost
Copy link

ghost commented Jan 16, 2019

Hmm. Thanks for trying. But at least it is now clear that the implementation scales.

@asger-semmle
Copy link
Contributor Author

asger-semmle commented Jan 16, 2019

I've pushed a commit that adds getADirectSuperClass() since it was needed for the query so we might as well keep it, even if the query changes didn't work out.

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

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

Changes LGTM, but there is one test failure.

ghost
ghost previously approved these changes Jan 17, 2019
*
* Does not include methods from superclasses.
*/
FunctionNode getAnInstanceMethod(string name) { result = impl.getAnInstanceMethod(name) }

Choose a reason for hiding this comment

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

Here and below, I wonder whether it is really worth including "a"/"an" in the predicate name and doc comment. Of course, it is technically correct since we don't assume/enforce uniqueness, but in the majority of cases we probably would expect the result to be unique, so having an overly general name might lead to confusion and bad auto-complete experience.

What do you think?

(We should, of course, still mention the possibility of multiple results in the doc comment.)

Copy link

Choose a reason for hiding this comment

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

I considered this as well, for the same reasons, but I think "a"/"an" should be used here.

Some arguments for:

  • the rest of the SourceNode getters use that convention
  • multiple prototypes are possible
  • the method definitions may be conditional
  • unlike ES6 classes, these class nodes are not always syntactic, the "a"/"an" prefix kind of reflects that
  • if we later add support for lookups in the prototype hierarchy, I think we want the "a/an" prefix, so it would be nice if we had some consistency between similar lookups

(this list is probably a rehash of what you already know)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm also against the a/an prefix. Even if it's technically possible, it's confusing and extremely rare in practice, and inconsistent with other APIs for things that are unique in practice.

Copy link

Choose a reason for hiding this comment

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

Ok. Let us remove it then.

@asger-semmle
Copy link
Contributor Author

I've reverted the a/an prefix from getInstanceMethod and getStaticMethod.

I've also excluded getters/setters from these predicates as that was the main situation where they had multiple returns, but it was in general unfortunate that you couldn't tell them apart using this API. I have instead introduced getInstanceMember and MemberKind to allow chainable access to any combination of methods/getter/setters. It's unfortunate that no commonly used name exists for "method or accessor" so I've just stuck with "member", even though constructors and fields aren't included.

Feel free to suggest another terminology, keeping in mind that DataFlow::MemberKind::method() is already quite a mouthful, so overly long names might not be the answer.

@esben-semmle @xiemaisi could you take another look at the latest commit?

@ghost ghost added the JS label Jan 20, 2019
@ghost
Copy link

ghost commented Jan 20, 2019

This looks good to go, but have you sanity checked the performance of the latest commit?

@ghost
Copy link

ghost commented Jan 21, 2019

Never mind. I keep forgetting that this is unevaluable..

@semmle-qlci semmle-qlci merged commit 0432b01 into github:master Jan 21, 2019
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.

3 participants