Java agent throws UnsupportedClassVersionError when Instrumentation#retransformClasses is called.

I need to dump who invokes a setCancelled(boolean cancelled) method in a running jar (Spigot 1.8). I decided to do this via dumping the caller using StackWalker by using a javaagent to add a method call which dumps the caller, the item field which is of type org.bukkit.inventory.ItemStack, & the cancelled argument. The only issue currently, is that when i call retransformClasses the whole thing comes burning down. Target class: org.bukkit.event.player.PlayerInteractEvent The agent is compiled under Java 17.0.12 the JVM is 17.0.12 The spigot jar is java 8 (i think) Ran via the -javaagent command line option
53 Replies
JavaBot
JavaBotā€¢2mo ago
āŒ› This post has been reserved for your question.
Hey @cire! Please use /close or the Close Post button above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically marked as dormant after 300 minutes of inactivity.
TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.
cire
cireOPā€¢2mo ago
Transformer:
ClassReader classReader = new ClassReader(byteCode);
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);

ClassNode classNode = new ClassNode();
classReader.accept(classNode, 0);

MethodNode methodNode_isCancelled = null;
for (MethodNode mn : classNode.methods) {
if ("setCancelled".equals(mn.name)) {
methodNode_isCancelled = mn;
break;
}
}

if (methodNode_isCancelled == null)
return byteCode;

InsnList insnList = new InsnList();
insnList.add(new VarInsnNode(Opcodes.ALOAD, 0));
insnList.add(new FieldInsnNode(Opcodes.GETSTATIC, "java/lang/StackWalker$Option", "RETAIN_CLASS_REFERENCE", "Ljava/lang/StackWalker$Option"));
insnList.add(new MethodInsnNode(INVOKESTATIC, "java/lang/StackWalker", "getInstance", "(Ljava/lang/StackWalker$Option;)Ljava/lang/StackWalker", false));
insnList.add(new MethodInsnNode(INVOKEVIRTUAL, "java/lang/StackWalker", "getCallerClass", "()Ljava/lang/Class", false));
insnList.add(new VarInsnNode(Opcodes.ALOAD, 0));
insnList.add(new FieldInsnNode(Opcodes.GETFIELD, "org/bukkit/event/player/PlayerInteractEvent", "item", "Lorg/bukkit/inventory/ItemStack"));
insnList.add(new VarInsnNode(Opcodes.ILOAD, 1));

insnList.add(new MethodInsnNode(INVOKESTATIC, "me/cire3/sfbf/SFBFTransformer", "dump", "(Ljava/lang/Class;Ljava/lang/Object;Z)V", false));

methodNode_isCancelled.instructions.insertBefore(methodNode_isCancelled.instructions.getFirst(), insnList);

byteCode = classWriter.toByteArray();
ClassReader classReader = new ClassReader(byteCode);
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);

ClassNode classNode = new ClassNode();
classReader.accept(classNode, 0);

MethodNode methodNode_isCancelled = null;
for (MethodNode mn : classNode.methods) {
if ("setCancelled".equals(mn.name)) {
methodNode_isCancelled = mn;
break;
}
}

if (methodNode_isCancelled == null)
return byteCode;

InsnList insnList = new InsnList();
insnList.add(new VarInsnNode(Opcodes.ALOAD, 0));
insnList.add(new FieldInsnNode(Opcodes.GETSTATIC, "java/lang/StackWalker$Option", "RETAIN_CLASS_REFERENCE", "Ljava/lang/StackWalker$Option"));
insnList.add(new MethodInsnNode(INVOKESTATIC, "java/lang/StackWalker", "getInstance", "(Ljava/lang/StackWalker$Option;)Ljava/lang/StackWalker", false));
insnList.add(new MethodInsnNode(INVOKEVIRTUAL, "java/lang/StackWalker", "getCallerClass", "()Ljava/lang/Class", false));
insnList.add(new VarInsnNode(Opcodes.ALOAD, 0));
insnList.add(new FieldInsnNode(Opcodes.GETFIELD, "org/bukkit/event/player/PlayerInteractEvent", "item", "Lorg/bukkit/inventory/ItemStack"));
insnList.add(new VarInsnNode(Opcodes.ILOAD, 1));

insnList.add(new MethodInsnNode(INVOKESTATIC, "me/cire3/sfbf/SFBFTransformer", "dump", "(Ljava/lang/Class;Ljava/lang/Object;Z)V", false));

methodNode_isCancelled.instructions.insertBefore(methodNode_isCancelled.instructions.getFirst(), insnList);

byteCode = classWriter.toByteArray();
Only ran on target class obviously
dan1st
dan1stā€¢2mo ago
Can you show the stack trace?
cire
cireOPā€¢2mo ago
Stacktrace:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:491)
at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:503)
Caused by: java.lang.UnsupportedClassVersionError
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:169)
at me.cire3.sfbf.SFBFAgentEntryPoint.transform(SFBFAgentEntryPoint.java:39)
at me.cire3.sfbf.SFBFAgentEntryPoint.premain(SFBFAgentEntryPoint.java:17)
... 6 more
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message Outstanding error when calling method in invokeJavaAgentMainMethod at s\src\java.instrument\share\native\libinstrument\JPLISAgent.c line: 619
*** java.lang.instrument ASSERTION FAILED ***: "success" with message invokeJavaAgentMainMethod failed at s\src\java.instrument\share\native\libinstrument\JPLISAgent.c line: 459
*** java.lang.instrument ASSERTION FAILED ***: "result" with message agent load/premain call failed at s\src\java.instrument\share\native\libinstrument\JPLISAgent.c line: 422
FATAL ERROR in native method: processing of -javaagent failed, processJavaStart failed
Exception in thread "main" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:491)
at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:503)
Caused by: java.lang.UnsupportedClassVersionError
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:169)
at me.cire3.sfbf.SFBFAgentEntryPoint.transform(SFBFAgentEntryPoint.java:39)
at me.cire3.sfbf.SFBFAgentEntryPoint.premain(SFBFAgentEntryPoint.java:17)
... 6 more
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message Outstanding error when calling method in invokeJavaAgentMainMethod at s\src\java.instrument\share\native\libinstrument\JPLISAgent.c line: 619
*** java.lang.instrument ASSERTION FAILED ***: "success" with message invokeJavaAgentMainMethod failed at s\src\java.instrument\share\native\libinstrument\JPLISAgent.c line: 459
*** java.lang.instrument ASSERTION FAILED ***: "result" with message agent load/premain call failed at s\src\java.instrument\share\native\libinstrument\JPLISAgent.c line: 422
FATAL ERROR in native method: processing of -javaagent failed, processJavaStart failed
dan1st
dan1stā€¢2mo ago
Are you ure you are running it with java 17? How exactly are you running the application?
cire
cireOPā€¢2mo ago
yep javaw -javaagent:path/to/java/agent spigot-1.8.8.jar [server options here] ASM version 9.6 btw
dan1st
dan1stā€¢2mo ago
Does javaw -version show you any output?
cire
cireOPā€¢2mo ago
nvm, im actually running java -javaagent:path/to/agent -Xmx1G -Xms1G -jar spigot-1.8.8.jar java --version is openjdk 17.0.12
dan1st
dan1stā€¢2mo ago
Can you set the bytecode version with ClassWriter?
cire
cireOPā€¢2mo ago
i don't think so but im new to asm
dan1st
dan1stā€¢2mo ago
Where are you adding the instructions to the classWriter?
cire
cireOPā€¢2mo ago
Adding to the classNode which affects the classwriter
cire
cireOPā€¢2mo ago
No description
cire
cireOPā€¢2mo ago
oh i forgot cn.accept(cw) brb i'll test if that fixes
JavaBot
JavaBotā€¢2mo ago
When compiling Java applications to .class files, javac adds an integer representing the version it has been compiled for to the class file. Each Java version has a class file (major) version associated with it. A list with Java versions and the matching class file major version numbers can be found in this Stack Overflow question. In order to use a class, the JVM must be of a newer or equal version to the one specified in the class file.
dan1st
dan1stā€¢2mo ago
try cn.version = 52 before the cn.accept(cw)
cire
cireOPā€¢2mo ago
got it should i bother with minor version?
dan1st
dan1stā€¢2mo ago
no
cire
cireOPā€¢2mo ago
i dont think jdk cares k
dan1st
dan1stā€¢2mo ago
though maybe you need some bit magic
cire
cireOPā€¢2mo ago
oh yeah its like 16 msb is minor and 16 lsb is major right
dan1st
dan1stā€¢2mo ago
I think it might be ok just using 52 might be the less significant part
JavaBot
JavaBotā€¢2mo ago
šŸ’¤ Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.
cire
cireOPā€¢2mo ago
Okay, i downgraded to JVM 1.8
cire
cireOPā€¢2mo ago
No description
cire
cireOPā€¢2mo ago
No description
cire
cireOPā€¢2mo ago
to access sun.reflect
dan1st
dan1stā€¢2mo ago
If you are using Java 8 to run it, your agent needs to be compiled with that as well Why do you need that?
cire
cireOPā€¢2mo ago
yup i changed my gradle #getCallerClass my vm that needs the debugging runs jvm8 so StackWalker doesn't exist
dan1st
dan1stā€¢2mo ago
? If the target uses Java 8 then you'd need to compile your agent with java 8 anyways, yes
cire
cireOPā€¢2mo ago
i need to figure out whats calling the setCancelled method yup agent is now built with jvm8
dan1st
dan1stā€¢2mo ago
Can't you just set a breakpoint?
cire
cireOPā€¢2mo ago
3rd party jar on a vm not really
dan1st
dan1stā€¢2mo ago
What about just getting/printing the stack trace?
cire
cireOPā€¢2mo ago
im waiting for the vm to shutdown the server and reboot with new agent
dan1st
dan1stā€¢2mo ago
You can still do that
cire
cireOPā€¢2mo ago
i heavily dislike bytecode, getCallerClass is the easiest with bytecode huh
dan1st
dan1stā€¢2mo ago
You can attach a debugger and set breakpoints even for code that isn't yours as long as you can control the JVM in question
cire
cireOPā€¢2mo ago
ill take a look at that thanks
JavaBot
JavaBotā€¢2mo ago
If you are finished with your post, please close it. If you are not, please ignore this message. Note that you will not be able to send further messages here after this post have been closed but you will be able to create new posts.
cire
cireOPā€¢2mo ago
[SavageFactionsBugFixAgent] Transforming class PlayerInteractEvent
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386)
at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401)
Caused by: java.lang.ClassFormatError
at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:144)
at me.cire3.sfbf.SFBFAgentEntryPoint.transform(SFBFAgentEntryPoint.java:41)
at me.cire3.sfbf.SFBFAgentEntryPoint.premain(SFBFAgentEntryPoint.java:19)
... 6 more
FATAL ERROR in native method: processing of -javaagent failed
[SavageFactionsBugFixAgent] Transforming class PlayerInteractEvent
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386)
at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401)
Caused by: java.lang.ClassFormatError
at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:144)
at me.cire3.sfbf.SFBFAgentEntryPoint.transform(SFBFAgentEntryPoint.java:41)
at me.cire3.sfbf.SFBFAgentEntryPoint.premain(SFBFAgentEntryPoint.java:19)
... 6 more
FATAL ERROR in native method: processing of -javaagent failed
buh šŸ˜’
dan1st
dan1stā€¢2mo ago
What does it have to do with that?
cire
cireOPā€¢2mo ago
i have to write the dumping in bytecode
dan1st
dan1stā€¢2mo ago
It's pretty much new Exception("THIS IS INSERTED FOR DEBUGGING").printStackTrace()
cire
cireOPā€¢2mo ago
ohhhhhh shit
dan1st
dan1stā€¢2mo ago
and you can do the same in bytecode
cire
cireOPā€¢2mo ago
wait i'm stupid šŸ’€
dan1st
dan1stā€¢2mo ago
or you could use Thread.getStackTrace() to get the current stack trace as a StackTraceElement[]
cire
cireOPā€¢2mo ago
i dont even need to printStackTrace i can just throw the exception and check console omg im stupid
dan1st
dan1stā€¢2mo ago
or that but that has a significant side effect but as I said, there's also the option of attaching a debugger and setting a breakpoint
cire
cireOPā€¢2mo ago
i'm only running this for debugging to figure out which plugin is cancelling the event i think i'll just throw an exception if cancelled param is true and check logs
dan1st
dan1stā€¢2mo ago
Note that the code calling the method could catch the exception
JavaBot
JavaBotā€¢2mo ago
šŸ’¤ Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.
Want results from more Discord servers?
Add your server