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
Python: Model parameter with default value as DefinitionNode
#13685
base: main
Are you sure you want to change the base?
Python: Model parameter with default value as DefinitionNode
#13685
Conversation
They look pretty safe to me, but haven't given them a whole lot of thought.
d3e4dc7
to
70994b9
Compare
|
There might also be an option to fix this problem by using
But just rewriting the code to be the following didn't work as I wanted. Even though it fixes the missing flow to predicate capturedJumpStep(Node nodeFrom, Node nodeTo) {
exists(SsaSourceVariable var, EssaNodeDefinition essaDef, ControlFlowNode val |
essaDef.definedBy(var, val)
|
nodeTo.asVar().(ScopeEntryDefinition).getSourceVariable() = var and
nodeFrom.asCfgNode() = val and
var.getScope().getScope*() = nodeFrom.getScope()
)
}I pursued this approach a bit since I wasn't 100% happy about the I should have added some tests to highlight what the state of dataflow from default values were before this change, since I expect that it's handled to some degree, I just haven't found the logic yet. |
tests added in github#5238 functionality added in github#6640
|
Clearly I was a bit to eager to just accept changes in 70994b9, and now had to fix things up. Keeping that history, since otherwise the changes in 43b0250 might seem strange. The additions to codeql/python/ql/test/experimental/dataflow/coverage/test.py Lines 856 to 860 in 4b4b9bf
|
I think with the current code I'm quite happy. The change below doesn't feel entirely good, but currently I don't see a better approach AssignmentDefinition() {
SsaSource::assignment_definition(this.getSourceVariable(), this.getDefiningNode(), value) and
+ not this instanceof ParameterDefinition
}
Found the original implementation which I eliminated in 4e8a114 |
Somehow the previous fix didn't work :O
|
I'm flabbergasted that the previous code did not work. exists(ParameterDefinition param |
nodeFrom.asCfgNode() = param.getDefault() and
- nodeTo.asCfgNode() = param.getDefiningNode()
+ nodeTo.asVar() = param.getVariable()
)How does making the change above make us not find the proper flow??? In the code below, with the fix of this commit we have
With the change before (and outlined in the diff above) we would have the steps, so CLEARLY that should just work!
def foo(x=tracked):
print(x)it just doesn't make sense to me |
|
Performance looks fine, and results indicate that we've found new ways to find the same alerts as before. |
Took me a bit to understand this. The reason is that in your second chain, the link
is neither followed in the local (In the first case above, |
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.
So, as I understand it, in the following program
def f(x, y=5):
passwe have two EssaDefinitions, namely for ESSA x and ESSA y, and their defining nodes (via getDefiningNode) are CFG x and CFG y respectively. This makes sense, since these may receive flow from outside during invocation of f.
Additionally, we have a DefinitionNode, namely CFG y, and its defining node (via getValue) is Expr 5. This quite nicely represents additional possible flow "from outside" (at definition time, at least) and is mirrored in the newly added jump step.
We do not consider y = 5 an assignment because it does not happen locally; we would have to split y into two or something like that to make it local flow. Did you consider moving this restriction up into SsaSource::assignment_definition?
Apart from this one thing, I think it hangs together quite nicely
I also checked that
predicate test(Node node) {
jumpStepSharedWithTypeTracker(_, node) and
not node instanceof LocalSourceNode
}is currently empty on two large databases I had lying around.
| @@ -501,7 +501,8 @@ class AssignmentDefinition extends EssaNodeDefinition { | |||
| ControlFlowNode value; | |||
|
|
|||
| AssignmentDefinition() { | |||
| SsaSource::assignment_definition(this.getSourceVariable(), this.getDefiningNode(), value) | |||
| SsaSource::assignment_definition(this.getSourceVariable(), this.getDefiningNode(), value) and | |||
| not this instanceof ParameterDefinition | |||
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.
Consider moving this restriction into assignment_definition.
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.
yes, that's better
This PR took a series of unexpected events (some could have been avoided with better planning), so the commits end up taking a few twists and turns. I think everything should be very straightforward if reading commit-by-commit😊