Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
Milory opened this issue Sep 9, 2024 · 7 comments
Assignees
Labels
bug Core Issues in jadx-core module java-input

Comments

@Milory
Copy link

Milory commented Sep 9, 2024

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

@Milory Milory added bug Core Issues in jadx-core module labels Sep 9, 2024
@jpstotz
Copy link
Collaborator

jpstotz commented Sep 9, 2024

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
Copy link
Owner

skylot commented Sep 9, 2024

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
Copy link
Author

Milory commented Sep 11, 2024

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
Copy link
Owner

skylot commented Sep 11, 2024

@Milory please share your Point.class file.

@Milory
Copy link
Author

Milory commented Sep 12, 2024

Point.class.zip

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

@skylot skylot self-assigned this Sep 12, 2024
@skylot skylot changed the title [core] The javassist.expr.Handler class calls the insertBefore() operation code. After decompiling the code, an UnsupportedOperationException is prompted, but the code logic is normal. [java-input] Failed to translate java bytecode stack for unvisited jump (require StackMapTable support) Sep 13, 2024
@skylot
Copy link
Owner

skylot commented Sep 13, 2024

@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 🤣

@skylot
Copy link
Owner

skylot commented Sep 14, 2024

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

@skylot skylot closed this as completed Sep 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Core Issues in jadx-core module java-input
Projects
None yet
Development

No branches or pull requests

3 participants