Seemingly incorrect definite assignment rules regarding try-catch and try-catch-finally

Alex Buckley alex.buckley at oracle.com
Fri Jun 10 17:02:24 UTC 2022


Filed https://bugs.openjdk.org/browse/JDK-8288230

On 5/4/2022 4:54 PM, Robbe Pincket wrote:
> Hello all
> 
> It seems that with moving around some sentences, some errors slipt in.
> * In issue 3b, I mention “issue 2 also applies …”. This is supposed to mention issue 3
> * The example for issue 3 is not correct, and doesn’t show the issue, here is a correct version:
> 
> ```java
>      public void testIssue3(int x) {
>          int var7;
> 
>          while (true) {
>              try {
>                  if(x > 0) {
>                      break;
>                  }
>              } finally {
>                  var7 = 100;
>              }
>          }
> 
>          // according to the spec, var7 is not considered to be
>          // definite assigned, even though `var7 = 100` would
>          // have been executed
>          // javac does not give an error
>          System.out.println(var7);
>      }
> ```
> 
> Greetings
> Robbe
> 
> From: Robbe Pincket<mailto:robbepincket at live.be>
> Sent: woensdag 4 mei 2022 19:46
> To: jls-jvms-spec-comments at openjdk.java.net<mailto:jls-jvms-spec-comments at openjdk.java.net>
> Subject: Seemingly incorrect definite assignment rules regarding try-catch and try-catch-finally
> 
> Hello experts
> 
> I was reading the specifications today regarding definite (un)assignment rules (Chapter 16), to confirm a mental image I had of the control flow logic while trying to fix bug in the java decompiler I help maintaining. However when checking the spec it seemed like my assumption were not correct. After checking whether the code I though should be valid, but should according to my interpretation of the spec, and seeing that in fact it does compile, I started reading the whole definite assignment specification a few times.
> 
> It has happened before that I thought there was an error in the spec, but after rereading it again, or checking for other relevant specifications regarding the topic, I usually notice that I had misread, or just missed part of the specification. Sadly when doing this for the issue at hand, I seemed to only notice more issues with the relevant specs.
> 
> So the issues I noticed:
> 1.
> Both the "unassigned before a catch" and the "unassigned before a finally" rule (16.2.15.) mention the following:
>> V is definitely unassigned before every return statement that belongs to the try block.
> However V could get assigned inside the expression of the return if there is such an expression
> I think the following line should be added:
>> V is definitely unassigned after e in every statement of the form return e that belongs to the try block.
> The original line could get update to mention only returns without an expression, but this is not needed to be correct (I think)
> 
> 2.
> Both the "unassigned before a catch" and the "unassigned before a finally" rule (16.2.15.) seem to not take yield statements into consideration.
> I think the following line should be added:
>> V is definitely unassigned after e in every statement of the form yield e that belongs to the try block.
> 
> 3. (the original issue)
> All of the following:
> * 16.2.5. Labeled Statements
> * 16.2.9. switch Statements
> * 16.2.10. while Statements
> * 16.2.11. do Statements
> * 16.2.12. for Statements
> All mention something along the lines of
>> V is [un]assigned before every break statement for which the ... statement is the break target.
> However, this does not seem to take into account that a "break" (as 14.15. mentions) only "attempts to transfer control", because if the break "jumps" out of a try with a finally, that finally block gets run first. This finally block can assign values to variables, changing which variables should be considered definite assigned and which ones are definite unassigned.
> It seems that javac understands this, even though this seems to be contradicting the specs.
> 
> 3b.
> issue 2 also applies to try Statements (16.2.15.) with a nested try finally with regards to definite unassignment, but with all statements that could break out of the try block/catch block (return, throw, assert, break, yield and continue)
> 
> I have an example for each of these below.
> If I made any errors in interpreting the specifications I’d be happy to hear it.
> 
> Greetings
> Robbe
> 
> ```java
> class Examples {
>      public int testIssue1(int x) {
>          final int var7;
> 
>          try {
>              return var7 = 8;
>          } finally {
>              // according to the spec, var7 is considered to be
>              // definite unassigned, even though `var7 = 8` could
>              // (and would) have been executed
>              // javac does give an error
>              var7 = 100;
>          }
>      }
> 
>      public void testIssue2(int x) {
>          final int var7;
> 
>          int y = switch(x) {
>              case 1 -> var7 = 0;
>              default -> {
>                  try {
>                      yield var7 = 8;
>                  } finally {
>                      // according to the spec, var7 is considered to be
>                      // definite unassigned, even though `var7 = 8` could
>                      // (and would) have been executed
>                      // javac does give an error
>                      var7 = 100;
>                  }
>              }
>          };
>      }
> 
>      public int testIssue3(int x) {
>          final int var7;
> 
>          while (true) {
>              try {
>                  return var7 = 8;
>              } finally {
>                  // according to the spec, var7 is considered to be
>                  // definite unassigned, even though `var7 = 8` could
>                  // (and would) have been executed
>                  // javac does give an error
>                  var7 = 100;
>              }
>          }
>      }
> 
>      public void testIssue3b(int x) {
>          final int var7;
> 
>          l: try {
>              try {
>                  break l;
>              } finally {
>                  var7 = 8;
>              }
>          } finally {
>              // according to the spec, var7 is considered to be
>              // definite unassigned, even though `var7 = 8` could
>              // (and would) have been executed
>              // javac does give an error
>              var7 = 100;
>          }
>      }
> }
> ```
> 
> 


More information about the jls-jvms-spec-comments mailing list