JDK-8043725 : javac fails with StackOverflowException
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: linux
  • CPU: x86_64
  • Submitted: 2014-05-21
  • Updated: 2015-10-14
  • Resolved: 2014-06-09
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
8u20Fixed 9 b19Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_20-ea"
Java(TM) SE Runtime Environment (build 1.8.0_20-ea-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.20-b14, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Linux HOST 3.11.0-18-generic #32-Ubuntu SMP Tue Feb 18 21:11:14 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
The class provided below compiles using javac 1.8.0_05-b13, but causes a stack overflow exception with javac 1.8.0_20-ea-b14.

REGRESSION.  Last worked in version 8

ADDITIONAL REGRESSION INFORMATION: 
java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the source code given below.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
It should compile without problem.
ACTUAL -
It produces a stack overflow exception shown below.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
The system is out of resources.
Consult the following stack trace for details.
java.lang.StackOverflowError
	at com.sun.tools.javac.code.Type.hasTag(Type.java:97)
	at com.sun.tools.javac.code.Types$SameTypeVisitor.visitType(Types.java:1102)
	at com.sun.tools.javac.code.Types$SameTypeVisitor.visitType(Types.java:1088)
	at com.sun.tools.javac.code.Types$DefaultTypeVisitor.visitTypeVar(Types.java:4404)
	at com.sun.tools.javac.code.Type$TypeVar.accept(Type.java:1266)
	at com.sun.tools.javac.code.Types$DefaultTypeVisitor.visit(Types.java:4398)
	at com.sun.tools.javac.code.Types.isSameType(Types.java:1082)
	at com.sun.tools.javac.code.Types.isSameType(Types.java:1077)
	at com.sun.tools.javac.code.Types.containsTypeEquivalent(Types.java:4061)
	at com.sun.tools.javac.code.Types.containsTypeEquivalent(Types.java:1436)
	at com.sun.tools.javac.code.Types$LooseSameTypeVisitor.containsTypes(Types.java:1231)
	at com.sun.tools.javac.code.Types$SameTypeVisitor.visitClassType(Types.java:1156)
	at com.sun.tools.javac.code.Types$SameTypeVisitor.visitClassType(Types.java:1088)
	at com.sun.tools.javac.code.Type$ClassType.accept(Type.java:763)
	at com.sun.tools.javac.code.Types$DefaultTypeVisitor.visit(Types.java:4398)
...


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class StackOverflowBug {

  interface A<T> {
  }

  <T extends A<T>> T m(T v) {
    return m(v);
  }
}
---------- END SOURCE ----------


Comments
I think that JDK-8037878 just introduced a new way to stress a visitor's code that already had a bug. I wonder if we should look for similar issues in other visitors.
30-05-2014

The issue comes from this check (in Types.LooseSameTypeVisitor): boolean sameTypeVars(TypeVar tv1, TypeVar tv2) { return tv1.tsym == tv2.tsym && visit(tv1.getUpperBound(), tv2.getUpperBound()); } Note that this call would recurse on the type-variable upper bounds to determine structural type-equality; this recursion never terminates in the above example, as the two variables being compared are 'clones' of the same type-variable (the one in the declaration of 'm') meaning that their symbol is always the same, and, since they have fbounds, the routine will loop endlessly. This problem has been introduced by the incorporation logic added as part of 8037878 - before, it wasn't possible for lub to end up in this corner case. The solution is to add a recursion guard on the above routine, similarly to what it has been done in other recursive routines in Types (i.e. type containment, type-disjointness, cast, etc.).
30-05-2014

Really easy to reproduce: class StackOverflowBug { <T extends Comparable<T>> T m(T v) { return m(v); } } given it's a regression and it's also easy to reproduce, I'm raising priority.
30-05-2014

This seems caused by a variant of 4993221 - an incorporation step (namely the one in 18.3.1) is forcing the compiler to compute the lub between T' (where T' <: A<T'>) and A<T> - this causes infinite recursion (through lcti, see JLS 4.10.4). Normally the compiler detect such situations and bails out - but not here.
30-05-2014

I think that this is a duplicate of JDK-6558545
29-05-2014

reproducible with 1.9.0-ea-b11
22-05-2014