JDK-8224952 : RI deviates from JVMS - non-zero minor_version for class files throws UnsupportedClassVersionError.
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 11,12
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • Submitted: 2019-05-29
  • Updated: 2020-01-05
  • Resolved: 2019-06-10
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 13 JDK 14
13 b25Fixed 14Fixed
Related Reports
Relates :  
Description
Table 4.1-A. class file format version ranges (by Java SE Platform) of JVMS states that all class file versions from 45.0 to 55.0  (both inclusive) are supported for Java SE 11. and 45.0 to 56.0 for Java SE 12.
This means that, say 45.1, 46.46 or 50.91 are all to be supported implicitly. But RI throws an exception:
Exception in thread "main" java.lang.UnsupportedClassVersionError: B (class file version 53.1) was compiled with an invalid non-zero minor version
	at java.base/java.lang.ClassLoader.defineClass1(Native Method)
	at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
	at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:151)
	at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:802)
	at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:700)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:623)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:334)
	at Wrapper.main(Wrapper.java:3)
Comments
ILW = HML = P2
04-06-2019

Bumping up the priority to P2, as this is a conformance + tck-red flagged issue.
31-05-2019

Harold - is this accurate historically? Questions for you below: JDK7: 46-current inclusive: requires minor version 0 <=45: allows any minor JDK8-JDK10: current: requires minor of 0 46-current exclusive: ignores minor <=45: allows any minor JDK11: current release (55) : requires minor 0 or 65535 46-55 inclusive: requires minor version 0 <= 45: allows any minor // Harold - how did JDK11 support preview features? Was 65535 used to indicate preview at this time? Was there a JVMS change or was this in anticipation/preliminary JVMS change? // Harold - why did JDK11 change from ignoring minor features 46-55 to requiring minor version 0? Again - was this in response to a JVMS change or in response to anticipated changes for preview? JDK12: major >= 56 (current): requires minor 0 or 65535 // JVMS preview spec changes 46-55 inclusive: requires minor version 0, <=45 allows other minor versions // Harold - is this accurate? As Holmes points out in JDK11, we allows 65535 // and by the time we shipped 12, we had seen Alex���s email about ignoring 55.65535 JDK13: major >= 57 (current): requires minor 0 or 65535 56: requires minor version 0 // Harold is this accurate? That does not match Alex���s email that we should ignore 55.65535 and 56.65535 46-55 inclusive: requires minor version 0 In response to your proposal: 1. JDK-12 last update already hit RDP2, so that is not going to change. JDK-8 and JDK-7 are fine. So we need to discuss JDK13 and JDK11. Your proposal for JDK13 is: major >= 56: requires minor or 65535 current: 65535 means "requires preview features" - so only load if preview enabled older: 65535 - ignored major <=55: allow any minor version This matches the JVMS (SE-12) preview changes. This matches the spec lead's goal of leniency for minor class file version usage, and specifically supports ignoring older 65535. I totally support making those JDK13 changes. JDK11 is harder. If you could fill in how the JDK11 decisions were made that would help. In general, when the JVMS changes we do not back port changes to match. In this particular case, I applaud your researching historical behavior, which states that JDK8-JDK10 ignored minor versions for all except the current release. So I am in agreement about: major version < 55: ignore minor version For me the question is whether for JDK11, for "current" version 55 and that depends on how preview features are handled in JDK11. If 65535 means preview feature is required, then I agree with your proposal of supporting 0 and 65535. If that wasn't actually supported in JDK11, then I would expect us to ignore the minor version.
31-05-2019

One of the very confusing aspects of this is that preview features were actually implemented in JDK 11 yet JVMS 11 does not support them - that was only added to JVMS 12, by which time it was noted: "Out of an abundance of caution for third-party JVM implementations, we decided to continue the longstanding JVMS practice of accepting any minor_version when the major_version is 45 through 55 inclusive. " but the implementation since 11 rejects non-zero minor versions!
29-05-2019

Some experiments. I created a class file with class file version 51.6. (The JDK-7 class file version was 51.0.) As expected, JDK-7 threw UnsupportedClassVersionError. JDK-8, JDK-9, and JDK-10 all accepted the minor version of 6 and ran the class file! JDK-11 and JDK-12 threw UnsupportedClassVersionError because of the non-zero minor_version.
29-05-2019

So JVMS 12 sets a new rule for 56+ but otherwise reinforces that all minor versions should be supported for 45 - 55. That seems unreasonable to me as the VM is expected to accept classfiles with minor versions the significance of which is unknown and presumably produced by something other than the JDK and its tools. I also find it strange that JVMS 12 Table 4.1-A attempts to change the allowed ranges for historical versions of Java SE! JDK 1.0.2 supports 45.0 through 45.3 as specified up to JVMS11, but now JVMS 12 claims it supports 45.0 through 45.65535!
29-05-2019

The JDK-12 JVM Spec says: For a class file whose major_version is 56 or above, the minor_version must be 0 or 65535. For a class file whose major_version is between 45 and 55 inclusive, the minor_version may be any value. A historical perspective on versions of the class file format is warranted. JDK 1.0.2 supported versions 45.0 through 45.3 inclusive. JDK 1.1 supported versions 45.0 through 45.65535 inclusive. When JDK 1.2 introduced support for major version 46, the only minor version supported under that major version was 0. Later JDKs continued the practice of introducing support for a new major version (47, 48, etc) but supporting only a minor version of 0 under the new major version. Finally, the introduction of preview features in Java SE 12 (see below) motivated a standard role for the minor version of the class file format, so JDK 12 supported minor versions of 0 and 65535 under major version 56. Subsequent JDKs introduce support for N.0 and N.65535 where N is the corresponding major version of the implemented Java SE Platform.
29-05-2019