Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8310016

Illegal bytecode for break from if with instanceof pattern matching condition

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P3 P3
    • 21, 22
    • tools
    • None
    • source
    • low
    • Hide
      The change has two aspects:
       - tweak to flow scoping for loops. This may lead to more binding variables being in scope after a loop, which may lead to new compile-time errors if the statements following the loop would use same-named variable. This is likely very rare.
       - the change to binding variable handling for labelled statements may cause some new compile-time errors. But, without this compile-time error, the classfile produced is invalid, hence the impact of this is likely extremely low.
       A differential corpus compilation didn't reveal any project that would be affected by either of those.
      Show
      The change has two aspects:  - tweak to flow scoping for loops. This may lead to more binding variables being in scope after a loop, which may lead to new compile-time errors if the statements following the loop would use same-named variable. This is likely very rare.  - the change to binding variable handling for labelled statements may cause some new compile-time errors. But, without this compile-time error, the classfile produced is invalid, hence the impact of this is likely extremely low.  A differential corpus compilation didn't reveal any project that would be affected by either of those.
    • Language construct
    • SE

      Summary

      For a specific code, javac is producing illegal bytecode. This change is proposing adjustments to the flow scoping rules in the JLS to avoid this problem.

      Problem

      Consider code like:

      X: if (!(o instanceof String s)) {
          break X;
      }
      System.err.println(s);

      Obviously, the System.err.println statement is executed whether or not o is matching String s. So, s may or may not have a meaning at this place. But the flow scoping rules allow this code to compile, leading to an invalid bytecode.

      As an interrelated problem, consider this loop example:

      X: {
               while (!(o instanceof String s)) {
                   break X;
               }
               System.err.println(s);
      }

      The JLS rules are not completely clear on whether this code is allowed or not. javac will reject this code, as it contains a break outside of the while, which may be overly strict.

      Solution

      The JLS and javac will be adjusted to:

      • prevent the first problem with breaking immediately out of the statement declaring the bindings variable by explicitly disallowing this case
      • allow the second example, by only disallowing breaks that immediately break of the loop declaring the binding variable.

      Specification

      The proposed JLS change is as follows:

      diff --git a/src/jls/06-names.xml b/src/jls/06-names.xml
      index cebcb21702a0bc6ce6c466fc2480a2d08fe228e8..a892a97457589b3ace4bc1e89e0e43c1b26cb19f 100644
      --- a/src/jls/06-names.xml
      +++ b/src/jls/06-names.xml
      @@ -2185,11 +2185,12 @@ The following rules apply to a statement &while; &lparen;&e;&rparen;
         <!-- External flow -->
      
         <listitem>
      -    <para role="norm" condition="static" xml:id="jls-6.3.2.3-100-B">
      +    <para role="norm" condition="static" xml:id="jls-6.3.2.3-100-B"
      +          revisionflag="changed" revision="21" conformance="8305701">
             A pattern variable is introduced by &while; &lparen;&e;&rparen; &S;
             iff (i) it is introduced by &e; when false and (ii) &S; does not
      -      contain a reachable &break; statement whose break target contains
      -      &S; (<xref linkend="jls-14.15"/>).</para>
      +      contain a reachable &break; statement for which the &while; statement is
      +      the break target (<xref linkend="jls-14.15"/>).</para>
      
           <para  revisionflag="deleted" revision="21" conformance="8309459" xml:id="jls-6.3.2.3-100-B.1z">
            <info role="norm" condition="error" />
      @@ -2214,12 +2215,13 @@ The following rule applies to a statement &do; &S; &while;
         <!-- External flow -->
      
         <listitem>
      -    <para role="norm" condition="static" xml:id="jls-6.3.2.4-100-A">
      +    <para role="norm" condition="static" xml:id="jls-6.3.2.4-100-A"
      +          revisionflag="changed" revision="21" conformance="8305701">
             A pattern variable is introduced by &do; &S; &while;
             &lparen;&e;&rparen; iff (i) it is introduced by &e; when
             false and (ii) &S; does not contain a reachable &break;
      -      statement whose break target contains &S; (<xref
      -      linkend="jls-14.15"/>).</para>
      +      statement for which the &do; statement is the break target 
      +      (<xref linkend="jls-14.15"/>).</para>
      
           <para  revisionflag="deleted" revision="21" conformance="8309459" xml:id="jls-6.3.2.4-100-A.1z">
            <info role="norm" condition="error" />
      @@ -2259,11 +2261,12 @@ linkend="jls-14.14.1"/>):</para>
         <!-- External flow -->
      
         <listitem>
      -    <para role="norm" condition="static" xml:id="jls-6.3.2.5-100-B">
      +    <para role="norm" condition="static" xml:id="jls-6.3.2.5-100-B"
      +          revisionflag="changed" revision="21" conformance="8305701">
             A pattern variable is introduced by a basic &for; statement iff
             (i) it is introduced by the condition expression when false and
             (ii) the contained statement, &S;, does not contain a reachable
      -      &break; statement whose break target contains &S;
      +      &break; for which the basic &for; statement is the break target
             (<xref linkend="jls-14.15"/>).</para>
      
           <para  revisionflag="deleted" revision="21" conformance="8309459" xml:id="jls-6.3.2.5-100-B.1z">
      @@ -2317,7 +2320,15 @@ The following rule applies to a labeled statement
         <!-- External flow -->
      
         <listitem>
      -    <para role="norm" condition="static" xml:id="jls-6.3.2.7-100-A">
      +    <para role="norm" condition="static" xml:id="jls-6.3.2.7-100-A"
      +          revisionflag="added" revision="21" conformance="8305701">
      +      A pattern variable is introduced by a labeled statement &L;&colon; &S;
      +      (where &L; is a label) iff (i) it is introduced by the statement &S;, and
      +      (ii) &S; does not contain a reachable &break; statement for which the
      +      labeled statement is the break target (<xref linkend="jls-14.15"/>). 
      +    </para>
      +    <para role="norm" condition="static" xml:id="jls-6.3.2.7-100-Az"
      +          revisionflag="deleted" revision="21" conformance="8305701">
             A pattern variable is introduced by a labeled statement iff it
             is introduced by the labeled statement's immediately contained
             &Statement;.</para>

      javac will be adjusted to follow this new specification.

      Please note this change is independent from JEPs 440 and 441. The problems above apply even to JDK 17, with preview features disabled.

            jlahoda Jan Lahoda
            webbuggrp Webbug Group
            Gavin Bierman
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: