Apparent bug in javac's dead code elimination

Vicente-Arturo Romero-Zaldivar vicente.romero at oracle.com
Mon Sep 8 21:55:33 UTC 2014


Bug closed as not an issue.

Vicente

On 09/08/2014 02:36 PM, Chris Kitching wrote:
> Ah!
>
> Apologies for not spotting that myself.
> Glad to know it's fixed in newer versions, anyway. Thanks for your time!
>
> On 08/09/14 14:17, Jonathan Gibbons wrote:
>> Chris,
>>
>> Update:
>> I see the problem when using JDK 1.7.0.
>> I do not see the problem using using JDK 1.8.0 or later.
>>
>> -- Jon
>>
>> On 09/08/2014 02:01 PM, Jonathan Gibbons wrote:
>>> Chris,
>>>
>>> I agree that javac should only generate valid class files, and that JVMS
>>> is quite explicit about when a Code attribute is required to be present
>>> or absent.
>>>
>>> I tried some simple experiments of my own and your Cake.java example.
>>> In neither case do I see any instances of a Code attribute being missing
>>> when required (or present when not.)  In other words, I have not yet seen
>>> anything akin to what would give rise to the message you saw with the
>>> mozilla class:
>>>
>>> java.lang.ClassFormatError: Absent Code attribute in method that is not
>>> native or abstract in class file
>>>
>>> Given that it is not an error for javac to be generating an empty
>>> class file
>>> for its own internal purposes, do you have any additional evidence that
>>> javac is creating an invalid class file?
>>>
>>> I was using current builds of JDK 9 for my experiments; what version of
>>> JDK are you using?
>>>
>>> -- Jon
>>>
>>> On 09/08/2014 12:27 PM, Chris Kitching wrote:
>>>> Hello,
>>>>
>>>> "What do you need this class for?"
>>>>
>>>> I don't need this class for anything, I merely need the compiler to
>>>> promise to never emit classes that are invalid. Surely that is something
>>>> is should be expected to do?
>>>> The current behaviour causes issues for tools that process all classes
>>>> in a given directory.
>>>>
>>>>
>>>> On 08/09/14 11:58, Vicente-Arturo Romero-Zaldivar wrote:
>>>>> Hi Chris,
>>>>>
>>>>> Yes I agree with Jon, this is not a bug. I have been checking the patch
>>>>> for [1] see [2]. In the code you pasted Cake$1 has nothing to do with
>>>>> the inner class defined in the 'if (false)' sentence. It's just javac
>>>>> reusing an existing class name that would have been a 'real' class if
>>>>> the condition were different to false. What do you need this class for?
>>>>> You shouldn't need to deal with it. The problem is that we don't have a
>>>>> way to say: "hey this is not a common inner class this is just a token,
>>>>> exact term access constructor tag, to provide access to a private
>>>>> constructor". The only difference between a token and a 'common' inner
>>>>> class is that the token is empty, no methods in it.
>>>>>
>>>>> Thanks,
>>>>> Vicente
>>>>>
>>>>> [1] https://bugs.openjdk.java.net/browse/JDK-7199823
>>>>> [2] http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/a51a8dac0a2f
>>>>>
>>>>>
>>>>>
>>>>> On 09/08/2014 10:26 AM, Jonathan Gibbons wrote:
>>>>>> I believe the existence of Cake$1 is part of javac's handling of
>>>>>> allowing any private code in SomeClass to access any private code in
>>>>>> SomeOtherClass.
>>>>>>
>>>>>> -- Jon
>>>>>>
>>>>>> On 09/06/2014 08:06 PM, Chris Kitching wrote:
>>>>>>> Greetings,
>>>>>>>
>>>>>>> As you probably know, javac does a bit of dead code elimintion: it'll
>>>>>>> get rid of redundant constructs like if (false) and suchlike.
>>>>>>>
>>>>>>> Consider, then, this ridiculous example:
>>>>>>>
>>>>>>> public class Cake {
>>>>>>>        public void start() {
>>>>>>>            if (false) {
>>>>>>>                new Runnable() {
>>>>>>>                    @Override
>>>>>>>                    public void run() {
>>>>>>>                        // Whatever
>>>>>>>                    }
>>>>>>>                };
>>>>>>>            }
>>>>>>>        }
>>>>>>>
>>>>>>>        private static class SomeClass {
>>>>>>>        }
>>>>>>> }
>>>>>>>
>>>>>>> As you might expect, this produces two classes: Cake and
>>>>>>> Cake$SomeClass.class, and all is well.
>>>>>>>
>>>>>>> Now consider this slightly more ridiculous example:
>>>>>>>
>>>>>>> public class Cake {
>>>>>>>        public void start() {
>>>>>>>            if (false) {
>>>>>>>                new Runnable() {
>>>>>>>                    @Override
>>>>>>>                    public void run() {
>>>>>>>                        // Whatever
>>>>>>>                    }
>>>>>>>                };
>>>>>>>            }
>>>>>>>        }
>>>>>>>
>>>>>>>        private static class SomeClass {
>>>>>>>        }
>>>>>>>
>>>>>>>        private static class SomeOtherClass extends SomeClass {
>>>>>>>        }
>>>>>>> }
>>>>>>>
>>>>>>>
>>>>>>> All I did was add an empty SomeOtherClass extending SomeClass.
>>>>>>> This example produces out these classes:
>>>>>>>
>>>>>>> Cake$1
>>>>>>> Cake
>>>>>>> Cake$SomeClass
>>>>>>> Cake$SomeOtherClass
>>>>>>>
>>>>>>> Cake$1, the Runnable wrapped in `if (false)`, has suddenly appeared.
>>>>>>> Oddly, the bytecode in Cake$1 does not change as you alter the
>>>>>>> contents
>>>>>>> of run(). It's as if javac is omitting the contents of the methods of
>>>>>>> the class, but not the class itself (but it did so earlier before we
>>>>>>> added SomeOtherClass!)
>>>>>>> Cake$1 is also corrupt. Attempts to load the class using the
>>>>>>> Reflection
>>>>>>> API (because, you know, that's a sane thing to do) fail with a
>>>>>>> stacktrace like this:
>>>>>>>
>>>>>>> java.lang.ClassFormatError: Absent Code attribute in method that
>>>>>>> is not
>>>>>>> native or abstract in class file
>>>>>>> org/mozilla/gecko/animation/PropertyAnimator$1
>>>>>>>         at java.lang.ClassLoader.defineClass1(Native Method)
>>>>>>>         at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
>>>>>>>         at
>>>>>>> java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
>>>>>>>
>>>>>>>         at
>>>>>>> java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
>>>>>>>         at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
>>>>>>>         at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
>>>>>>>         at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
>>>>>>>         at java.security.AccessController.doPrivileged(Native Method)
>>>>>>>         at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
>>>>>>>         at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
>>>>>>>         at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
>>>>>>>
>>>>>>> And that's exactly what just happened to Mozilla:
>>>>>>> https://bugzilla.mozilla.org/show_bug.cgi?id=1063991
>>>>>>>
>>>>>>> (that also provides a bit of context, as well as the interesting
>>>>>>> consequence that the Cake$1 you get if you move the Runnable
>>>>>>> outside the
>>>>>>> if is different to the one you get in the situation described above
>>>>>>> (when, really, no Cake$1 at all should exist).
>>>>>>>
>>>>>>> Perhaps the desugaring step for inner classes is getting a little...
>>>>>>> overzealous?
>>>>>>>
>>>>>>> I've been able to reproduce this with javac 7 and 8. I've not
>>>>>>> tried it
>>>>>>> on the current JDK 9 snapshot.



More information about the compiler-dev mailing list