-
Notifications
You must be signed in to change notification settings - Fork 156
8269795: C2: Out of bounds array load floats above its range check in loop peeling resulting in SEGV #235
Conversation
… loop peeling resulting in SEGV
|
👋 Welcome back chagedorn! A progress list of the required criteria for merging this PR into |
|
@chhagedorn The following label will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command. |
Webrevs
|
TobiHartmann
left a comment
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.
Nice analysis, the fix looks good to me! Just some minor comments below.
[...] which is only the initial Bool node of the dominating test before the first invocation [...]
Should be "of the dominated test", right?
|
|
||
| /* | ||
| * @test | ||
| * @key stress randomness |
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.
There is no randomness in the test, right? Or is that referring to the use of StressGCM? If so, these keys are missing from other other tests that use this flag.
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, it's referring to StressGCM. @robcasloz once updated all tests with StressGCM to use these keys in JDK-8253765. But some newer tests miss these keys. Should we update them in an RFE to be consistent?
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, I think that would be good.
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.
Okay, I filed JDK-8270156 to clean it up later.
| } | ||
| } | ||
|
|
||
| public void mainTest() { |
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.
Is that method needed?
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.
It is needed, otherwise, it does not reproduce.
| // Condition is not a member of this loop? | ||
| !loop->is_member(get_loop(get_ctrl(test->in(1))))){ | ||
| // Walk loop body looking for instances of this test | ||
| Node* test_cond = test->in(1); |
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.
Maybe move this up to line 517 and replace the test->in(1)->is_Con() and get_ctrl(test->in(1)) usages in line 520/522 for better readability.
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.
Unfortunately, that's not possible as test could be an IfProj with only a control input.
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.
Right, too bad.
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.
Add comment why you cache the value - dominated_by() call may modify it.
|
@chhagedorn This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be: You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 38 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
Thanks for your review Tobias!
Yes, you're right as we are updating |
rwestrel
left a comment
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.
Looks good to me.
|
Thanks Roland for your review! |
vnkozlov
left a comment
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.
Looks good. I have few comments.
| // Condition is not a member of this loop? | ||
| !loop->is_member(get_loop(get_ctrl(test->in(1))))){ | ||
| // Walk loop body looking for instances of this test | ||
| Node* test_cond = test->in(1); |
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.
Add comment why you cache the value - dominated_by() call may modify it.
| Node *test = prev->in(0); | ||
| progress = false; // Reset for next iteration | ||
| Node* prev = loop->_head->in(LoopNode::LoopBackControl); // loop->tail(); | ||
| Node* test = prev->in(0); |
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.
May be add assert(test != NULL). idom() call at the end of loop has such asserts.
In other places we have check test != NULL but we not doing that here (at line 519).
| int p_op = prev->Opcode(); | ||
| if ((p_op == Op_IfFalse || p_op == Op_IfTrue) && | ||
| test->is_If() && // Test? | ||
| test->is_If() && // Test? |
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.
We can do what Tobias is asking by pre-check:
int p_op = prev->Opcode();
Node* test_cond = NULL;
if ((p_op == Op_IfFalse || p_op == Op_IfTrue) && test->is_If()) {
test_cond = test->in(1);
}
if (test_cond != NULL &&
vnkozlov
left a comment
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.
Good.
TobiHartmann
left a comment
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.
Looks good!
|
Thanks Vladimir, Tobias and Roland for your reviews! |
|
/integrate |
|
Going to push as commit 040c02b.
Your commit was automatically rebased without conflicts. |
|
@chhagedorn Pushed as commit 040c02b. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
In the testcase, an out of bounds array load (
LoadI) floats above its range check resulting in a segfault. The problem can be traced back to incorrectly treating anIfnode, on which theLoadIis control dependent, as being dominated inPhaseIdealLoop::peeled_dom_test_elim. As a result,PhaseIdealLoop::dominated_by()moves theLoadIout and before the loop while the range check stays inside the loop.peeled_dom_test_elim()walks through the idom chain of the loop body and tries to find loop-invariant tests. Once it finds one, it not only moves this test out of the loop but also looks for other tests with the same condition node which can be removed. The condition of the dominated tests in the loop are replaced with aConIindominated_by(). The data dependencies on the removed dominated tests are rewired to a peeled node before the loop.However, the current code directly checks
test->in(1)at L527 which is only the initialBoolnode of the dominated test before the first invocation ofdominated_by()in the loop on L525. Afterwards,test->in(1)is aConInode. We now continue to look for tests with an identicalConIcondition to move their data nodes out of this loop. This is wrong and exactly happens in the testcase: The loop body still contains a not yet cleaned up (by IGVN)Ifnode (with aConIcondition) of an eliminated skeleton predicate on which an out of boundsLoadInode is control dependent. TheLoadIis then wrongly rewired out of the loop and before its range check.The fix is to only check against the initial
test->in(1)Boolnode which satisfies the conditions checked on the lines before (L518-520).Thanks,
Christian
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk17 pull/235/head:pull/235$ git checkout pull/235Update a local copy of the PR:
$ git checkout pull/235$ git pull https://git.openjdk.java.net/jdk17 pull/235/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 235View PR using the GUI difftool:
$ git pr show -t 235Using diff file
Download this PR as a diff file:
https://git.openjdk.java.net/jdk17/pull/235.diff