开发者

Why are decompiled java programs not always directly compilable and what are the parts that are not?

So I am trying to make slight valid legal changes to a compiled java program. I am decompiling it using JD-GUI for Mac. For the most part the decompiled code is error free but there are some strange things like undeclared variables, multiple identical variable declarations and just some strange statements which are not readily compilable. Some of the strange statements in the decompiled code are really puzzling. I have been having trouble with one switch statement in particular:

    switch ($SWITCH_TABLE$PackageName$ClassName$InnerEnumName()[getPlatform().ordinal()])

Where PackageName.ClassName is the class this statement is in, and InnerEnumName is an inner enum within ClassName. Also note that getPlatform() is a method in ClassName which returns an enum of type InnerEnumName

The weird part is when I just stripped this class of 开发者_如何学JAVAthe problematic statements, compiled it, and inserted it back into the program, it started to work but had a few strange bugs. For example when I changed the switch statement to

    switch (getPlatform().ordinal())

it started hitting case 3 (the third case and the case for value 3) when it is supposed to hit case 4 (once again the fourth case as well as the case for value 4)


Decompiling is always going to be imperfect. The decompiler must take the bytecodes and reverse-engineer the original source, figuring out where loops are, what the loop controls are, etc. I would never expect it to be flawless for non-trivial programs.

In the case of the $ names, these are names generated internally in the process of "faking" inner classes (since the JVM doesn't actually support inner classes). The decompiler is apparently doing an imperfect job of figuring out what the inner classes are and appropriately naming them and the objects the compiler created to fake things out. Someone familiar with the bytecode format could probably sort things out fairly quickly, but, like the rest, it's non-trivial.

(In this particular case it appears that the compiler, for some reason, created a mapping table from inner enum values to some other values, and when you "stripped" the statement you lost that mapping.)

[I'll add that one big problem that decompilers have is that javac is such a moving target. In particular things like inner class implementations are being constantly tweaked, so what worked one week may fail the next, with the next +.001 version of the compiler.]


JD-GUI (JD?) has issues it seems. Try to find a better decompiler? Too bad jad's ancient - it used to be good.


At the risk of resurrecting an ancient question - by stripping out the array indirection on the ordinal, the meaning of the original switch is changed.

I wrote this up here : http://www.benf.org/other/cfr/switch-on-enum.html

The salient bit is:

The first enum -> integer function that springs to mind is .ordinal(). However - there are a couple of problems with this:

The enum class we're switching on isn't fixed - we can't take a copy of the target ordinals for the case statements - someone might change the enum's definition! Someone might even remove the field we use as a case label.

So we need a lookup function which isn't dependant on the ordinal of the enum value being fixed (i.e. resolves it at run time), and can cope with a field of the enum being removed.

Hence the array you stripped out - it's a runtime map between ordinals in the enum statement, and the location in your switch statement.

What's really interesting here is that it means Javac creates an extra inner class per switch-on-enum - Fun!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜