RFR: 8358801: javac produces class that does not pass verifier.
Maurizio Cimadamore
mcimadamore at openjdk.org
Mon Jun 23 09:26:29 UTC 2025
On Tue, 17 Jun 2025 10:01:02 GMT, Jan Lahoda <jlahoda at openjdk.org> wrote:
> Consider code like:
>
>
> public class Main {
>
> private boolean test(String s, int i) {
> if (s.subSequence(0, 1) instanceof Runnable r) {
> return true;
> }
>
> Integer dummy;
> switch (i) {
> case 0:
> String clashing = null;
> return true;
> default:
> return true;
> }
> }
>
> public static void main(String[] args) {
> }
> }
>
>
> javac will produce code that won't (rightfully) pass the verifier:
>
>
> $ java Main.java
> Exception in thread "main" java.lang.VerifyError: Inconsistent stackmap frames at branch target 49
> Exception Details:
> Location:
> Main.test(Ljava/lang/String;I)Z @49: iconst_1
> Reason:
> Type top (current frame, locals[4]) is not assignable to 'java/lang/String' (stack map, locals[4])
> Current Frame:
> bci: @25
> flags: { }
> locals: { 'Main', 'java/lang/String', integer }
> stack: { integer }
> Stackmap Frame:
> bci: @49
> flags: { }
> locals: { 'Main', 'java/lang/String', integer, top, 'java/lang/String' }
> stack: { }
> Bytecode:
> 0000000: 2b03 04b6 0007 3a04 1904 c100 0d99 000b
> 0000010: 1904 c000 0d4e 04ac 1cab 0000 0000 0018
> 0000020: 0000 0001 0000 0000 0000 0013 013a 0404
> 0000030: ac04 ac
> Stackmap Table:
> same_frame(@24)
> same_frame(@44)
> append_frame(@49,Top,Object[#8])
>
> at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
> at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3035)
> at java.base/java.lang.Class.getMethodsRecursive(Class.java:3177)
> at java.base/java.lang.Class.findMethod(Class.java:2465)
> at java.base/java.lang.System$1.findMethod(System.java:1980)
> at java.base/jdk.internal.misc.MethodFinder.findMainMethod(MethodFinder.java:86)
> at jdk.compiler/com.sun.tools.javac.launcher.SourceLauncher.execute(SourceLauncher.java:194)
> at jdk.compiler/com.sun.tools.javac.launcher.SourceLauncher.run(SourceLauncher.java:138)
> at jdk.compiler/com.sun.tools.javac.launcher.SourceLauncher.main(SourceLauncher.java:76)
>
>
>
> Now, the problem, as far as I can tell, is this: javac will desugar the pattern matching instanceof along the lines of:
>
>
> if (... (var $temp = s.subSequence(0, 1) in ... && ...) ...) {
> return true;
> }
>
>
> (`$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...
Pesky issue and a relatively clean solution (given the circumstances). I tend to agree with how the fix decided to treat this as a special case for when let expressions are used inside a conditional, which seems to be where the issue really stems from.
Marked as reviewed by mcimadamore (Reviewer).
-------------
PR Review: https://git.openjdk.org/jdk/pull/25849#pullrequestreview-2949331976
PR Review: https://git.openjdk.org/jdk/pull/25849#pullrequestreview-2949333331
More information about the compiler-dev
mailing list