From b06844ff06740ccdbb7e24a898afa6530f1b66a1 Mon Sep 17 00:00:00 2001 From: ExE Boss Date: Tue, 6 Sep 2022 09:30:00 +0000 Subject: [PATCH 1/4] =?UTF-8?q?Fix=C2=A0`SignatureWriter`=20when=C2=A0a?= =?UTF-8?q?=C2=A0generic=C2=A0type=20has=C2=A0a=C2=A0depth=20over=C2=A030?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../asm/signature/SignatureWriter.java | 55 ++++++++++++++++--- .../asm/signature/SignatureWriterTest.java | 43 +++++++++++++++ 2 files changed, 90 insertions(+), 8 deletions(-) diff --git a/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java b/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java index 2217a88ae..327521afb 100644 --- a/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java +++ b/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java @@ -27,6 +27,8 @@ // THE POSSIBILITY OF SUCH DAMAGE. package org.objectweb.asm.signature; +import java.util.ArrayList; +import java.util.List; import org.objectweb.asm.Opcodes; /** @@ -52,7 +54,7 @@ public class SignatureWriter extends SignatureVisitor { /** * The stack used to keep track of class types that have arguments. Each element of this stack is * a boolean encoded in one bit. The top of the stack is the least significant bit. Pushing false - * = *2, pushing true = *2+1, popping = /2. + * {@code <<= 1}, pushing true {@code <<= 1; |= 1}, popping {@code >>>= 1}. * *

Class type arguments must be surrounded with '<' and '>' and, because * @@ -62,12 +64,18 @@ public class SignatureWriter extends SignatureVisitor { * SignatureWriter instances), * * - *

we need a stack to properly balance these 'parentheses'. A new element is pushed on this + *

we need a stack to properly balance these angle brackets. A new element is pushed on this * stack for each new visited type, and popped when the visit of this type ends (either is * visitEnd, or because visitInnerClassType is called). */ private int argumentStack; + /** The sum of the depths of {@link #argumentStack} and {@link #deepArgStack}. */ + private long argumentStackDepth; + + /** Used when {@link #argumentStack} can no longer fit into a single 32-bit integer. */ + private List deepArgStack; + /** Constructs a new {@link SignatureWriter}. */ public SignatureWriter() { super(/* latest api =*/ Opcodes.ASM9); @@ -159,7 +167,7 @@ public class SignatureWriter extends SignatureVisitor { stringBuilder.append(name); // Pushes 'false' on the stack, meaning that this type does not have type arguments (as far as // we can tell at this point). - argumentStack *= 2; + pushArgStack(false); } @Override @@ -169,7 +177,7 @@ public class SignatureWriter extends SignatureVisitor { stringBuilder.append(name); // Pushes 'false' on the stack, meaning that this type does not have type arguments (as far as // we can tell at this point). - argumentStack *= 2; + pushArgStack(false); } @Override @@ -177,7 +185,7 @@ public class SignatureWriter extends SignatureVisitor { // If the top of the stack is 'false', this means we are visiting the first type argument of the // currently visited type. We therefore need to append a '<', and to replace the top stack // element with 'true' (meaning that the current type does have type arguments). - if (argumentStack % 2 == 0) { + if (argumentStackDepth > 0 && !peekArgStack()) { argumentStack |= 1; stringBuilder.append('<'); } @@ -189,7 +197,7 @@ public class SignatureWriter extends SignatureVisitor { // If the top of the stack is 'false', this means we are visiting the first type argument of the // currently visited type. We therefore need to append a '<', and to replace the top stack // element with 'true' (meaning that the current type does have type arguments). - if (argumentStack % 2 == 0) { + if (argumentStackDepth > 0 && !peekArgStack()) { argumentStack |= 1; stringBuilder.append('<'); } @@ -232,9 +240,40 @@ public class SignatureWriter extends SignatureVisitor { // If the top of the stack is 'true', this means that some type arguments have been visited for // the type whose visit is now ending. We therefore need to append a '>', and to pop one element // from the stack. - if (argumentStack % 2 == 1) { + if (argumentStackDepth > 0 && popArgStack()) { stringBuilder.append('>'); } - argumentStack /= 2; + } + + private boolean peekArgStack() { + assert argumentStackDepth > 0 : this; + return (argumentStack & 1) == 1; + } + + private void pushArgStack(boolean state) { + if (argumentStackDepth > 0 && (argumentStackDepth % 32) == 0) { + if (deepArgStack == null) { + deepArgStack = new ArrayList<>(5); + } + deepArgStack.add(argumentStack); + argumentStack = 0; + } else { + argumentStack <<= 1; + } + argumentStackDepth++; + if (state) { + argumentStack |= 1; + } + } + + private boolean popArgStack() { + assert argumentStackDepth > 0 : this; + boolean result = (argumentStack & 1) == 1; + argumentStack >>>= 1; + argumentStackDepth--; + if (argumentStackDepth > 0 && (argumentStackDepth % 32) == 0) { + argumentStack = deepArgStack.remove(deepArgStack.size() - 1); + } + return result; } } diff --git a/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java b/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java index be1ba0122..e9aefa628 100644 --- a/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java +++ b/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java @@ -29,6 +29,7 @@ package org.objectweb.asm.signature; import static org.junit.jupiter.api.Assertions.assertEquals; +import java.util.stream.IntStream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.objectweb.asm.test.AsmTest; @@ -62,4 +63,46 @@ class SignatureWriterTest extends AsmTest { assertEquals(signature, signatureWriter.toString()); } + + static IntStream deepSignatures() { + return IntStream.range(0, 48); + } + + @ParameterizedTest + @MethodSource("deepSignatures") + void testWrite_deepSignature(int depth) { + SignatureWriter signatureWriter = new SignatureWriter(); + String expected = writeDeepSignature(signatureWriter, depth); + assertEquals(expected, signatureWriter.toString(), "depth=" + depth); + } + + private String writeDeepSignature(SignatureVisitor signatureVisitor, int maxDepth) { + StringBuilder expected = new StringBuilder(); + writeDeepSignatureInner(signatureVisitor, expected, 0, maxDepth); + return expected.toString(); + } + + private void writeDeepSignatureInner(SignatureVisitor signatureVisitor, StringBuilder expected, int currentDepth, int maxDepth) { + signatureVisitor.visitClassType(TEST_GENERIC); + expected.append('L' + TEST_GENERIC); + if (currentDepth < maxDepth) { + expected.append(""); + } + signatureVisitor.visitEnd(); + expected.append(';'); + } + + private static final String TEST_OPEN = "TestOpen"; + private static final String TEST_GENERIC = "TestGeneric"; + private static final String TEST_CLOSE = "TestClose"; } -- GitLab From be2b87ecedb3a3a2daefca432996c342fa406c76 Mon Sep 17 00:00:00 2001 From: ExE Boss Date: Wed, 7 Sep 2022 07:50:00 +0000 Subject: [PATCH 2/4] =?UTF-8?q?fixup!=20Fix=C2=A0`SignatureWriter`=20when?= =?UTF-8?q?=C2=A0a=C2=A0generic=C2=A0type=20has=C2=A0a=C2=A0depth=20over?= =?UTF-8?q?=C2=A030?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/objectweb/asm/signature/SignatureWriter.java | 2 +- .../objectweb/asm/signature/SignatureWriterTest.java | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java b/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java index 327521afb..c834eef05 100644 --- a/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java +++ b/asm/src/main/java/org/objectweb/asm/signature/SignatureWriter.java @@ -250,7 +250,7 @@ public class SignatureWriter extends SignatureVisitor { return (argumentStack & 1) == 1; } - private void pushArgStack(boolean state) { + private void pushArgStack(final boolean state) { if (argumentStackDepth > 0 && (argumentStackDepth % 32) == 0) { if (deepArgStack == null) { deepArgStack = new ArrayList<>(5); diff --git a/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java b/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java index e9aefa628..6d037ce6d 100644 --- a/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java +++ b/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java @@ -70,19 +70,23 @@ class SignatureWriterTest extends AsmTest { @ParameterizedTest @MethodSource("deepSignatures") - void testWrite_deepSignature(int depth) { + void testWrite_deepSignature(final int depth) { SignatureWriter signatureWriter = new SignatureWriter(); String expected = writeDeepSignature(signatureWriter, depth); assertEquals(expected, signatureWriter.toString(), "depth=" + depth); } - private String writeDeepSignature(SignatureVisitor signatureVisitor, int maxDepth) { + private String writeDeepSignature(final SignatureVisitor signatureVisitor, final int maxDepth) { StringBuilder expected = new StringBuilder(); writeDeepSignatureInner(signatureVisitor, expected, 0, maxDepth); return expected.toString(); } - private void writeDeepSignatureInner(SignatureVisitor signatureVisitor, StringBuilder expected, int currentDepth, int maxDepth) { + private void writeDeepSignatureInner( + final SignatureVisitor signatureVisitor, + final StringBuilder expected, + final int currentDepth, + final int maxDepth) { signatureVisitor.visitClassType(TEST_GENERIC); expected.append('L' + TEST_GENERIC); if (currentDepth < maxDepth) { -- GitLab From 85c2d1fbc4d40e52d320fc5519bcd5bdd9bdf2a4 Mon Sep 17 00:00:00 2001 From: ExE Boss Date: Wed, 7 Sep 2022 08:00:00 +0000 Subject: [PATCH 3/4] =?UTF-8?q?fixup!=20Fix=C2=A0`SignatureWriter`=20when?= =?UTF-8?q?=C2=A0a=C2=A0generic=C2=A0type=20has=C2=A0a=C2=A0depth=20over?= =?UTF-8?q?=C2=A030?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/objectweb/asm/signature/SignatureWriterTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java b/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java index 6d037ce6d..aec7224a3 100644 --- a/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java +++ b/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java @@ -41,6 +41,10 @@ import org.objectweb.asm.test.AsmTest; */ class SignatureWriterTest extends AsmTest { + private static final String TEST_CLOSE = "TestClose"; + private static final String TEST_GENERIC = "TestGeneric"; + private static final String TEST_OPEN = "TestOpen"; + @ParameterizedTest @MethodSource({ "org.objectweb.asm.signature.SignaturesProviders#classSignatures", @@ -105,8 +109,4 @@ class SignatureWriterTest extends AsmTest { signatureVisitor.visitEnd(); expected.append(';'); } - - private static final String TEST_OPEN = "TestOpen"; - private static final String TEST_GENERIC = "TestGeneric"; - private static final String TEST_CLOSE = "TestClose"; } -- GitLab From dac1a9fd6526a2bf985f88c59b624b5e8dbae515 Mon Sep 17 00:00:00 2001 From: ExE Boss Date: Wed, 7 Sep 2022 08:20:00 +0000 Subject: [PATCH 4/4] =?UTF-8?q?fixup!=20Fix=C2=A0`SignatureWriter`=20when?= =?UTF-8?q?=C2=A0a=C2=A0generic=C2=A0type=20has=C2=A0a=C2=A0depth=20over?= =?UTF-8?q?=C2=A030?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/objectweb/asm/signature/SignatureWriterTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java b/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java index aec7224a3..3717f4bdf 100644 --- a/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java +++ b/asm/src/test/java/org/objectweb/asm/signature/SignatureWriterTest.java @@ -99,7 +99,8 @@ class SignatureWriterTest extends AsmTest { v.visitClassType(TEST_OPEN); v.visitEnd(); - writeDeepSignatureInner(signatureVisitor.visitTypeArgument('='), expected, currentDepth + 1, maxDepth); + writeDeepSignatureInner( + signatureVisitor.visitTypeArgument('='), expected, currentDepth + 1, maxDepth); v = signatureVisitor.visitTypeArgument('='); v.visitClassType(TEST_CLOSE); -- GitLab