JS: Generalize global access paths to include local ones - #2224
Conversation
esbena
left a comment
There was a problem hiding this comment.
Wow. That is a nice generalisation.
I only have two optimizer-related comments.
| exists(Expr predExpr, Expr succExpr | | ||
| pred = valueNode(predExpr) and succ = valueNode(succExpr) | ||
| | | ||
| predExpr = succExpr.(ParExpr).getExpression() |
There was a problem hiding this comment.
Does it make the optimizer unhappy if we use Expr::getUnderlyingValue instead of all these explicit cases? (I know this is just a port of some steps, feel free to ignore)
There was a problem hiding this comment.
I don't know about the optimizer, but it doesn't do quite the same thing. getUnderlyingValue goes all the way to the bottom in one step, whereas we generally want the individual steps here.
For example, suppose you add type casts as a sanitizer in a data flow query. In this case, getUnderlyingValue would simply skip over the type cast, bypassing the sanitizer.
There was a problem hiding this comment.
Good point. I suppose we could look into letting Expr expose the non-recursive version as getImmediatelyUnderlyingValue in another PR.
| result = fromReference(node) | ||
| DataFlow::Node getAReferenceTo(Root root, string path) { | ||
| path = fromReference(result, root) and | ||
| not root.isGlobal() |
There was a problem hiding this comment.
Is not root.isGlobal() used to help the optimizer? Or is it just done to encourage not using DataFlow::globalAccessPathRootPseudoNode() explicitly?
There was a problem hiding this comment.
It's mainly to avoid exposing the pseudo-node, yes.
max-schaefer
left a comment
There was a problem hiding this comment.
LGTM, but I agree with Esben about doing a full evaluation.
|
There's an evaluation on default.slugs from a slightly earlier version but that's the security suite only. I'll do a full evaluation. |
8d9c34c to
cdd6825
Compare
|
@asger-semmle, I think you mentioned that there were new evaluation results? Or are you still rerunning? |
|
Here's the full evaluation. I messed up the re-run of the slowest slugs, a new one is underway. |
|
The re-run of the 10 slowest slugs looks much better. |
Co-Authored-By: Max Schaefer <54907921+max-schaefer@users.noreply.github.com>
cdd6825 to
81723ab
Compare
|
I'd like to merge this unless you have any further change requests @max-schaefer? |
Renames the
GlobalAccessPathmodule toAccessPathand generalizes it to deal with access paths relative to a givenSourceNoderoot.The predicates
GlobalAccessPath::{fromReference,fromRhs}are helpful internally, but felt clunky as part of the public API so we now exposeAccessPath::{getAReferenceTo,getAnAssignmentTo}instead.Type tracking can step through these access paths. This is modelled as store/loads edges that step into/out of the root node using the whole access path as if it was a single property name.
This means we treat
x.foo.barandx["foo.bar"]as the same thing, which is a bit sleazy but probably fine for type tracking purposes. We could tag the strings to avoid this potential clash if we're willing to pay the overhead.There is a modest performance cost and an equally modest number of new call edges.