Work around the NPE bug in ClassRemapper of ASM. ASM throws an NPE in
MethodRemapper when MethodRemapper is chained after MethodNode and there is
compressed stack map frame in a method.
RELNOTES: n/a
@@ -19,8 +19,10 @@ import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.ClassRemapper;
+import org.objectweb.asm.commons.MethodRemapper;
import org.objectweb.asm.commons.Remapper;
/** Utility class to prefix or unprefix class names of core library classes */
@@ -112,7 +114,7 @@ class CoreLibraryRewriter {
@Override
public void accept(ClassVisitor cv, Attribute[] attrs, int flags) {
cv =
- new ClassRemapper(
+ new ClassRemapperWithBugFix(
cv,
new Remapper() {
@Override
@@ -137,7 +139,7 @@ class CoreLibraryRewriter {
this.cv = this.writer;
if (prefix.length() != 0) {
this.cv =
- new ClassRemapper(
+ new ClassRemapperWithBugFix(
this.cv,
new Remapper() {
@Override
@@ -152,4 +154,38 @@ class CoreLibraryRewriter {
return writer.toByteArray();
}
}
+
+ /** ClassRemapper subclass to work around b/36654936 (caused by ASM bug 317785) */
+ private static class ClassRemapperWithBugFix extends ClassRemapper {
+
+ public ClassRemapperWithBugFix(ClassVisitor cv, Remapper remapper) {
+ super(cv, remapper);
+ }
+
+ @Override
+ protected MethodVisitor createMethodRemapper(MethodVisitor mv) {
+ return new MethodRemapper(mv, this.remapper) {
+ private final boolean isArrayNullOrEmpty(Object[] array) {
+ return array == null || array.length == 0;
+ }
+
+ @Override
+ public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
+ if (isArrayNullOrEmpty(local)) {
+ nLocal = 0;
+ }
+ if (isArrayNullOrEmpty(stack)) {
+ nStack = 0;
+ }
+ /*
+ * In {@code FrameNode.accept(MethodVisitor)}, when the frame is Opcodes.F_CHOP,
+ * it is possible that nLocal is greater than 0, and local is null, which causes
+ * MethodRemapper to throw a NPE. So the patch is to make sure that the
+ * {@code nLocal<=local.length} and {@code nStack<=stack.length}
+ */
+ super.visitFrame(type, nLocal, local, nStack, stack);
+ }
+ };
+ }
+ }
}
