JDK-8036942 : javac generates incorrect exception table for multi-catch statements inside a lambda
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2014-03-07
  • Updated: 2014-08-15
  • Resolved: 2014-05-01
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u20 b15Fixed 9Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
If this code is compiled:

import java.io.IOException;

public class FunWithMultiCatch {
  public static void main(String[] args) {
    Runnable r = () -> {
      try {
        Object o = null;
        o.getClass();
        throw new IOException();
      } catch(IOException | IllegalArgumentException e) {
        System.out.println("KO !");
      } catch(RuntimeException e) {
        System.out.println("OK !");
      }
    };
    r.run();
  }
}

javac generates this code:

private static void lambda$main$0();
    descriptor: ()V
    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=2, locals=1, args_size=0
         0: aconst_null   
         1: astore_0      
         2: aload_0       
         3: invokevirtual #4                  // Method java/lang/Object.getClass:()Ljava/lang/Class;
         6: pop           
         7: new           #5                  // class java/io/IOException
        10: dup           
        11: invokespecial #6                  // Method java/io/IOException."<init>":()V
        14: athrow        
        15: astore_0      
        16: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        19: ldc           #9                  // String KO !
        21: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        24: goto          36
        27: astore_0      
        28: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        31: ldc           #12                 // String OK !
        33: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        36: return        
      Exception table:
         from    to  target type
             0    15    15   Class java/lang/Exception   <----- this will capture all exceptions.
             0    15    27   Class java/lang/RuntimeException

if the original code is modified to:

import java.io.IOException;

class FunWithMultiCatch {
  public static void main(String[] args) {
      try {
        Object o = null;
        o.getClass();
        throw new IOException();
      } catch(IOException | IllegalArgumentException e) {
        System.out.println("KO !");
      } catch(RuntimeException e) {
        System.out.println("OK !");
      }
  }
}

then we obtain this exception table:

    Exception table:
         from    to  target type
             0    15    15   Class java/io/IOException
             0    15    15   Class java/lang/IllegalArgumentException
             0    15    27   Class java/lang/RuntimeException

reported in lambda-dev: http://mail.openjdk.java.net/pipermail/lambda-dev/2014-March/011940.html
Comments
Release note: "Correct handling of try-catch with multiple catches inside a lambda"
30-07-2014

Verified
29-07-2014

Dual fix versions were specified for this bug record. That's not allowed! I've removed 9 as fixversion since that fix already has a backport record.
01-05-2014

Erasure was eliminating the union type information on the mutli-catch. Additionally, the tree construction did not handle union types, again treating it as the LUB.
18-04-2014

The lost information here is from retrieving just from the symbol and not the tree, which in this case has more detailed information. Erasure is not at fault, at least in this case. I agree a more general approach is needed, probably more tree copying than reconstruction from the symbol type. BTW. I've changed 8013178 to be a duplicate of this, which it is.
09-04-2014

This patch was proposed at [1] as a solution for this bug: diff -r f675ddb8bd67 -r 16879f001d25 src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java --- a/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Fri Mar 07 13:30:23 2014 -0800 +++ b/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Mon Mar 10 16:08:59 2014 +0000 @@ -441,6 +441,9 @@ int prevPos = make.pos; try { result = make.at(tree).VarDef((VarSymbol)lambdaContext.getSymbolMap(LOCAL_VAR).get(tree.sym), init); + if ((result != null) && tree.vartype.hasTag(TYPEUNION)) { + ((JCVariableDecl) result).vartype = tree.vartype; + } } finally { make.at(prevPos); } [1] http://mail.openjdk.java.net/pipermail/lambda-dev/2014-March/011946.html This patch is added only as a reference. I think that we should seek for a general solution and / or check if there are more cases like this one.
11-03-2014

LTM makes a heavy use of erasure() during translations and mapping of variables. These erasure operations may be correct in most cases but it may lead to an information loss as this case shows. It's also arguably that such an intense use of erasure() is needed here as LTM is applied after TransTypes which is supposed to erase most / all types, so I wonder if this may be a bug in TransTypes. I think that it should be evaluated by Robert Field, which is current maintainer of LTM, what is the best approach here, I will thus reassigning it to him.
10-03-2014

This is 8013178. I wish more information had been given there as to what version was used to try to reproduce this. My main concern with this issue is whether there are any other coding constructs that are being handled differently when part of a lambda?
10-03-2014

This looks very similar to JDK-8013178
08-03-2014

Raised to P2.
07-03-2014