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;








0















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);











share|improve this question
























  • 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


















0















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);











share|improve this question
























  • 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














0












0








0








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);











share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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





    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


















  • 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

















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













3 Answers
3






active

oldest

votes


















2














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 :)






share|improve this answer






























    1














    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.






    share|improve this answer






























      0














      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





      share|improve this answer

























        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
        );



        );













        draft saved

        draft discarded


















        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









        2














        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 :)






        share|improve this answer



























          2














          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 :)






          share|improve this answer

























            2












            2








            2







            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 :)






            share|improve this answer













            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 :)







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Mar 8 at 19:17









            LppEddLppEdd

            10k21749




            10k21749























                1














                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.






                share|improve this answer



























                  1














                  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.






                  share|improve this answer

























                    1












                    1








                    1







                    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.






                    share|improve this answer













                    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.







                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Mar 9 at 2:31









                    AntimonyAntimony

                    27.5k66980




                    27.5k66980





















                        0














                        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





                        share|improve this answer





























                          0














                          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





                          share|improve this answer



























                            0












                            0








                            0







                            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





                            share|improve this answer















                            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






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Mar 8 at 19:17

























                            answered Mar 8 at 19:12









                            Amit BeraAmit Bera

                            4,3611630




                            4,3611630



























                                draft saved

                                draft discarded
















































                                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.




                                draft saved


                                draft discarded














                                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





















































                                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







                                Popular posts from this blog

                                1928 у кіно

                                Захаров Федір Захарович

                                Ель Греко