Repository: Tencent/Shadow (language: java)

Issue:
NEW followed by no DUP was found
集成Admob sdk报错
![image](https://user-images.githubusercontent.com/3365208/227095051-f7b7e23e-6a71-42d2-9222-e7b26b703592.png)



Discussion / hints:
插件添加`implementation 'com.google.android.gms:play-services-ads:22.0.0'`可以复现问题。

类`com.google.android.gms.internal.ads.zzceh`反编译片段：
```
public final boolean onCreateWindow(android.webkit.WebView, boolean, boolean, android.os.Message);
    descriptor: (Landroid/webkit/WebView;ZZLandroid/os/Message;)Z
    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
    Code:
      stack=2, locals=5, args_size=5
         0: aload         4
         2: getfield      #236                // Field android/os/Message.obj:Ljava/lang/Object;
         5: checkcast     #30                 // class android/webkit/WebView$WebViewTransport
         8: astore_2
         9: new           #32                 // class android/webkit/WebView
        12: astore_3
        13: aload_3
        14: aload_1
        15: invokevirtual #237                // Method android/webkit/WebView.getContext:()Landroid/content/Context;
        18: invokespecial #240                // Method android/webkit/WebView."<init>":(Landroid/content/Context;)V
        21: aload_0
```

其中` 9: new `下一行不是`dup`，不符合 https://github.com/jboss-javassist/javassist/blob/700be6f6f9546e8af049b1a763ce27f1fde5955d/src/main/javassist/convert/TransformNewClass.java#L59 的预期。

错误在哪边还不确定。
根据：https://stackoverflow.com/a/8594701/11616914

可知dup是为了接下来调用init方法和areturn时返回值。

但我们这里遇到的代码并不需要把webview返回。通过测试发现，我们的javac确实会不管后面用不用这个new出来的对象，都跟上一个dup指令。但看起来理论上来说确实不是必要的。

也许这个有问题的类就是proguard等工具把这个无用的dup给优化掉了。那么问题就是javassist实现错误了。

Fix patch:
diff --git a/projects/sdk/core/transform-kit/src/main/java/javassist/EnhancedCodeConverter.java b/projects/sdk/core/transform-kit/src/main/java/javassist/EnhancedCodeConverter.java
index 44b507904..bd803b3c3 100644
--- a/projects/sdk/core/transform-kit/src/main/java/javassist/EnhancedCodeConverter.java
+++ b/projects/sdk/core/transform-kit/src/main/java/javassist/EnhancedCodeConverter.java
@@ -1,6 +1,7 @@
 package javassist;
 
 import javassist.convert.TransformCallExceptSuperCallToStatic;
+import javassist.convert.TransformNewClassFix;
 
 public class EnhancedCodeConverter extends CodeConverter {
 
@@ -8,4 +9,9 @@ public void redirectMethodCallExceptSuperCallToStatic(CtMethod origMethod, CtMet
         transformers = new TransformCallExceptSuperCallToStatic(transformers, origMethod,
                 substMethod);
     }
+
+    public void replaceNew(CtClass oldClass, CtClass newClass) {
+        transformers = new TransformNewClassFix(transformers, oldClass.getName(),
+                newClass.getName());
+    }
 }
diff --git a/projects/sdk/core/transform-kit/src/main/java/javassist/convert/TransformNewClassFix.java b/projects/sdk/core/transform-kit/src/main/java/javassist/convert/TransformNewClassFix.java
new file mode 100644
index 000000000..2348fcd37
--- /dev/null
+++ b/projects/sdk/core/transform-kit/src/main/java/javassist/convert/TransformNewClassFix.java
@@ -0,0 +1,70 @@
+package javassist.convert;
+
+import javassist.CannotCompileException;
+import javassist.CtClass;
+import javassist.bytecode.CodeAttribute;
+import javassist.bytecode.CodeIterator;
+import javassist.bytecode.ConstPool;
+
+/**
+ * 完全复制自TransformNewClass代码
+ * 去掉“"NEW followed by no DUP was found"检查
+ */
+final public class TransformNewClassFix extends Transformer {
+    private int nested;
+    private String classname, newClassName;
+    private int newClassIndex, newMethodNTIndex, newMethodIndex;
+
+    public TransformNewClassFix(Transformer next,
+                                String classname, String newClassName) {
+        super(next);
+        this.classname = classname;
+        this.newClassName = newClassName;
+    }
+
+    @Override
+    public void initialize(ConstPool cp, CodeAttribute attr) {
+        nested = 0;
+        newClassIndex = newMethodNTIndex = newMethodIndex = 0;
+    }
+
+    /**
+     * Modifies a sequence of
+     * NEW classname
+     * DUP
+     * ...
+     * INVOKESPECIAL classname:method
+     */
+    @Override
+    public int transform(CtClass clazz, int pos, CodeIterator iterator,
+                         ConstPool cp) throws CannotCompileException {
+        int index;
+        int c = iterator.byteAt(pos);
+        if (c == NEW) {
+            index = iterator.u16bitAt(pos + 1);
+            if (cp.getClassInfo(index).equals(classname)) {
+
+                if (newClassIndex == 0)
+                    newClassIndex = cp.addClassInfo(newClassName);
+
+                iterator.write16bit(newClassIndex, pos + 1);
+                ++nested;
+            }
+        } else if (c == INVOKESPECIAL) {
+            index = iterator.u16bitAt(pos + 1);
+            int typedesc = cp.isConstructor(classname, index);
+            if (typedesc != 0 && nested > 0) {
+                int nt = cp.getMethodrefNameAndType(index);
+                if (newMethodNTIndex != nt) {
+                    newMethodNTIndex = nt;
+                    newMethodIndex = cp.addMethodrefInfo(newClassIndex, nt);
+                }
+
+                iterator.write16bit(newMethodIndex, pos + 1);
+                --nested;
+            }
+        }
+
+        return pos;
+    }
+}
diff --git a/projects/sdk/core/transform/src/main/kotlin/com/tencent/shadow/core/transform/specific/ReceiverSupportTransform.kt b/projects/sdk/core/transform/src/main/kotlin/com/tencent/shadow/core/transform/specific/ReceiverSupportTransform.kt
index 79bfbc2ea..f5a324fe7 100644
--- a/projects/sdk/core/transform/src/main/kotlin/com/tencent/shadow/core/transform/specific/ReceiverSupportTransform.kt
+++ b/projects/sdk/core/transform/src/main/kotlin/com/tencent/shadow/core/transform/specific/ReceiverSupportTransform.kt
@@ -20,7 +20,11 @@ package com.tencent.shadow.core.transform.specific
 
 import com.tencent.shadow.core.transform_kit.SpecificTransform
 import com.tencent.shadow.core.transform_kit.TransformStep
-import javassist.*
+import javassist.CodeConverter
+import javassist.CtClass
+import javassist.CtMethod
+import javassist.Modifier
+import javassist.NotFoundException
 import javassist.compiler.Javac.CtFieldWithInit
 
 /**
@@ -70,7 +74,7 @@ class ReceiverSupportTransform : SpecificTransform() {
                     } catch (e: NotFoundException) {
                         null
                     }
-                if (onReceiveMethod != null) {
+                if (onReceiveMethod != null && !Modifier.isVolatile(onReceiveMethod.modifiers)) {
                     targetReceivers.add(ctClass)
                 }
             }
diff --git a/projects/sdk/core/transform/src/main/kotlin/com/tencent/shadow/core/transform/specific/WebViewTransform.kt b/projects/sdk/core/transform/src/main/kotlin/com/tencent/shadow/core/transform/specific/WebViewTransform.kt
index 4d7ea4fd3..e93a73109 100644
--- a/projects/sdk/core/transform/src/main/kotlin/com/tencent/shadow/core/transform/specific/WebViewTransform.kt
+++ b/projects/sdk/core/transform/src/main/kotlin/com/tencent/shadow/core/transform/specific/WebViewTransform.kt
@@ -20,8 +20,8 @@ package com.tencent.shadow.core.transform.specific
 
 import com.tencent.shadow.core.transform_kit.SpecificTransform
 import com.tencent.shadow.core.transform_kit.TransformStep
-import javassist.CodeConverter
 import javassist.CtClass
+import javassist.EnhancedCodeConverter
 
 class WebViewTransform : SpecificTransform() {
     companion object {
@@ -29,7 +29,7 @@ class WebViewTransform : SpecificTransform() {
         const val ShadowWebViewClassname = "com.tencent.shadow.core.runtime.ShadowWebView"
     }
 
-    val codeConverter = CodeConverter()
+    val codeConverter = EnhancedCodeConverter()
     override fun setup(allInputClass: Set<CtClass>) {
         codeConverter.replaceNew(
             mClassPool[AndroidWebViewClassname],


Test patch:
diff --git a/projects/sdk/core/transform/src/test/java/test/EggReceiver.java b/projects/sdk/core/transform/src/test/java/test/EggReceiver.java
new file mode 100644
index 000000000..851f80fed
--- /dev/null
+++ b/projects/sdk/core/transform/src/test/java/test/EggReceiver.java
@@ -0,0 +1,27 @@
+package test;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import java.util.List;
+
+abstract class EggReceiver extends BroadcastReceiver {
+    List<String> log;
+
+    EggReceiver(List<String> log) {
+        this.log = log;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        log.add("EggReceiver onReceive");
+    }
+
+    public static class FoxReceiver extends EggReceiver {
+        FoxReceiver(List<String> log) {
+            super(log);
+        }
+    }
+
+}
diff --git a/projects/sdk/core/transform/src/test/kotlin/com/tencent/shadow/core/transform/specific/ReceiverSupportTransformTest.kt b/projects/sdk/core/transform/src/test/kotlin/com/tencent/shadow/core/transform/specific/ReceiverSupportTransformTest.kt
index 9e15aa860..8eabf8b27 100644
--- a/projects/sdk/core/transform/src/test/kotlin/com/tencent/shadow/core/transform/specific/ReceiverSupportTransformTest.kt
+++ b/projects/sdk/core/transform/src/test/kotlin/com/tencent/shadow/core/transform/specific/ReceiverSupportTransformTest.kt
@@ -21,6 +21,8 @@ class ReceiverSupportTransformTest : AbstractTransformTest() {
                     "test.BarReceiver",
                     "test.CatReceiver",
                     "test.DogReceiver",
+                    "test.EggReceiver",
+                    "test.EggReceiver\$FoxReceiver",
                 )
         ].toMutableSet()