Java 8 / Fernflower Decompiler: Bug or Feature Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern) Data science time! April 2019 and salary with experience The Ask Question Wizard is Live!Is Java “pass-by-reference” or “pass-by-value”?How do I efficiently iterate over each entry in a Java Map?What is the difference between public, protected, package-private and private in Java?How do I “decompile” Java class files?How do I read / convert an InputStream into a String in Java?When to use LinkedList over ArrayList in Java?How do I generate random integers within a specific range in Java?decompiling DEX into Java sourcecodeHow do I convert a String to an int in Java?Creating a memory leak with Java
Why didn't Eitri join the fight?
How to find all the available tools in mac terminal?
When a candle burns, why does the top of wick glow if bottom of flame is hottest?
Is grep documentation wrong?
Why do we bend a book to keep it straight?
When the Haste spell ends on a creature, do attackers have advantage against that creature?
Why are the trig functions versine, haversine, exsecant, etc, rarely used in modern mathematics?
Is safe to use va_start macro with this as parameter?
Is it a good idea to use CNN to classify 1D signal?
Maximum summed powersets with non-adjacent items
Is it common practice to audition new musicians one-on-one before rehearsing with the entire band?
How do pianists reach extremely loud dynamics?
Is it cost-effective to upgrade an old-ish Giant Escape R3 commuter bike with entry-level branded parts (wheels, drivetrain)?
Withdrew £2800, but only £2000 shows as withdrawn on online banking; what are my obligations?
How can I use the Python library networkx from Mathematica?
8 Prisoners wearing hats
What is the meaning of the new sigil in Game of Thrones Season 8 intro?
Can an alien society believe that their star system is the universe?
How come Sam didn't become Lord of Horn Hill?
Fundamental Solution of the Pell Equation
Is there such thing as an Availability Group failover trigger?
Compare a given version number in the form major.minor.build.patch and see if one is less than the other
What does できなさすぎる means?
Most bit efficient text communication method?
Java 8 / Fernflower Decompiler: Bug or Feature
Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)
Data science time! April 2019 and salary with experience
The Ask Question Wizard is Live!Is Java “pass-by-reference” or “pass-by-value”?How do I efficiently iterate over each entry in a Java Map?What is the difference between public, protected, package-private and private in Java?How do I “decompile” Java class files?How do I read / convert an InputStream into a String in Java?When to use LinkedList over ArrayList in Java?How do I generate random integers within a specific range in Java?decompiling DEX into Java sourcecodeHow do I convert a String to an int in Java?Creating a memory leak with Java
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
OpenJDK 1.8.0_191
I compiled and decompiled a piece of code below using Fernflower.
public class Decompile
public static void main(String[] args)
final int VAL = 20;
System.out.println(VAL);
The output is:
public class Decompile
public static void main(String[] args)
boolean VAL = true;
System.out.println(20);
I'm confused, how did VAL
become a boolean?
UPDATE:
In Intellij IDEA decompiled code looks like this:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class Decompile
public Decompile()
public static void main(String[] args)
int VAL = true;
System.out.println(20);
java decompiling decompiler
add a comment |
OpenJDK 1.8.0_191
I compiled and decompiled a piece of code below using Fernflower.
public class Decompile
public static void main(String[] args)
final int VAL = 20;
System.out.println(VAL);
The output is:
public class Decompile
public static void main(String[] args)
boolean VAL = true;
System.out.println(20);
I'm confused, how did VAL
become a boolean?
UPDATE:
In Intellij IDEA decompiled code looks like this:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class Decompile
public Decompile()
public static void main(String[] args)
int VAL = true;
System.out.println(20);
java decompiling decompiler
Have you tried other decompilers for comparison?
– scrutari
Mar 8 at 19:09
2
@scrutari yes, JDCore, CFR and Procyon show VAL as int
– GrastaSsS
Mar 8 at 19:10
1
TheVAL
is a constant which gets inlined, so while there might be a record the variable existed, it probably doesn't know how to work out what it was.
– Peter Lawrey
Mar 8 at 19:11
1
P.S. if you like working at the bytecode level, ASM is worth a look, as it is the foundation for many other bytecode manipulation libraries. asm.ow2.io/asm4-guide.pdf
– LppEdd
Mar 8 at 19:36
add a comment |
OpenJDK 1.8.0_191
I compiled and decompiled a piece of code below using Fernflower.
public class Decompile
public static void main(String[] args)
final int VAL = 20;
System.out.println(VAL);
The output is:
public class Decompile
public static void main(String[] args)
boolean VAL = true;
System.out.println(20);
I'm confused, how did VAL
become a boolean?
UPDATE:
In Intellij IDEA decompiled code looks like this:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class Decompile
public Decompile()
public static void main(String[] args)
int VAL = true;
System.out.println(20);
java decompiling decompiler
OpenJDK 1.8.0_191
I compiled and decompiled a piece of code below using Fernflower.
public class Decompile
public static void main(String[] args)
final int VAL = 20;
System.out.println(VAL);
The output is:
public class Decompile
public static void main(String[] args)
boolean VAL = true;
System.out.println(20);
I'm confused, how did VAL
become a boolean?
UPDATE:
In Intellij IDEA decompiled code looks like this:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
public class Decompile
public Decompile()
public static void main(String[] args)
int VAL = true;
System.out.println(20);
java decompiling decompiler
java decompiling decompiler
edited Mar 8 at 19:17
GrastaSsS
asked Mar 8 at 19:07
GrastaSsSGrastaSsS
127113
127113
Have you tried other decompilers for comparison?
– scrutari
Mar 8 at 19:09
2
@scrutari yes, JDCore, CFR and Procyon show VAL as int
– GrastaSsS
Mar 8 at 19:10
1
TheVAL
is a constant which gets inlined, so while there might be a record the variable existed, it probably doesn't know how to work out what it was.
– Peter Lawrey
Mar 8 at 19:11
1
P.S. if you like working at the bytecode level, ASM is worth a look, as it is the foundation for many other bytecode manipulation libraries. asm.ow2.io/asm4-guide.pdf
– LppEdd
Mar 8 at 19:36
add a comment |
Have you tried other decompilers for comparison?
– scrutari
Mar 8 at 19:09
2
@scrutari yes, JDCore, CFR and Procyon show VAL as int
– GrastaSsS
Mar 8 at 19:10
1
TheVAL
is a constant which gets inlined, so while there might be a record the variable existed, it probably doesn't know how to work out what it was.
– Peter Lawrey
Mar 8 at 19:11
1
P.S. if you like working at the bytecode level, ASM is worth a look, as it is the foundation for many other bytecode manipulation libraries. asm.ow2.io/asm4-guide.pdf
– LppEdd
Mar 8 at 19:36
Have you tried other decompilers for comparison?
– scrutari
Mar 8 at 19:09
Have you tried other decompilers for comparison?
– scrutari
Mar 8 at 19:09
2
2
@scrutari yes, JDCore, CFR and Procyon show VAL as int
– GrastaSsS
Mar 8 at 19:10
@scrutari yes, JDCore, CFR and Procyon show VAL as int
– GrastaSsS
Mar 8 at 19:10
1
1
The
VAL
is a constant which gets inlined, so while there might be a record the variable existed, it probably doesn't know how to work out what it was.– Peter Lawrey
Mar 8 at 19:11
The
VAL
is a constant which gets inlined, so while there might be a record the variable existed, it probably doesn't know how to work out what it was.– Peter Lawrey
Mar 8 at 19:11
1
1
P.S. if you like working at the bytecode level, ASM is worth a look, as it is the foundation for many other bytecode manipulation libraries. asm.ow2.io/asm4-guide.pdf
– LppEdd
Mar 8 at 19:36
P.S. if you like working at the bytecode level, ASM is worth a look, as it is the foundation for many other bytecode manipulation libraries. asm.ow2.io/asm4-guide.pdf
– LppEdd
Mar 8 at 19:36
add a comment |
3 Answers
3
active
oldest
votes
The bytecode is
L0
LINENUMBER 5 L0
BIPUSH 20
ISTORE 1
L1
LINENUMBER 6 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
BIPUSH 20
INVOKEVIRTUAL java/io/PrintStream.println (I)V
As you can see the BIPUSH
pushes 20
onto the stack, then ISTORE
takes the value and store it into the local variable.
It's a Fernflower
problem.
For your interest the output for bytecode version 55
is
int VAL = true;
System.out.println(20);
You can see decompilers can be wrong :)
add a comment |
The underlying issue is that Java bytecode has no notion of booleans, byte, chars, or shorts (except in type signatures). All local variables with those types are instead compiled to ints. Boolean true and false are compiled to 1
and 0
respectively.
What this means is that the decompiler has to guess whether a given local variable was supposed to be a boolean or an integer type. In this case, the value 20
is stored in the variable, which will never be stored in a variable of boolean type in Java code, so it should be easy for the decompiler to guess that it is an integer type based on the context. But it appears that Fernflower's boolean guesser is not that sophisticated.
For what it's worth, this is an inherently hard problem. Especially when you consider that non-Java bytecode doesn't have to follow the same patterns that Java does. It is perfectly valid for bytecode to use the same variable in both integer and boolean contexts. The Krakatau decompiler has a pretty sophisticated inference step for guessing whether variables should be booleans or not, but it will still get things wrong in situations like this.
add a comment |
It works like that as compiler
do some optimization
during the generation of the byte code
. As VAL = 20; is final and not changing, so it can put the 20
in place of VAL
without impacting
the functionality in the second statement. Now the decompiler
has only byte code
and when it goes to read the Byte code it found 20
as inline in the second line
. Byte code generated by the code as below:
0: bipush 20
2: istore_1
3: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream;
6: bipush 20
8: invokevirtual #26 // Method java/io/PrintStream.println:(I)V
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55069491%2fjava-8-fernflower-decompiler-bug-or-feature%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
The bytecode is
L0
LINENUMBER 5 L0
BIPUSH 20
ISTORE 1
L1
LINENUMBER 6 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
BIPUSH 20
INVOKEVIRTUAL java/io/PrintStream.println (I)V
As you can see the BIPUSH
pushes 20
onto the stack, then ISTORE
takes the value and store it into the local variable.
It's a Fernflower
problem.
For your interest the output for bytecode version 55
is
int VAL = true;
System.out.println(20);
You can see decompilers can be wrong :)
add a comment |
The bytecode is
L0
LINENUMBER 5 L0
BIPUSH 20
ISTORE 1
L1
LINENUMBER 6 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
BIPUSH 20
INVOKEVIRTUAL java/io/PrintStream.println (I)V
As you can see the BIPUSH
pushes 20
onto the stack, then ISTORE
takes the value and store it into the local variable.
It's a Fernflower
problem.
For your interest the output for bytecode version 55
is
int VAL = true;
System.out.println(20);
You can see decompilers can be wrong :)
add a comment |
The bytecode is
L0
LINENUMBER 5 L0
BIPUSH 20
ISTORE 1
L1
LINENUMBER 6 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
BIPUSH 20
INVOKEVIRTUAL java/io/PrintStream.println (I)V
As you can see the BIPUSH
pushes 20
onto the stack, then ISTORE
takes the value and store it into the local variable.
It's a Fernflower
problem.
For your interest the output for bytecode version 55
is
int VAL = true;
System.out.println(20);
You can see decompilers can be wrong :)
The bytecode is
L0
LINENUMBER 5 L0
BIPUSH 20
ISTORE 1
L1
LINENUMBER 6 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
BIPUSH 20
INVOKEVIRTUAL java/io/PrintStream.println (I)V
As you can see the BIPUSH
pushes 20
onto the stack, then ISTORE
takes the value and store it into the local variable.
It's a Fernflower
problem.
For your interest the output for bytecode version 55
is
int VAL = true;
System.out.println(20);
You can see decompilers can be wrong :)
answered Mar 8 at 19:17
LppEddLppEdd
10k21749
10k21749
add a comment |
add a comment |
The underlying issue is that Java bytecode has no notion of booleans, byte, chars, or shorts (except in type signatures). All local variables with those types are instead compiled to ints. Boolean true and false are compiled to 1
and 0
respectively.
What this means is that the decompiler has to guess whether a given local variable was supposed to be a boolean or an integer type. In this case, the value 20
is stored in the variable, which will never be stored in a variable of boolean type in Java code, so it should be easy for the decompiler to guess that it is an integer type based on the context. But it appears that Fernflower's boolean guesser is not that sophisticated.
For what it's worth, this is an inherently hard problem. Especially when you consider that non-Java bytecode doesn't have to follow the same patterns that Java does. It is perfectly valid for bytecode to use the same variable in both integer and boolean contexts. The Krakatau decompiler has a pretty sophisticated inference step for guessing whether variables should be booleans or not, but it will still get things wrong in situations like this.
add a comment |
The underlying issue is that Java bytecode has no notion of booleans, byte, chars, or shorts (except in type signatures). All local variables with those types are instead compiled to ints. Boolean true and false are compiled to 1
and 0
respectively.
What this means is that the decompiler has to guess whether a given local variable was supposed to be a boolean or an integer type. In this case, the value 20
is stored in the variable, which will never be stored in a variable of boolean type in Java code, so it should be easy for the decompiler to guess that it is an integer type based on the context. But it appears that Fernflower's boolean guesser is not that sophisticated.
For what it's worth, this is an inherently hard problem. Especially when you consider that non-Java bytecode doesn't have to follow the same patterns that Java does. It is perfectly valid for bytecode to use the same variable in both integer and boolean contexts. The Krakatau decompiler has a pretty sophisticated inference step for guessing whether variables should be booleans or not, but it will still get things wrong in situations like this.
add a comment |
The underlying issue is that Java bytecode has no notion of booleans, byte, chars, or shorts (except in type signatures). All local variables with those types are instead compiled to ints. Boolean true and false are compiled to 1
and 0
respectively.
What this means is that the decompiler has to guess whether a given local variable was supposed to be a boolean or an integer type. In this case, the value 20
is stored in the variable, which will never be stored in a variable of boolean type in Java code, so it should be easy for the decompiler to guess that it is an integer type based on the context. But it appears that Fernflower's boolean guesser is not that sophisticated.
For what it's worth, this is an inherently hard problem. Especially when you consider that non-Java bytecode doesn't have to follow the same patterns that Java does. It is perfectly valid for bytecode to use the same variable in both integer and boolean contexts. The Krakatau decompiler has a pretty sophisticated inference step for guessing whether variables should be booleans or not, but it will still get things wrong in situations like this.
The underlying issue is that Java bytecode has no notion of booleans, byte, chars, or shorts (except in type signatures). All local variables with those types are instead compiled to ints. Boolean true and false are compiled to 1
and 0
respectively.
What this means is that the decompiler has to guess whether a given local variable was supposed to be a boolean or an integer type. In this case, the value 20
is stored in the variable, which will never be stored in a variable of boolean type in Java code, so it should be easy for the decompiler to guess that it is an integer type based on the context. But it appears that Fernflower's boolean guesser is not that sophisticated.
For what it's worth, this is an inherently hard problem. Especially when you consider that non-Java bytecode doesn't have to follow the same patterns that Java does. It is perfectly valid for bytecode to use the same variable in both integer and boolean contexts. The Krakatau decompiler has a pretty sophisticated inference step for guessing whether variables should be booleans or not, but it will still get things wrong in situations like this.
answered Mar 9 at 2:31
AntimonyAntimony
27.5k66980
27.5k66980
add a comment |
add a comment |
It works like that as compiler
do some optimization
during the generation of the byte code
. As VAL = 20; is final and not changing, so it can put the 20
in place of VAL
without impacting
the functionality in the second statement. Now the decompiler
has only byte code
and when it goes to read the Byte code it found 20
as inline in the second line
. Byte code generated by the code as below:
0: bipush 20
2: istore_1
3: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream;
6: bipush 20
8: invokevirtual #26 // Method java/io/PrintStream.println:(I)V
add a comment |
It works like that as compiler
do some optimization
during the generation of the byte code
. As VAL = 20; is final and not changing, so it can put the 20
in place of VAL
without impacting
the functionality in the second statement. Now the decompiler
has only byte code
and when it goes to read the Byte code it found 20
as inline in the second line
. Byte code generated by the code as below:
0: bipush 20
2: istore_1
3: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream;
6: bipush 20
8: invokevirtual #26 // Method java/io/PrintStream.println:(I)V
add a comment |
It works like that as compiler
do some optimization
during the generation of the byte code
. As VAL = 20; is final and not changing, so it can put the 20
in place of VAL
without impacting
the functionality in the second statement. Now the decompiler
has only byte code
and when it goes to read the Byte code it found 20
as inline in the second line
. Byte code generated by the code as below:
0: bipush 20
2: istore_1
3: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream;
6: bipush 20
8: invokevirtual #26 // Method java/io/PrintStream.println:(I)V
It works like that as compiler
do some optimization
during the generation of the byte code
. As VAL = 20; is final and not changing, so it can put the 20
in place of VAL
without impacting
the functionality in the second statement. Now the decompiler
has only byte code
and when it goes to read the Byte code it found 20
as inline in the second line
. Byte code generated by the code as below:
0: bipush 20
2: istore_1
3: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream;
6: bipush 20
8: invokevirtual #26 // Method java/io/PrintStream.println:(I)V
edited Mar 8 at 19:17
answered Mar 8 at 19:12
Amit BeraAmit Bera
4,3611630
4,3611630
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55069491%2fjava-8-fernflower-decompiler-bug-or-feature%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Have you tried other decompilers for comparison?
– scrutari
Mar 8 at 19:09
2
@scrutari yes, JDCore, CFR and Procyon show VAL as int
– GrastaSsS
Mar 8 at 19:10
1
The
VAL
is a constant which gets inlined, so while there might be a record the variable existed, it probably doesn't know how to work out what it was.– Peter Lawrey
Mar 8 at 19:11
1
P.S. if you like working at the bytecode level, ASM is worth a look, as it is the foundation for many other bytecode manipulation libraries. asm.ow2.io/asm4-guide.pdf
– LppEdd
Mar 8 at 19:36