judovana/java-runtime-decompiler

Provide feedback from getClass when class is not found (not throw `RuntimeException`)

Closed this issue · 10 comments

(CFR decompiler)

Processing com.google.gson.JsonPrimitive
java.lang.RuntimeException: Class com.google.gson.internal. not found in loaded classes.
        at org.jrd.agent.InstrumentationProvider.findClass(InstrumentationProvider.java:80)
        at org.jrd.agent.InstrumentationProvider.findClassBody(InstrumentationProvider.java:69)
        at org.jrd.agent.AgentActionWorker.sendByteCode(AgentActionWorker.java:193)
        at org.jrd.agent.AgentActionWorker.executeRequest(AgentActionWorker.java:107)
        at org.jrd.agent.AgentActionWorker.<init>(AgentActionWorker.java:41)
        at org.jrd.agent.ConnectionDelegator.run(ConnectionDelegator.java:78)
java.lang.RuntimeException: Agent returned error: java.lang.RuntimeException: Class com.google.gson.internal. not found in loaded classes.
        at org.jrd.backend.communication.Communicate.readResponse(Communicate.java:117)
        at org.jrd.backend.communication.CallDecompilerAgent.submitRequest(CallDecompilerAgent.java:48)
        at org.jrd.backend.core.DecompilerRequestReceiver.getResponse(DecompilerRequestReceiver.java:144)
        at org.jrd.backend.core.DecompilerRequestReceiver.getByteCodeAction(DecompilerRequestReceiver.java:197)
        at org.jrd.backend.core.DecompilerRequestReceiver.processRequest(DecompilerRequestReceiver.java:77)
        at org.jrd.frontend.frame.main.DecompilationController.submitRequest(DecompilationController.java:570)
        at org.jrd.backend.data.Cli.obtainClass(Cli.java:796)
        at org.jrd.backend.communication.RuntimeCompilerConnector$JrdClassesProvider.getClass(RuntimeCompilerConnector.java:44)
        at io.github.mkoncek.classpathless.impl.CompilerJavac.transitiveImport(CompilerJavac.java:123)
        at io.github.mkoncek.classpathless.impl.CompilerJavac.compileClass(CompilerJavac.java:151)
...

The problem is with the class $Gson$Preconditions, someone thought it would be a good idea to use $ in a normal class name. Nevertheless it is completely legal to name your class with dollars. Problem then is, i have no way of knowing whether it actually is a nested class or not, i can only find out by requesting getClass from JRD. However if you don't find a class with the prefixed name, you end up throwing a generic RuntimeException.
I think it would be better to simply return an empty collection (or throw a more specific exception).

The problem is with the class $Gson$Preconditions, someone thought it would be a good idea to use $ in a normal class name. Nevertheless it is completely legal to name your class with dollars.

What an interesting edge case! Will fix.

(CFR decompiler)

More broadly speaking it is any decompiler wrapper implementing the decompileWithInners(...) method, probably.

@mkoncek, looking into it, I have no problem decompiling $Gson$Preconditions with CFR, not even with CFR_old before 09a8933 fixing #96. What class were you trying to decompile? What is the version of Cfr.jar in your Cfr decompiler wrapper plugin? (Configure -> Plugins)

It was there before you edited it: Processing com.google.gson.JsonPrimitive. It imports $Gson$Preconditions.

Oops, misclicked on that one, my bad.

This probably also needs slight adjustments on CPLC side, but in order to play around with it I first need JRD not to crash.
(Although maybe i can just catch the exception)

Can confirm that catching RuntimeException on my side makes the file compile, but that is just an observation, not a solution.

image

image

image

Need more info to replicate the bug. With the latest CFR jar, CFR wrapper and JRD, I have no issue decompiling $Gson$Precondition nor JsonPrimitive in both CLI and GUI. (it is not lazy-loaded on startup)

Note that the PIDs of the target processes are different every time to not cross-contaminate.

#205 has probably fixed this, but it still floods stderr.
Although i don't think yoou can do much about it.

Expanded stderr messages in #206 to be more explanatory.

However because the error logging happens much deeper than in either JrdClassesProvider or Cli::obtainClass/Cli::initClass, we cannot outright remove the log calls.

One option would be to temporarily switch System.err with a dummy PrintStream, but that's worth considering in another issue. This one will close with #206.