Bug 538636 - disable javaagent based on Object.class major_version

... also upgraded to ASM 6.2.1 (see bug 539082)

Change-Id: I5fe1457929f8d6416a6f0434ee8414eb177eef8e
Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
diff --git a/org.eclipse.jdt.launching.javaagent/pom.xml b/org.eclipse.jdt.launching.javaagent/pom.xml
index 5b0334b..74756ff 100644
--- a/org.eclipse.jdt.launching.javaagent/pom.xml
+++ b/org.eclipse.jdt.launching.javaagent/pom.xml
@@ -20,7 +20,7 @@
     <dependency>
       <groupId>org.ow2.asm</groupId>
       <artifactId>asm</artifactId>
-      <version>6.2</version>
+      <version>6.2.1</version>
     </dependency>
   </dependencies>
 
diff --git a/org.eclipse.jdt.launching.javaagent/src/main/java/org/eclipse/jdt/launching/internal/javaagent/Premain.java b/org.eclipse.jdt.launching.javaagent/src/main/java/org/eclipse/jdt/launching/internal/javaagent/Premain.java
index 8b38b6a..225df81 100644
--- a/org.eclipse.jdt.launching.javaagent/src/main/java/org/eclipse/jdt/launching/internal/javaagent/Premain.java
+++ b/org.eclipse.jdt.launching.javaagent/src/main/java/org/eclipse/jdt/launching/internal/javaagent/Premain.java
@@ -13,6 +13,7 @@
  *******************************************************************************/
 package org.eclipse.jdt.launching.internal.javaagent;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.lang.instrument.ClassFileTransformer;
 import java.lang.instrument.IllegalClassFormatException;
@@ -22,7 +23,6 @@
 import java.security.ProtectionDomain;
 
 import org.eclipse.jdt.launching.internal.weaving.ClassfileTransformer;
-import org.objectweb.asm.ClassReader;
 
 public class Premain {
 	private static final ClassfileTransformer transformer = new ClassfileTransformer();
@@ -30,23 +30,12 @@
 	public static void premain(final String agentArgs, final Instrumentation inst) {
 		final boolean debuglog = "debuglog".equals(agentArgs); //$NON-NLS-1$
 
-		// disable instrumentation if ASM is not able to read Object.class definition
-		try {
-			InputStream is = ClassLoader.getSystemResourceAsStream("java/lang/Object.class"); //$NON-NLS-1$
-			try {
-				new ClassReader(is);
-			}
-			finally {
-				is.close();
-			}
-		}
-		catch (Exception e) {
+		// disable instrumentation if Object.class class format is not supported
+		short major = readJavaLangObjectMajor(debuglog);
+		if (major < 0 || major > ClassfileTransformer.MAX_CLASS_MAJOR) {
 			String vendor = System.getProperty("java.vendor"); //$NON-NLS-1$
 			String version = System.getProperty("java.version"); //$NON-NLS-1$
-			System.err.printf("JRE %s/%s is not supported, advanced source lookup disabled: %s.\n", vendor, version, e.getMessage()); //$NON-NLS-1$
-			if (debuglog) {
-				e.printStackTrace(System.err);
-			}
+			System.err.printf("JRE %s/%s is not supported, advanced source lookup disabled.\n", vendor, version); //$NON-NLS-1$
 			return;
 		}
 
@@ -89,4 +78,52 @@
 			System.err.println("Advanced source lookup enabled."); //$NON-NLS-1$
 		}
 	}
+
+	private static short readJavaLangObjectMajor(boolean debuglog) {
+		// https://docs.oracle.com/javase/specs/jvms/se10/html/jvms-4.html
+		// We need class major_version, i.e. the u2 field starting at offset 6
+
+		final int offset = 6;
+
+		final InputStream is = ClassLoader.getSystemResourceAsStream("java/lang/Object.class"); //$NON-NLS-1$
+		if (is == null) {
+			if (debuglog) {
+				System.err.println("Could not open java/lang/Object.class system resource stream."); //$NON-NLS-1$
+			}
+			return -1;
+		}
+
+		byte[] bytes = new byte[offset + 2];
+		try {
+			try {
+				if (is.read(bytes) < bytes.length) {
+					if (debuglog) {
+						System.err.println("Could not read java/lang/Object.class system resource stream."); //$NON-NLS-1$
+					}
+					return -1;
+				}
+			}
+			finally {
+				is.close();
+			}
+		}
+		catch (IOException e) {
+			if (debuglog) {
+				System.err.println("Could not read java/lang/Object.class system resource stream."); //$NON-NLS-1$
+				e.printStackTrace(System.err);
+			}
+			return -1;
+		}
+
+		int magic = ((bytes[0] & 0xFF) << 24) | ((bytes[1] & 0xFF) << 16) | ((bytes[2] & 0xFF) << 8) | (bytes[3] & 0xFF);
+		if (magic != 0xCAFEBABE) {
+			if (debuglog) {
+				System.err.println("Invalid java/lang/Object.class magic."); //$NON-NLS-1$
+			}
+			return -1;
+		}
+
+		return (short) (((bytes[offset] & 0xFF) << 8) | (bytes[offset + 1] & 0xFF));
+	}
+
 }
diff --git a/org.eclipse.jdt.launching.javaagent/src/main/java/org/eclipse/jdt/launching/internal/weaving/ClassfileTransformer.java b/org.eclipse.jdt.launching.javaagent/src/main/java/org/eclipse/jdt/launching/internal/weaving/ClassfileTransformer.java
index cd163e3..6476bba 100644
--- a/org.eclipse.jdt.launching.javaagent/src/main/java/org/eclipse/jdt/launching/internal/weaving/ClassfileTransformer.java
+++ b/org.eclipse.jdt.launching.javaagent/src/main/java/org/eclipse/jdt/launching/internal/weaving/ClassfileTransformer.java
@@ -23,12 +23,18 @@
 	// must match JDIHelpers.STRATA_ID
 	private static final String STRATA_ID = "jdt"; //$NON-NLS-1$
 
+	/** max supported java class format major version, must match {@link #ASM_API} below **/
+	public static final int MAX_CLASS_MAJOR = Opcodes.V10;
+
+	/** supported ASM API version, must match {@link #MAX_CLASS_MAJOR} above */
+	private static final int ASM_API = Opcodes.ASM6;
+
 	public byte[] transform(byte[] classfileBuffer, final String location) {
 
 		final ClassReader r = new ClassReader(classfileBuffer, 0, classfileBuffer.length);
 		final ClassWriter w = new ClassWriter(0);
 
-		r.accept(new ClassVisitor(Opcodes.ASM5, w) {
+		r.accept(new ClassVisitor(ASM_API, w) {
 			@Override
 			public void visitSource(String source, String debug) {
 				String javaSource = source;
diff --git a/org.eclipse.jdt.launching/lib/javaagent-shaded.jar b/org.eclipse.jdt.launching/lib/javaagent-shaded.jar
index 42c65f3..647041f 100644
--- a/org.eclipse.jdt.launching/lib/javaagent-shaded.jar
+++ b/org.eclipse.jdt.launching/lib/javaagent-shaded.jar
Binary files differ