-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Python: Prevent bad TC and add a bit of caching #5535
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Using `simpleLocalFlowStep+` with the first argument specialised to `CfgNode` was causing the compiler to turn this into a very slowly converging manual TC computation. Instead, we use `simpleLocalFlowStep*` (which is fast) and then join that with a single step from any `CfgNode`. This should amount to the same thing. I also noticed that the charpred for `LocalSourceNode` was getting recomputed a lot, so this is now cached. (The recomputation was especially bad since it relied on `simpleLocalFlowStep+`, but anyway it's a good idea not to recompute this.)
A more principled approach is possible here, but in the short term this will prevent an explosion. For reference, openstack/cinder has roughly 19000 `ForTarget`s and tuples of size up to 5300, and we were calculating the cartesian product of these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
python/ql/src/semmle/python/dataflow/new/internal/DataFlowPrivate.qll
Outdated
Show resolved
Hide resolved
It's always a sad thing to see a good plan go wrong: 86860032 ~0% {4} r26 = JOIN r19 WITH DataFlowPublic::TupleElementContent#class#ff CARTESIAN PRODUCT OUTPUT Lhs.0 'nodeFrom', Lhs.1 'nodeTo', Rhs.0, Rhs.1 129256 ~3% {4} r27 = SELECT r26 ON In.3 <= 7 129256 ~0% {3} r28 = SCAN r27 OUTPUT In.0 'nodeFrom', In.2 'c', In.1 'nodeTo' Happily, now it looks like this: 129256 ~0% {3} r20 = JOIN r19 WITH DataFlowPrivate::small_tuple#f CARTESIAN PRODUCT OUTPUT Lhs.0 'nodeFrom', Rhs.0, Lhs.1 'nodeTo'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but the testing will tell..
) | ||
} | ||
|
||
pragma[noinline] | ||
TupleElementContent small_tuple() { result.getIndex() <= 7 } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did any special logic go into picking the value 7
? or could it just as well have been 10
? (either way, I would really appreciate a comment in the code explaining those details, so it's easy to figure out in 1 year time when we look at it again 😉 )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I originally said 10, then yoff said that might be a bit high, then I said 5 but then changed my mind and said 7 which we both agreed was a nice round number.
I don't expect this code to be around in a year's time, and ideally not even a month from now. We already have a plan for a more principled approach for this (mimicking the "any index"-ness of list element content), but in the short term restricting this value is the best way to avoid blowup.
This one is a bit awkward, since the previous version was supposed to improve indexing. Unfortunately this is vastly outweighed by the slow convergence of the TC. Right now we pay the cost of inverting the `hasFlowSource` relation, but this is still cheaper.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This version of hasLocalSource
looks much more natural to me.
Using
simpleLocalFlowStep+
with the first argument specialised toCfgNode
was causing the compiler to turn this into a very slowlyconverging manual TC computation.
Instead, we use
simpleLocalFlowStep*
(which is fast) and then jointhat with a single step from any
CfgNode
. This should amount to thesame thing.
I also noticed that the charpred for
LocalSourceNode
was gettingrecomputed a lot, so this is now cached. (The recomputation was
especially bad since it relied on
simpleLocalFlowStep+
, but anywayit's a good idea not to recompute this.)