From 06006c3a79e713284551ff5bfd331307cb9d67b8 Mon Sep 17 00:00:00 2001 From: Uwe Schindler Date: Wed, 3 Feb 2016 15:15:03 +0100 Subject: [PATCH 1/2] Add initial support for new Java 9 class file format (JDK-8148785) --- .../de/thetaphi/forbiddenapis/AsmUtils.java | 23 +++++++++++++++++++ .../de/thetaphi/forbiddenapis/Checker.java | 6 ++--- .../thetaphi/forbiddenapis/DeprecatedGen.java | 2 +- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/thetaphi/forbiddenapis/AsmUtils.java b/src/main/java/de/thetaphi/forbiddenapis/AsmUtils.java index 59783b94..45a1250e 100644 --- a/src/main/java/de/thetaphi/forbiddenapis/AsmUtils.java +++ b/src/main/java/de/thetaphi/forbiddenapis/AsmUtils.java @@ -16,11 +16,17 @@ * limitations under the License. */ +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.PushbackInputStream; import java.net.URISyntaxException; import java.net.URL; import java.util.Locale; import java.util.regex.Pattern; +import org.objectweb.asm.ClassReader; + /** Some static utilities for analyzing with ASM, also constants. */ public final class AsmUtils { @@ -146,5 +152,22 @@ public static String getModuleName(URL jrtUrl) { return null; } } + + /** Utility method to load class files of Java 9 by patching them, so ASM can read them. */ + public static ClassReader readAndPatchClass(InputStream in) throws IOException { + final byte[] b = new byte[8]; + final PushbackInputStream pbin = new PushbackInputStream(in, b.length); + for (int upto = 0; upto < b.length;) { + final int read = pbin.read(b, upto, b.length - upto); + if (read == -1) + throw new EOFException("Not enough bytes available to read header of class file."); + upto += read; + } + if (b[6] == 0 && b[7] == 53) { + b[7] = 52; + } + pbin.unread(b); + return new ClassReader(pbin); + } } diff --git a/src/main/java/de/thetaphi/forbiddenapis/Checker.java b/src/main/java/de/thetaphi/forbiddenapis/Checker.java index 494ef7db..f6f85ac5 100644 --- a/src/main/java/de/thetaphi/forbiddenapis/Checker.java +++ b/src/main/java/de/thetaphi/forbiddenapis/Checker.java @@ -245,7 +245,7 @@ private ClassSignature loadClassFromJigsaw(String classname) throws IOException } try { - return new ClassSignature(new ClassReader(in), AsmUtils.isRuntimeModule(moduleName), false); + return new ClassSignature(AsmUtils.readAndPatchClass(in), AsmUtils.isRuntimeModule(moduleName), false); } finally { in.close(); } @@ -297,7 +297,7 @@ private ClassSignature getClassFromClassLoader(final String clazz) throws ClassN final boolean isRuntimeClass = isRuntimeClass(conn); final InputStream in = conn.getInputStream(); try { - classpathClassCache.put(clazz, c = new ClassSignature(new ClassReader(in), isRuntimeClass, false)); + classpathClassCache.put(clazz, c = new ClassSignature(AsmUtils.readAndPatchClass(in), isRuntimeClass, false)); } finally { in.close(); } @@ -528,7 +528,7 @@ private void parseSignaturesFile(Reader reader, boolean isBundled) throws IOExce public void addClassToCheck(final InputStream in) throws IOException { final ClassReader reader; try { - reader = new ClassReader(in); + reader = AsmUtils.readAndPatchClass(in); } finally { in.close(); } diff --git a/src/tools/java/de/thetaphi/forbiddenapis/DeprecatedGen.java b/src/tools/java/de/thetaphi/forbiddenapis/DeprecatedGen.java index 87945583..06af0677 100644 --- a/src/tools/java/de/thetaphi/forbiddenapis/DeprecatedGen.java +++ b/src/tools/java/de/thetaphi/forbiddenapis/DeprecatedGen.java @@ -71,7 +71,7 @@ protected boolean isDeprecated(int access) { protected void parseClass(InputStream in) throws IOException { final ClassReader reader; try { - reader = new ClassReader(in); + reader = AsmUtils.readAndPatchClass(in); } catch (IllegalArgumentException iae) { // unfortunately the ASM IAE has no message, so add good info! throw new IllegalArgumentException("The class file format of your runtime seems to be too recent to be parsed by ASM (may need to be upgraded)."); From 3105d8ef7a9a90a7e7fef591d2aa39e6f4567376 Mon Sep 17 00:00:00 2001 From: Uwe Schindler Date: Wed, 3 Feb 2016 16:05:23 +0100 Subject: [PATCH 2/2] Make the patcher more generic --- .../java/de/thetaphi/forbiddenapis/AsmUtils.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/thetaphi/forbiddenapis/AsmUtils.java b/src/main/java/de/thetaphi/forbiddenapis/AsmUtils.java index 45a1250e..274f8f51 100644 --- a/src/main/java/de/thetaphi/forbiddenapis/AsmUtils.java +++ b/src/main/java/de/thetaphi/forbiddenapis/AsmUtils.java @@ -22,10 +22,13 @@ import java.io.PushbackInputStream; import java.net.URISyntaxException; import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.Locale; import java.util.regex.Pattern; import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Opcodes; /** Some static utilities for analyzing with ASM, also constants. */ public final class AsmUtils { @@ -153,6 +156,13 @@ public static String getModuleName(URL jrtUrl) { } } + private static void patchClassMajorVersion(byte[] header, int versionFrom, int versionTo) { + final ByteBuffer buf = ByteBuffer.wrap(header).order(ByteOrder.BIG_ENDIAN); + if (buf.getShort(6) == versionFrom) { + buf.putShort(6, (short) versionTo); + } + } + /** Utility method to load class files of Java 9 by patching them, so ASM can read them. */ public static ClassReader readAndPatchClass(InputStream in) throws IOException { final byte[] b = new byte[8]; @@ -163,9 +173,7 @@ public static ClassReader readAndPatchClass(InputStream in) throws IOException { throw new EOFException("Not enough bytes available to read header of class file."); upto += read; } - if (b[6] == 0 && b[7] == 53) { - b[7] = 52; - } + patchClassMajorVersion(b, Opcodes.V1_8 + 1, Opcodes.V1_8); pbin.unread(b); return new ClassReader(pbin); }