diff --git a/build.gradle b/build.gradle index ad5a7a43..a4d7246d 100644 --- a/build.gradle +++ b/build.gradle @@ -366,3 +366,11 @@ tasks.register('runPolDet', Exec) { } defaultTasks "buildJars" + +sourceSets { + test { + resources { + srcDirs = ['src/tests/resources'] + } + } +} \ No newline at end of file diff --git a/src/main/gov/nasa/jpf/jvm/ClassFile.java b/src/main/gov/nasa/jpf/jvm/ClassFile.java index 9e331b84..9078ddc4 100644 --- a/src/main/gov/nasa/jpf/jvm/ClassFile.java +++ b/src/main/gov/nasa/jpf/jvm/ClassFile.java @@ -46,6 +46,7 @@ public class ClassFile extends BinaryClassSource { public static final int METHOD_HANDLE = 15; public static final int METHOD_TYPE = 16; public static final int INVOKE_DYNAMIC = 18; + private static final int MAX_SUPPORTED_VERSION = 61; public static final int REF_GETFIELD = 1; public static final int REF_GETSTATIC = 2; @@ -218,7 +219,7 @@ public String getRequestedTypeName(){ public static final String BOOTSTRAP_METHOD_ATTR = "BootstrapMethods"; protected final static String[] stdClassAttrs = { - SOURCE_FILE_ATTR, DEPRECATED_ATTR, INNER_CLASSES_ATTR, DEPRECATED_ATTR, SIGNATURE_ATTR, + SOURCE_FILE_ATTR, DEPRECATED_ATTR, INNER_CLASSES_ATTR, SIGNATURE_ATTR, RUNTIME_INVISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_ANNOTATIONS_ATTR, RUNTIME_VISIBLE_TYPE_ANNOTATIONS_ATTR, ENCLOSING_METHOD_ATTR, BOOTSTRAP_METHOD_ATTR }; @@ -944,6 +945,10 @@ public void parse( ClassFileReader reader) throws ClassParseException { // we don't do much with the version numbers yet int minor = readU2(); int major = readU2(); + if (major > MAX_SUPPORTED_VERSION) { + // this will throw ClassParseException if the major version java 18 or higher + error("Unsupported class file version: " + major); + } // get the const pool int cpCount = readU2(); diff --git a/src/tests/gov/nasa/jpf/jvm/FileVersionTest.java b/src/tests/gov/nasa/jpf/jvm/FileVersionTest.java new file mode 100644 index 00000000..1b7748f4 --- /dev/null +++ b/src/tests/gov/nasa/jpf/jvm/FileVersionTest.java @@ -0,0 +1,50 @@ +package gov.nasa.jpf.jvm; + +import gov.nasa.jpf.util.test.TestJPF; +import gov.nasa.jpf.vm.ClassParseException; +import org.junit.Test; + +import java.io.*; + +public class FileVersionTest extends TestJPF { + + private static final String JAVA17_CLASS = "/TestClassJava17.class"; + private static final String JAVA21_CLASS = "/TestClassJava21.class"; + + // loading a .class file into a byte array + private byte[] loadClassFile(String resourceName) throws IOException { + try (InputStream is = getClass().getResourceAsStream(resourceName)) { + if (is == null) throw new IOException("Resource not found: " + resourceName); + + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + // we choose here buffer size 1024 cause its enough to read most .class files in one or two iterations + // smaller buffer size like 256 will require more operations and larger buffers will waster memory + // i'm not sure which is suitable for this since the test classes we complied is empty but i think both could work + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = is.read(buffer)) != -1) { + bos.write(buffer, 0, bytesRead); + } + return bos.toByteArray(); + } + } + + + @Test + public void testSupportedVersionJava17() throws IOException, ClassParseException { + byte[] classData = loadClassFile(JAVA17_CLASS); + ClassFile classFile = new ClassFile(classData); + ClassFileReader reader = new ClassFileReaderAdapter(); + // this should pass with no exceptions + classFile.parse(reader); + } + + @Test(expected = ClassParseException.class) + public void testUnsupportedVersionJava21() throws IOException, ClassParseException { + byte[] classData = loadClassFile(JAVA21_CLASS); + ClassFile classFile = new ClassFile(classData); + ClassFileReader reader = new ClassFileReaderAdapter(); + // this should throw ClassParseException + classFile.parse(reader); + } +} \ No newline at end of file diff --git a/src/tests/resources/TestClassJava17.class b/src/tests/resources/TestClassJava17.class new file mode 100644 index 00000000..c30a4af6 Binary files /dev/null and b/src/tests/resources/TestClassJava17.class differ diff --git a/src/tests/resources/TestClassJava21.class b/src/tests/resources/TestClassJava21.class new file mode 100644 index 00000000..19e2ec0b Binary files /dev/null and b/src/tests/resources/TestClassJava21.class differ