-
Notifications
You must be signed in to change notification settings - Fork 6.1k
8358801: javac produces class that does not pass verifier. #25849
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
base: master
Are you sure you want to change the base?
Conversation
👋 Welcome back jlahoda! A progress list of the required criteria for merging this PR into |
❗ This change is not yet ready to be integrated. |
//in the defined variables for jumps that go outside of this let | ||
//expression: | ||
undefineVariablesInChain(result.falseJumps, limit); | ||
undefineVariablesInChain(result.trueJumps, limit); |
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.
Should we move this truncation of variables to CondItem itself? I moved the truncation of continue/break to GenContext and found that helpful, maybe we can require an extra int arg for makeCondItem(int, Chain, Chain)
for the limit?
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.
To me, personally: while doing it here is not perfect (mostly because I would prefer if we didn't have to do this bookkeeping at all), it seems to me like a fairly local property - the let expr starts, and then does its own cleanup. It already calls code.endScopes(limit);
above this change, so this is basically an extension to that. If we did it at makeCondItem
time, we would need to pass the limit everywhere makeCondItem
is called, making it non-local. Many parts of the code would now suddenly have to care whether the node is inside a let expression. That feels to me like increasing complexity.
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.
Sounds reasonable. I asked this because I could see undefineVariablesInChain
being used elsewhere, such as GenContext::addCont/addExit
. We should probably update those two sites, as I didn't consider a linked list chain being used in those sites.
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.
Or you can even make it an instance method on Chain - the limit can be considered an intrinsic property to where the chain leads to, except this information is not available when a chain is constructed (should it be?)
Consider code like:
javac will produce code that won't (rightfully) pass the verifier:
Now, the problem, as far as I can tell, is this: javac will desugar the pattern matching instanceof along the lines of:
(
$temp
is register/local variable number 4)specifically, note the
&&
in the middle of the let expression, and that the expression is in the conditional position. What happens here is that at the position of the&&
will basically generate a jump to skip the if (i.e. a jump whose target is just behind the if, for the case where the...
left to it evaluates to false). The problem here is that at the source position of the jump, the variable$temp
is defined/has value. And the set of variables which are defined/have value is stored at the moment of jump, and restored at the target place of the jump. I.e. in this case, javac will think variable number 4 has a value.This, by itself, while it does not seem right, but does not lead to a breakage, as the variable is not in
code.lvar
, and hence javac will ignore it.The problem is that inside the first case, variable number 4 is declared, and
lvar
is filled for it. In the first case, it is still not problematic, as the variable is defined/has value there as well. But, for the default case, the variable still has anlvar
entry (as the variable is still declared, just should be unassigned), but the defined/has value flag stored earlier is restored again. So, javac thinks the variable is fully valid, and generates a bogus StackMapTable entry listing the variable, leading to the verifier failure.I think the source of all trouble is the wrong "defined" flag. The solution in this PR is to make sure the variables declared by the let expression are removed from the
defined
variables stored in the conditional jump chains.Note this only applies to jumps that go outside of the left expression (and hence outside of the scope of the variable), internal jumps inside the let expression, if there would be any, shouldn't be affected.
Progress
Warning
8358801: javac produces class that does not pass verifier.
Found leading lowercase letter in issue title for
8358801: javac produces class that does not pass verifier.
Issue
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/25849/head:pull/25849
$ git checkout pull/25849
Update a local copy of the PR:
$ git checkout pull/25849
$ git pull https://git.openjdk.org/jdk.git pull/25849/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 25849
View PR using the GUI difftool:
$ git pr show -t 25849
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/25849.diff
Using Webrev
Link to Webrev Comment