From 4af564030cbbffa09f3f0b0ad8dae35829695aa1 Mon Sep 17 00:00:00 2001 From: Jerome Haltom Date: Sat, 18 Jul 2026 09:09:17 -0500 Subject: [PATCH] Support class file versions through Java 25 (major 69) The decoder guarded on `majorVersion > 63`, rejecting Java 20-25 class files even though all of their structures (attributes, constant pool tags, opcodes, stack map frames) already decode correctly. The format has been stable since Java 17 (major 61); no new structures were added in 20-25. Add a `ClassFormatVersion.Latest` constant (= Java25) and compare the decoder guards against it so the cap tracks the newest defined version automatically instead of drifting behind a magic number. Co-Authored-By: Claude Opus 4.8 --- src/IKVM.ByteCode/ClassFormatVersion.cs | 3 +++ src/IKVM.ByteCode/Decoding/ClassFile.cs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/IKVM.ByteCode/ClassFormatVersion.cs b/src/IKVM.ByteCode/ClassFormatVersion.cs index b067fd5..c814a14 100644 --- a/src/IKVM.ByteCode/ClassFormatVersion.cs +++ b/src/IKVM.ByteCode/ClassFormatVersion.cs @@ -86,6 +86,9 @@ public record struct ClassFormatVersion(ushort Major, ushort Minor) : IComparabl /// Java 25 (class file 69.0) public static readonly ClassFormatVersion Java25 = new(69, 0); + /// The latest class file format version supported by this library. + public static readonly ClassFormatVersion Latest = Java25; + /// /// Implicitly converts a major version number to a with a minor version of 0. /// diff --git a/src/IKVM.ByteCode/Decoding/ClassFile.cs b/src/IKVM.ByteCode/Decoding/ClassFile.cs index 0588ec5..47ff2ee 100644 --- a/src/IKVM.ByteCode/Decoding/ClassFile.cs +++ b/src/IKVM.ByteCode/Decoding/ClassFile.cs @@ -40,7 +40,7 @@ public static bool TryMeasure(ref ClassFormatReader reader, ref int size) if (reader.TryReadU2(out ushort majorVersion) == false) return false; - if (majorVersion > 63) + if (majorVersion > ClassFormatVersion.Latest.Major) throw new UnsupportedClassVersionException(new ClassFormatVersion(majorVersion, minorVersion)); if (ConstantTable.TryMeasure(ref reader, ref size) == false) @@ -252,7 +252,7 @@ public static bool TryRead(ref ClassFormatReader reader, out ClassFile? clazz, I if (reader.TryReadU2(out ushort majorVersion) == false) return false; - if (majorVersion > 63) + if (majorVersion > ClassFormatVersion.Latest.Major) throw new UnsupportedClassVersionException(new ClassFormatVersion(majorVersion, minorVersion)); var version = new ClassFormatVersion(majorVersion, minorVersion);