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

Instrumenting constructors fails with VerificationError when interacting with classes that lack stack map frames #35

Closed
kyle-cackett opened this issue Jan 31, 2020 · 10 comments

Comments

@kyle-cackett
Copy link

The Java Allocation Instrumenter passes the ClassWriter.COMPUTE_MAXS flag to the ASM ClassWriter during constructor instrumentation. According to the ASM Javadocs:

for classes whose version is Opcodes.V1_7 of more, this option requires valid stack map frames. The maximum stack size is then computed from these frames, and from the bytecode instructions in between. If stack map frames are not present or must be recomputed, used COMPUTE_FRAMES instead.

Other Java agents (such as the JaCoCo code coverage agent) may use ASM to write modified class files without computing stack map frames by passing 0 as a flag to the ClassWriter object. This flag is mapped to MethodWriter.COMPUTE_NOTHING which means that neither stack map frames nor the maximum stack size are computed. The interaction between agents which modify bytecode and do not recompute stack map frames and the Allocation Instrumenter leads to VerifyErrors when the JVM attempts to verify the twice-modified classes.

To improve the resiliency of the Allocation Instrumenter, we recommend passing the ClassWriter.COMPUTE_FRAMES flag to the ASM ClassWriter in place of the ClassWriter.COMPUTE_MAXS flag.

I have a minimal reproducible test case which has been used to verify that making the change suggested above does resolve the issue; I can provide you with it if necessary. In parallel, I am also opening an issue with the JaCoCo project to adjust the flags that they pass to their ClassWriter. However, in theory any bytecode-modifying agent could elect not to write stack map frames so it seems most effectively to address the issue here in the Allocation Instrumenter.

@kyle-cackett
Copy link
Author

Minimal reproducible example can be found here: https://github.com/kyle-cackett/class-instrumentation

@jhmanson
Copy link
Contributor

Yeah, I think that was just a mistake - we do the right thing in the AllocationInstrumenter class. I'll push a fix. Thanks for reporting it.

@kyle-cackett
Copy link
Author

@jhmanson do you have an idea of when you think this fix will be pushed? This issue is keeping us from moving to Java 8 so we're trying to decide whether to wait for a fix upstream or fork the library and apply the patch below:

a/src/main/java/com/google/monitoring/runtime/instrumentation/ConstructorInstrumenter.java b/src/main/java/com/google/monitoring/runtime/instrumentation/ConstructorInstrumenter.java
index 933d4c4..e53ed5a 100644
--- a/src/main/java/com/google/monitoring/runtime/instrumentation/ConstructorInstrumenter.java
+++ b/src/main/java/com/google/monitoring/runtime/instrumentation/ConstructorInstrumenter.java
@@ -116,7 +116,7 @@ public class ConstructorInstrumenter implements ClassFileTransformer {
   public static byte[] instrument(byte[] originalBytes, Class<?> classBeingRedefined) {
     try {
       ClassReader cr = new ClassReader(originalBytes);
-      ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
+      ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
       VerifyingClassAdapter vcw = new VerifyingClassAdapter(cw, originalBytes, cr.getClassName());
       ClassVisitor adapter = new ConstructorClassAdapter(vcw, classBeingRedefined);

@jhmanson
Copy link
Contributor

jhmanson commented Feb 7, 2020

Sorry about that. I pushed the patch internally, and then my machine died, so it fell off my radar. I can push it tomorrow morning.

jhmanson added a commit that referenced this issue Feb 7, 2020
This is in line with general guidance for ClassWriter use and what we do
in other places.

Reported at #35

PiperOrigin-RevId: 292488953
@jhmanson
Copy link
Contributor

jhmanson commented Feb 7, 2020

All done!

@jhmanson jhmanson closed this as completed Feb 7, 2020
@kyle-cackett
Copy link
Author

Thank you!

@kyle-cackett
Copy link
Author

@jhmanson Do you have any plans for an upcoming release which will contain this fix? We'd like to depend on an official version if possible.

@jhmanson
Copy link
Contributor

Hm... I think I don't have the right permissions to release to sonatype etc. Maybe @cushon or @cgdecker can help?

@kyle-cackett
Copy link
Author

@cushon @cgdecker Do you have a sense for when we might expect a new release of the allocation instrumenter containing this fix?

@cgdecker
Copy link
Member

Sorry for the long delay... I've released java-allocation-instrumenter 3.3.0 to Maven Central with this fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants