From 407303160488ea0d2aff5d0022d87f6e8a4c5f26 Mon Sep 17 00:00:00 2001 From: Rafael Winterhalter Date: Fri, 15 Jul 2016 15:51:00 +0200 Subject: [PATCH] Added stack monitor for advice code to avoid that stack underflows generate verifier errors for irregular advice code. --- .travis.yml | 2 +- .../src/main/java/net/bytebuddy/asm/Advice.java | 14 +++++++++++++- .../utility/StackAwareMethodVisitor.java | 10 ++++++++++ .../AgentBuilderDefaultApplicationTest.java | 2 +- .../bytebuddy/test/utility/IntegrationRule.java | 2 +- .../utility/StackAwareMethodVisitorTest.java | 17 +++++++++++++++++ 6 files changed, 43 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2145c35ea75..73a0afa8d04 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ matrix: - jdk: oraclejdk7 env: TARGET=-Pjava7 -script: mvn verify $TARGET -Pintegration -Dnet.bytebuddy.travis=true +script: mvn verify $TARGET -Pintegration -Dnet.bytebuddy.test.travis=true after_success: - mvn clean cobertura:cobertura coveralls:report -Pintegration diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/asm/Advice.java b/byte-buddy-dep/src/main/java/net/bytebuddy/asm/Advice.java index e214f83bbe2..17b4c34c1e1 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/asm/Advice.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/asm/Advice.java @@ -5784,7 +5784,9 @@ protected ExceptionTableSubstitutor(MethodVisitor methodVisitor) { public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { substitutions.put(start, labels.get(index++)); substitutions.put(end, labels.get(index++)); - substitutions.put(handler, labels.get(index++)); + Label actualHandler = labels.get(index++); + substitutions.put(handler, actualHandler); + ((CodeTranslationVisitor) mv).propagateHandler(actualHandler); } @Override @@ -6328,6 +6330,16 @@ protected CodeTranslationVisitor(MethodVisitor methodVisitor, endOfMethod = new Label(); } + /** + * Propagates a label for an exception handler that is typically suppressed by the overlaying + * {@link Resolved.AdviceMethodInliner.ExceptionTableSubstitutor}. + * + * @param label The label to register as a target for an exception handler. + */ + protected void propagateHandler(Label label) { + ((StackAwareMethodVisitor) mv).register(label, Collections.singletonList(StackSize.SINGLE)); + } + @Override public void visitParameter(String name, int modifiers) { /* do nothing */ diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/utility/StackAwareMethodVisitor.java b/byte-buddy-dep/src/main/java/net/bytebuddy/utility/StackAwareMethodVisitor.java index 847c5093a79..8bb0fe70e59 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/utility/StackAwareMethodVisitor.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/utility/StackAwareMethodVisitor.java @@ -146,6 +146,16 @@ private void doDrain(List stackSizes) { } } + /** + * Explicitly registers a label to define a given stack state. + * + * @param label The label to register a stack state for. + * @param stackSizes The stack sizes to assume when reaching the supplied label. + */ + public void register(Label label, List stackSizes) { + sizes.put(label, stackSizes); + } + @Override public void visitInsn(int opcode) { switch (opcode) { diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/agent/builder/AgentBuilderDefaultApplicationTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/agent/builder/AgentBuilderDefaultApplicationTest.java index ecfdee22bd9..0a2eb9e5a57 100644 --- a/byte-buddy-dep/src/test/java/net/bytebuddy/agent/builder/AgentBuilderDefaultApplicationTest.java +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/agent/builder/AgentBuilderDefaultApplicationTest.java @@ -64,7 +64,7 @@ public class AgentBuilderDefaultApplicationTest { @Parameterized.Parameters public static Collection data() { // Travis runs out of memory if all of these tests are run. This property serves as a protection (on some profiles). - if (Boolean.getBoolean("net.bytebuddy.travis")) { + if (Boolean.getBoolean("net.bytebuddy.test.travis")) { Logger.getLogger("net.bytebuddy").info("Only running agent application with a single type locator on Travis CI server"); return Arrays.asList(new Object[][]{{AgentBuilder.TypeLocator.Default.FAST}}); } diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/test/utility/IntegrationRule.java b/byte-buddy-dep/src/test/java/net/bytebuddy/test/utility/IntegrationRule.java index 1f37212f657..aa0dbfff141 100644 --- a/byte-buddy-dep/src/test/java/net/bytebuddy/test/utility/IntegrationRule.java +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/test/utility/IntegrationRule.java @@ -10,7 +10,7 @@ public class IntegrationRule implements MethodRule { - private static final String PROPERTY_KEY = "net.bytebuddy.property.integration"; + private static final String PROPERTY_KEY = "net.bytebuddy.test.integration"; private final boolean integration; diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/utility/StackAwareMethodVisitorTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/utility/StackAwareMethodVisitorTest.java index 265aace98af..65993f9e106 100644 --- a/byte-buddy-dep/src/test/java/net/bytebuddy/utility/StackAwareMethodVisitorTest.java +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/utility/StackAwareMethodVisitorTest.java @@ -9,9 +9,12 @@ import org.junit.rules.TestRule; import org.mockito.InOrder; import org.mockito.Mock; +import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; +import java.util.Arrays; + import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.mockito.Mockito.*; @@ -125,6 +128,20 @@ public void testDrainFreeList() throws Exception { verifyNoMoreInteractions(this.methodVisitor); } + @Test + public void testManualRegistration() throws Exception { + StackAwareMethodVisitor methodVisitor = new StackAwareMethodVisitor(this.methodVisitor, methodDescription); + Label label = new Label(); + methodVisitor.register(label, Arrays.asList(StackSize.DOUBLE, StackSize.SINGLE)); + methodVisitor.visitLabel(label); + methodVisitor.drainStack(); + InOrder inOrder = inOrder(this.methodVisitor); + inOrder.verify(this.methodVisitor).visitLabel(label); + inOrder.verify(this.methodVisitor).visitInsn(Opcodes.POP); + inOrder.verify(this.methodVisitor).visitInsn(Opcodes.POP2); + verifyNoMoreInteractions(this.methodVisitor); + } + @Test public void testStackCanUnderflow() throws Exception { StackAwareMethodVisitor methodVisitor = new StackAwareMethodVisitor(this.methodVisitor, methodDescription);