JDK-8058511 : StackOverflowError at com.sun.tools.javac.code.Types.lub
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8u20
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2014-09-15
  • Updated: 2015-06-04
  • Resolved: 2014-10-14
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
8u40Fixed 9 b36Fixed
Related Reports
Relates :  
Description
When trying to build our project's code using JDK 8u20's, javac crashes with a StackOverflowError.
This worked fine in all prior versions of t he JDK (e.g. 8u11, 7u67,
6u45, etc.) so this is a regression in the compiler.
This happens on RHEL 5.10 64-bit, CentOS 6.5 32-bit & 64-bit, RHEL 7
64-bit, etc.

java version "1.8.0_20"
Java(TM) SE Runtime Environment (build 1.8.0_20-b26)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b23, mixed mode)
javac 1.8.0_20

The system is out of resources.
Consult the following stack trace for details.
java.lang.StackOverflowError
        at com.sun.tools.javac.code.Types.lub(Types.java:3532)
        at com.sun.tools.javac.code.Types.lub(Types.java:3616)
        at com.sun.tools.javac.code.Types.lub(Types.java:3616)
        at com.sun.tools.javac.code.Types.lub(Types.java:3616)
        at com.sun.tools.javac.code.Types.lub(Types.java:3616)
...

HOW TO REPRODUCE:

To reproduce issue, download tarball at following URL:

http://nextmidas.techma.com/nextmidas/nxm350/nxm350_showing_jdk8u20_javac_bug.tar.gz
(the original project has been simplified in order to make it easier to reproduce).

Then:

1. extract tarball
2. cd to directory (nxmxxx)
3. javac -classpath . -source 1.6 nxm/sys/lib/KeyObject.java

I think one of the key thing here is the use of -source 1.6 or -or-
-source 1.7 when using JDK 8u20's javac.

Comments
Correction - the offending changeset is this one: http://hg.openjdk.java.net/jdk9/jdk9/langtools/rev/abbc15936e1b Which as been introduced to fix JDK-8042338.
18-09-2014

The following test case: class Test { <Z> void choose(Z z1, Z z2) { } void test(Class<Double> cd, Class<? extends double[]> cdarr) { choose(cd, cdarr); } } Reproduces the crash even without the source flag - lub() seems to be broken for these specific inputs - possibly as a result of this fix JDK-8033718
18-09-2014

Minimal test case: class Test { Class<?> test(Class<Double> cd, Class<? extends double[]> cdarr) { return (false) ? cd : cdarr; } } Needs to be compiled with -source 7 in order to reproduce the crash.
18-09-2014

Another related lub failure present in all releases (in 8 you need so set -source 7 to reproduce): import java.util.*; class Test { <Z> void m(Z z) { } void test(List<? extends double[]> l) { Object o = true ? l.get(0) : l.get(0); } } Gives: An exception has occurred in the compiler (1.7.0_65). Please file a bug at the Java Developer Connection (http://java.sun.com/webapps/bugreport) after checking the Bug Parade for duplicates. Include your program and the following diagnostic in your report. Thank you. java.lang.NullPointerException at com.sun.tools.javac.code.Types.lub(Types.java:2886) at com.sun.tools.javac.code.Types.lub(Types.java:2844) at com.sun.tools.javac.comp.Attr.condType1(Attr.java:1278) at com.sun.tools.javac.comp.Attr.condType(Attr.java:1201) at com.sun.tools.javac.comp.Attr.visitConditional(Attr.java:1182) at com.sun.tools.javac.tree.JCTree$JCConditional.accept(JCTree.java:1108) at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:431) at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:418) at com.sun.tools.javac.comp.Attr.attribExpr(Attr.java:449) at com.sun.tools.javac.comp.Attr.visitVarDef(Attr.java:887) at com.sun.tools.javac.tree.JCTree$JCVariableDecl.accept(JCTree.java:725) at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:431) at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:418) at com.sun.tools.javac.comp.Attr.attribStat(Attr.java:480) at com.sun.tools.javac.comp.Attr.attribStats(Attr.java:496) at com.sun.tools.javac.comp.Attr.visitBlock(Attr.java:918) at com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:781) at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:431) at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:418) at com.sun.tools.javac.comp.Attr.attribStat(Attr.java:480) at com.sun.tools.javac.comp.Attr.visitMethodDef(Attr.java:836) at com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:669) at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:431) at com.sun.tools.javac.comp.Attr.attribTree(Attr.java:418) at com.sun.tools.javac.comp.Attr.attribStat(Attr.java:480) at com.sun.tools.javac.comp.Attr.attribClassBody(Attr.java:3250) at com.sun.tools.javac.comp.Attr.attribClass(Attr.java:3173) at com.sun.tools.javac.comp.Attr.attribClass(Attr.java:3109) at com.sun.tools.javac.comp.Attr.attrib(Attr.java:3083) at com.sun.tools.javac.main.JavaCompiler.attribute(JavaCompiler.java:1184) at com.sun.tools.javac.main.JavaCompiler.compile2(JavaCompiler.java:870) at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:829) at com.sun.tools.javac.main.Main.compile(Main.java:439) at com.sun.tools.javac.main.Main.compile(Main.java:353) at com.sun.tools.javac.main.Main.compile(Main.java:342) at com.sun.tools.javac.main.Main.compile(Main.java:333) at com.sun.tools.javac.Main.compile(Main.java:76) at com.sun.tools.javac.Main.main(Main.java:61) Again, this is caused by the fact that javac is trying to access the element type of an array but it gets a captured variable (whose bound is an array) instead; hence, elementType returns null and lub NPEs.
18-09-2014

The likely cause as to why this has never been reported before is that the following code: import java.util.*; class Test { <Z> void choose(Z z1, Z z2) { } void m(List<? extends double[]> ld, Double d) { choose(ld.get(0), d); } } Works correctly in all releases; due to a known discrepancy between the JLS and javac, javac would call the upper bound on the actual argument, hence turning #CAP into double[] before calling lub.
18-09-2014

Note - lub always had this bug with infinite recursion - I tried the following with JDK 7 (1.7.0_65): import java.util.*; class Test { void m(List<? extends double[]> ld, Double d) { Object o = true ? ld.get(0) : d; } } And the crash is there (albeit with different line numbers, of course). We can conclude that JDK-8042338 only exposed an existing javac issue that would have been otherwise very hard to reproduce. The root fix is to address the problem in lub.
18-09-2014

The specific change that introduced the regression is the following (inside Types.merge): - m = new WildcardType(lub(upperBound(act1.head), - upperBound(act2.head)), + m = new WildcardType(lub(wildUpperBound(act1.head), + wildUpperBound(act2.head)), When invoked on Class<Double>, Class<#CAP>, where #CAP <: double[], Types.merge used to call Types.upperBound on both type-arguments and then apply lub on the results - which meant: lub(Double, double[]) Now, since we use wildUpperBound instead, we only rewrite wildcard upper bounds, which leads to lub being called with the following parameters: lub(Double, #CAP1) From here on, the compiler never terminates, as lub is first rewriting #CAP as its upper bound (double[]) but then in this code: for (Type t : ts) { if (!t.hasTag(ARRAY)) // Filter out any arrays classes = classes.prepend(t); } } return lub(classes); We fail to 'exclude' #CAP from the list because we fail to see that it's a var with an array bound. Hence, we loop forever with the same types being passed to lub.
18-09-2014