skylot / jadx

Dex to Java decompiler
Apache License 2.0
41.64k stars 4.88k forks source link

[java-input] Failed to translate java bytecode stack for unvisited jump (require StackMapTable support) #2271

Closed Milory closed 1 month ago

Milory commented 1 month ago

Issue details

platform

  1. macos 14.6.1 (23G93)
  2. jdk (Zulu 8.78.0.19-CA-macos-aarch64)
  3. Decompilation tools (jadx-gui 1.4.7)
  4. javassist (3.30.2-GA)

test code

public class Test {

    @Test
    @SneakyThrows
    @DisplayName("test Handler")
    public void test() {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("Point");
        CtMethod method = cc.getDeclaredMethod("parseIntDefault");
        method.instrument(
                new ExprEditor() {
                    @Override
                    public void edit(Handler h) throws CannotCompileException {
                        // Here the code will print an output in the catch code block
                        h.insertBefore("{ System.out.println(\"Before println\"); }");
                    }
                }
        );
        cc.writeFile();
    }
}

class Point {
    public int parseIntDefault(String num, int defaultNum) {
        try{
            return Integer.parseInt(num);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        return defaultNum;
    }
}

Decompile and view source code

$ jadx-gui Point.class
/* compiled from: Test.java */
/* loaded from: Point.class */
class Point {
    Point() {
    }

    /*  JADX ERROR: IndexOutOfBoundsException in pass: SSATransform
        java.lang.IndexOutOfBoundsException: bitIndex < 0: -1
            at java.util.BitSet.set(BitSet.java:444)
            at jadx.core.dex.visitors.ssa.LiveVarAnalysis.fillBasicBlockInfo(LiveVarAnalysis.java:73)
            at jadx.core.dex.visitors.ssa.LiveVarAnalysis.runAnalysis(LiveVarAnalysis.java:36)
            at jadx.core.dex.visitors.ssa.SSATransform.process(SSATransform.java:55)
            at jadx.core.dex.visitors.ssa.SSATransform.visit(SSATransform.java:41)
        */
    public int parseIntDefault(java.lang.String r5, int r6) {
        /*
            r4 = this;
            r0 = r5
            int r0 = java.lang.Integer.parseInt(r0)     // Catch: java.lang.NumberFormatException -> Lc
            return r0
        L5:
            r7 = r-1
            r-1 = r7
            r-1.printStackTrace()
            r-1 = r6
            return r-1
        Lc:
            r8 = move-exception
            java.io.PrintStream r-1 = java.lang.System.out
            java.lang.String r0 = "Before println"
            r-1.println(r0)
            r-1 = r8
            goto L5
        */
        throw new UnsupportedOperationException("Method not decompiled: Point.parseIntDefault(java.lang.String, int):int");
    }
}

Initially I suspected it was a bug in the javassist library, but after executing the code I found that it worked properly.

public class Test {

    @Test
    @SneakyThrows
    @DisplayName("test Handler")
    public void test() {
        ClassPool pool = ClassPool.getDefault();
        CtClass cc = pool.get("Point");
        CtMethod method = cc.getDeclaredMethod("parseIntDefault");
        method.instrument(
                new ExprEditor() {
                    @Override
                    public void edit(Handler h) throws CannotCompileException {
                       // Here the code will print an output in the catch code block
                        h.insertBefore("{ System.out.println(\"Before println\"); }");
                    }
                }
        );
        Class<?> aClass = cc.toClass();
        Object o = aClass.newInstance();
        Method parseIntDefault = aClass.getDeclaredMethod("parseIntDefault", String.class, int.class);
        System.err.println(parseIntDefault.invoke(o, "abc", 0));
    }
}

class Point {
    public int parseIntDefault(String num, int defaultNum) {
        try{
            return Integer.parseInt(num);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        return defaultNum;
    }
}

I found that the logic here is normal

Before println
java.lang.NumberFormatException: For input string: "abc"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:580)
    at java.lang.Integer.parseInt(Integer.java:615)
    at Point.parseIntDefault(Test.java:321)
    .......
0

Relevant log output or stacktrace

ERROR - [27] IndexOutOfBoundsException in pass: SSATransform in method: Point.parseIntDefault(java.lang.String, int):int, file: Point.class
java.lang.IndexOutOfBoundsException: bitIndex < 0: -1
    at java.util.BitSet.set(BitSet.java:444)
    at jadx.core.dex.visitors.ssa.LiveVarAnalysis.fillBasicBlockInfo(LiveVarAnalysis.java:73)
    at jadx.core.dex.visitors.ssa.LiveVarAnalysis.runAnalysis(LiveVarAnalysis.java:36)
    at jadx.core.dex.visitors.ssa.SSATransform.process(SSATransform.java:55)
    at jadx.core.dex.visitors.ssa.SSATransform.visit(SSATransform.java:41)
    at jadx.core.dex.visitors.DepthTraversal.visit(DepthTraversal.java:26)
    at jadx.core.dex.visitors.DepthTraversal.lambda$visit$1(DepthTraversal.java:14)
    at java.util.ArrayList.forEach(ArrayList.java:1259)
    at jadx.core.dex.visitors.DepthTraversal.visit(DepthTraversal.java:14)
    at jadx.core.ProcessClass.process(ProcessClass.java:72)
    at jadx.core.ProcessClass.generateCode(ProcessClass.java:115)
    at jadx.core.dex.nodes.ClassNode.decompile(ClassNode.java:383)
    at jadx.core.dex.nodes.ClassNode.decompile(ClassNode.java:307)
    at jadx.api.JavaClass.load(JavaClass.java:127)
    at jadx.api.JavaClass.getCodeInfo(JavaClass.java:61)
    at jadx.gui.treemodel.JClass.getCodeInfo(JClass.java:109)
    at jadx.gui.ui.TabbedPane.lambda$codeJump$2(TabbedPane.java:208)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:750)
2024-09-09 11:16:22.137 java[26036:6167736] TSM AdjustCapsLockLEDForKeyTransitionHandling - _ISSetPhysicalKeyboardCapsLockLED Inhibit

Provide sample and class/method full name

No response

Jadx version

1.4.7

jpstotz commented 1 month ago

Jadx v1.4.7 is a bit outdated as 1.5.0 had been released on Apr 20. Have you tried it if the bug is still present? You can also test our latest unstable version https://nightly.link/skylot/jadx/workflows/build-artifacts/master

skylot commented 1 month ago

I am not able to reproduce this issue with latest master. Also, it looks exactly like the issue fixed in PR #2056, so it should be resolved also in 1.5.0 release.

Milory commented 1 month ago

I am not able to reproduce this issue with latest master. Also, it looks exactly like the issue fixed in PR #2056, so it should be resolved also in 1.5.0 release.

I made two attempts here. The first time I tried to download the latest unstable version and found that the problem still exists.

image image

So the second time I tried to download the latest code from the master branch and compile it manually, but the problem still existed.

image image image
skylot commented 1 month ago

@Milory please share your Point.class file.

Milory commented 1 month ago

Point.class.zip

Due to the inability to upload class files, I have compressed the files into zip files. Please check

skylot commented 1 month ago

@Milory looks like this issue will take some time to fix. Turns out, current implementation of stack to register translator in jadx-input plugin can't handle blocks accessible only with jumps from later instructions because of unknown stack info. Such info can be parsed from StackMapTable section, so I need to support this.

As a workaround for now, you can enable Preferences->Decompilation->Use dx/d8 to convert java bytecode option in jadx-gui or --use-dx in jadx-cli. This option enable conversion of java bytecode to dex internally using dx or d8 tools, such approach slightly slower and if d8 kicks in it might change code slightly, but it will work :rofl:

skylot commented 1 month ago

Done. Please check latest unstable build: https://nightly.link/skylot/jadx/workflows/build-artifacts/master