diff options
author | Evgeny Mandrikov <Godin@users.noreply.github.com> | 2017-01-04 13:59:51 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-01-04 13:59:51 +0200 |
commit | b208594754d27c6c953c854ee044931f9d2bb9c7 (patch) | |
tree | 379e7e07974d212a6b7348ccca1bbc3505a11995 | |
parent | ed979068709c2f33b9e6ace44bb4d1618d56dc98 (diff) | |
download | jacoco-b208594754d27c6c953c854ee044931f9d2bb9c7.tar.gz |
Test that "ClassFormatError: Short length on BootstrapMethods" fixed by ASM upgrade (#462)
-rw-r--r-- | org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java | 126 | ||||
-rw-r--r-- | org.jacoco.doc/docroot/doc/changes.html | 3 |
2 files changed, 129 insertions, 0 deletions
diff --git a/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java new file mode 100644 index 00000000..987d11ef --- /dev/null +++ b/org.jacoco.core.test/src-java8/org/jacoco/core/test/validation/BootstrapMethodReferenceTest.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2009, 2017 Mountainminds GmbH & Co. KG and Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Evgeny Mandrikov - initial API and implementation + * + *******************************************************************************/ +package org.jacoco.core.test.validation; + +import static org.junit.Assert.assertEquals; + +import java.lang.invoke.CallSite; +import java.lang.invoke.ConstantCallSite; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.InvocationTargetException; + +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.RuntimeData; +import org.jacoco.core.runtime.SystemPropertiesRuntime; +import org.jacoco.core.test.TargetLoader; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Handle; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * Test of ASM bug <a href= + * "http://forge.ow2.org/tracker/?func=detail&aid=317748&group_id=23&atid=100023">#317748</a> + * that caused + * {@code java.lang.ClassFormatError: Short length on BootstrapMethods in class file} + * during instrumentation. + */ +public class BootstrapMethodReferenceTest { + + private final IRuntime runtime = new SystemPropertiesRuntime(); + private final Instrumenter instrumenter = new Instrumenter(runtime); + + @Before + public void setup() throws Exception { + runtime.startup(new RuntimeData()); + } + + @After + public void teardown() { + runtime.shutdown(); + } + + @Test + public void test() throws Exception { + final String className = "Example"; + + final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + cw.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, className, null, + "java/lang/Object", null); + + final MethodVisitor mv = cw.visitMethod( + Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "run", "()I", null, + null); + mv.visitCode(); + addCauseOfResizeInstructions(mv); + final MethodType methodType = MethodType.methodType(CallSite.class, + MethodHandles.Lookup.class, String.class, MethodType.class); + final Handle handle = new Handle(Opcodes.H_INVOKESTATIC, + this.getClass().getCanonicalName().replace('.', '/'), + "bootstrap", methodType.toMethodDescriptorString(), false); + mv.visitInvokeDynamicInsn("invoke", "()I", handle); + mv.visitInsn(Opcodes.IRETURN); + mv.visitMaxs(1, 0); + mv.visitEnd(); + + cw.visitEnd(); + + final byte[] original = cw.toByteArray(); + assertEquals(42, run(className, original)); + + final byte[] instrumented = instrumenter.instrument(original, + className); + assertEquals(42, run(className, instrumented)); + } + + private static int run(final String className, final byte[] bytes) + throws ClassNotFoundException, NoSuchMethodException, + InvocationTargetException, IllegalAccessException { + return (Integer) new TargetLoader().add(className, bytes) + .getMethod("run").invoke(null); + } + + /** + * Adds code that triggers usage of + * {@link org.objectweb.asm.MethodWriter#INSERTED_FRAMES} during + * instrumentation. + */ + private static void addCauseOfResizeInstructions(final MethodVisitor mv) { + mv.visitInsn(Opcodes.ICONST_0); + mv.visitInsn(Opcodes.ICONST_1); + final Label target = new Label(); + mv.visitJumpInsn(Opcodes.IFLE, target); + for (int i = 0; i < Short.MAX_VALUE; i++) { + mv.visitInsn(Opcodes.NOP); + } + mv.visitLabel(target); + } + + @SuppressWarnings("unused") + public static CallSite bootstrap(final MethodHandles.Lookup caller, + final String name, final MethodType type) throws Exception { + return new ConstantCallSite(caller.findStatic(BootstrapMethodReferenceTest.class, + "callTarget", MethodType.methodType(int.class))); + } + + @SuppressWarnings("unused") + public static int callTarget() { + return 42; + } + +} diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 37023188..92d39345 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -22,6 +22,9 @@ <h3>Fixed Bugs</h3> <ul> + <li>"<code>java.lang.ClassFormatError: Short length on BootstrapMethods in class file</code>" + caused by bug in ASM library + (GitHub <a href="https://github.com/jacoco/jacoco/issues/462">#462</a>).</li> <li>Do not recompute frames in case of large methods, otherwise <code>java.lang.ClassNotFoundException</code> might be thrown (GitHub <a href="https://github.com/jacoco/jacoco/issues/177">#177</a>).</li> |