Commit 82bcacf4 authored by Eric Bruneton's avatar Eric Bruneton
Browse files

Merge branch '317897-incorrect-on-method-enter-in-advice-adapter' into 'master'

Resolve "AdviceAdapter incorrectly emits onMethodEnter from a try-catch block in a constructor"

Closes #317897

See merge request asm/asm!298
parents 9e6c4e79 1d64cfbb
......@@ -456,10 +456,10 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
doVisitMethodInsn(opcode, descriptor);
doVisitMethodInsn(opcode, name, descriptor);
}
private void doVisitMethodInsn(final int opcode, final String descriptor) {
private void doVisitMethodInsn(final int opcode, final String name, final String descriptor) {
if (isConstructor && !superClassConstructorCalled) {
for (Type argumentType : Type.getArgumentTypes(descriptor)) {
popValue();
......@@ -474,7 +474,9 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
break;
case INVOKESPECIAL:
Object value = popValue();
if (value == UNINITIALIZED_THIS && !superClassConstructorCalled) {
if (value == UNINITIALIZED_THIS
&& !superClassConstructorCalled
&& name.equals("<init>")) {
superClassConstructorCalled = true;
onMethodEnter();
}
......@@ -500,7 +502,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
doVisitMethodInsn(Opcodes.INVOKEDYNAMIC, descriptor);
doVisitMethodInsn(Opcodes.INVOKEDYNAMIC, name, descriptor);
}
@Override
......
......@@ -601,6 +601,37 @@ public class AdviceAdapterTest extends AsmTest {
assertDoesNotThrow(() -> buildClassWithMethod(outputMethod).newInstance());
}
@Test
public void testAllMethods_constructorWithHandlerFallthroughToPrivateMethodCall() {
Label label1 = new Label();
Label label2 = new Label();
Label label3 = new Label();
MethodNode inputMethod =
new MethodNodeBuilder("<init>", "(I)V", 2, 2)
.trycatch(label1, label2, label2)
.aload(0)
.methodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)
// After instrumentation, expect a before advice here, before instruction #2.
.label(label1)
.go(label3)
.label(label2)
.astore(1)
.label(label3)
.aload(0)
.methodInsn(Opcodes.INVOKESPECIAL, "C", "privateMethod", "()V", false)
// After instrumentation, expect an after advice here, before instruction #9.
.vreturn()
.build();
MethodNode outputMethod = new MethodNode(Opcodes.ACC_PUBLIC, "<init>", "(I)V", null, null);
inputMethod.accept(new BasicAdviceAdapter(outputMethod));
MethodNode expectedMethod =
new ExpectedMethodBuilder(inputMethod).withBeforeAdviceAt(2).withAfterAdviceAt(9).build();
assertEquals(toText(expectedMethod), toText(outputMethod));
assertDoesNotThrow(() -> buildClassWithMethod(outputMethod).newInstance());
}
@ParameterizedTest
@MethodSource(ALL_CLASSES_AND_ALL_APIS)
public void testAllMethods_precompiledClass(
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment