Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6246: Making the agent stop using Unsafe #35

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -0,0 +1,4 @@
package org.openjdk.jmc.agent.generated_events;

public final class Dummy {
}
@@ -42,6 +42,7 @@
import org.openjdk.jmc.agent.Parameter;
import org.openjdk.jmc.agent.ReturnValue;
import org.openjdk.jmc.agent.TransformDescriptor;
import org.openjdk.jmc.agent.generated_events.Dummy;
import org.openjdk.jmc.agent.util.TypeUtils;

public class JFRTransformDescriptor extends TransformDescriptor {
@@ -143,7 +144,7 @@ private String initializeEventDescription() {
}

private String initializeEventClassName() {
return TypeUtils.getPathPart(getClassName()) + getClassPrefix()
return TypeUtils.getPathPart(Dummy.class.getName().replace('.', '/')) + getClassPrefix()
+ TypeUtils.deriveIdentifierPart(getEventName());
}

@@ -87,7 +87,7 @@ private void reflectiveRegister(Class<?> generateEventClass) throws Exception {

private Class<?> generateEventClass() throws Exception {
try {
return Class.forName(transformDescriptor.getEventClassName().replace('/', '.'));
return Class.forName(transformDescriptor.getEventClassName().replace('/', '.'), false, definingClassLoader);
} catch (ClassNotFoundException e) {
byte[] eventClass = JFRNextEventClassGenerator.generateEventClass(transformDescriptor);
return TypeUtils.defineClass(transformDescriptor.getEventClassName(), eventClass, 0, eventClass.length,
@@ -85,7 +85,7 @@ private static void createField(ClassWriter cw, JFRTransformDescriptor td, Param

String fieldType = getFieldType(type);

FieldVisitor fv = cw.visitField(Opcodes.ACC_PROTECTED, param.getFieldName(), fieldType, null, null);
FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC, param.getFieldName(), fieldType, null, null);

// Name
AnnotationVisitor av = fv.visitAnnotation("Ljdk/jfr/Label;", true);
@@ -125,7 +125,7 @@ private static void createField(ClassWriter cw, JFRTransformDescriptor td, Type

String fieldType = getFieldType(type);

FieldVisitor fv = cw.visitField(Opcodes.ACC_PROTECTED, returnValue.getFieldName(), fieldType, null, null);
FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC, returnValue.getFieldName(), fieldType, null, null);

// Name
AnnotationVisitor av = fv.visitAnnotation("Ljdk/jfr/Label;", true);
@@ -32,19 +32,19 @@
*/
package org.openjdk.jmc.agent.util;

import java.lang.invoke.MethodHandles;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.ProtectionDomain;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.openjdk.jmc.agent.Agent;
import org.openjdk.jmc.agent.jfr.impl.JFRUtils;
import org.openjdk.jmc.agent.generated_events.Dummy;

/**
* Helper methods for doing transforms.
@@ -61,17 +61,6 @@

public static final Object STRING_INTERNAL_NAME = "java/lang/String"; //$NON-NLS-1$

private final static String UNSAFE_JDK_7_CLASS = "sun.misc.Unsafe"; //$NON-NLS-1$
private final static String UNSAFE_JDK_11_CLASS = "jdk.internal.misc.Unsafe"; //$NON-NLS-1$

private static final Object UNSAFE;
private static final Method UNSAFE_DEFINE_CLASS_METHOD;

static {
UNSAFE = getUnsafe();
UNSAFE_DEFINE_CLASS_METHOD = getUnsafeDefineClassMethod(UNSAFE);
}

/**
* The file extension for java source files (.java).
*/
@@ -122,12 +111,41 @@ public static String toString(Object o) {
public static Class<?> defineClass(
String eventClassName, byte[] eventClass, int i, int length, ClassLoader definingClassLoader,
ProtectionDomain protectionDomain) {
String version = System.getProperty("java.version");
if (Integer.parseInt(version.substring(0, version.indexOf("."))) < 9) {
return defineClassWithReflection(eventClassName, eventClass, i, length, definingClassLoader, protectionDomain);
}

return defineClassWithLookup(eventClassName, eventClass, i, length, definingClassLoader, protectionDomain);
}

private static Class<?> defineClassWithLookup(
String eventClassName, byte[] eventClass, int i, int length, ClassLoader definingClassLoader,
ProtectionDomain protectionDomain) {
try {
return (Class<?>) UNSAFE_DEFINE_CLASS_METHOD.invoke(UNSAFE, eventClassName, eventClass, i, length,
definingClassLoader, protectionDomain);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
Method privateLookupIn = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
MethodHandles.Lookup lookup = (MethodHandles.Lookup) privateLookupIn.invoke(null, Dummy.class, MethodHandles.lookup());
byte[] bytes = Arrays.copyOfRange(eventClass, i, i + length);
Method defineClass = MethodHandles.Lookup.class.getDeclaredMethod("defineClass", byte[].class);
return (Class<?>) defineClass.invoke(lookup, (Object) bytes);
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
Agent.getLogger().log(Level.SEVERE, "Failed to dynamically define the class " + eventClassName, e); //$NON-NLS-1$
}

return null;
}

private static Class<?> defineClassWithReflection(
String eventClassName, byte[] eventClass, int i, int length, ClassLoader definingClassLoader,
ProtectionDomain protectionDomain) {
try {
Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class, ProtectionDomain.class);
defineClass.setAccessible(true);
return (Class<?>) defineClass.invoke(definingClassLoader, eventClassName, eventClass, i, length, protectionDomain);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
Agent.getLogger().log(Level.SEVERE, "Failed to dynamically define the class " + eventClassName, e); //$NON-NLS-1$
}

return null;
}

@@ -258,49 +276,4 @@ private static String toString(Object o, int length) {
private static void emitBox(MethodVisitor mv, String desc) {
mv.visitMethodInsn(Opcodes.INVOKESTATIC, INAME, "box", desc, false); //$NON-NLS-1$
}

private static Object getUnsafe() {
// Lovely, but this seems to be the only way
Class<?> unsafeClass = getUnsafeClass();
try {
Field f = unsafeClass.getDeclaredField("theUnsafe"); //$NON-NLS-1$
f.setAccessible(true);
return f.get(null);
} catch (Exception e) {
Logger.getLogger(JFRUtils.class.getName()).log(Level.SEVERE, "Could not access Unsafe!", e); //$NON-NLS-1$
}
return null;
}

private static Method getUnsafeDefineClassMethod(Object unsafe) {
try {
return unsafe.getClass().getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class,
ClassLoader.class, ProtectionDomain.class);
} catch (NoSuchMethodException | SecurityException e) {
System.out.println(
"Could not find, or access, any defineClass method. The agent will not work. If on JDK 11, try adding --add-exports java.base/jdk.internal.misc=ALL-UNNAMED"); //$NON-NLS-1$
e.printStackTrace();
System.out.flush();
System.exit(3);
}
return null;
}

private static Class<?> getUnsafeClass() {
Class<?> clazz = null;
try {
clazz = Class.forName(UNSAFE_JDK_11_CLASS);
} catch (ClassNotFoundException e) {
try {
clazz = Class.forName(UNSAFE_JDK_7_CLASS);
} catch (ClassNotFoundException e1) {
System.out.println(
"Could not find, or access, any Unsafe class. The agent will not work. If on JDK 11, try adding --add-exports java.base/jdk.internal.misc=ALL-UNNAMED"); //$NON-NLS-1$
e1.printStackTrace();
System.out.flush();
System.exit(2);
}
}
return clazz;
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.