Breaking binary compatibility due to adding private method to an interface compiled inconsistently

David M. Lloyd david.lloyd at redhat.com
Wed Oct 19 12:16:08 UTC 2016


Forgive me, but that's quite an incredible response.  How many 
recompilations equals a hex edit?  You can just as well say that Ch.13 
doesn't apply to any changes ever because any recompilation is 
tantamount to a hex edit, which is clearly counter to the intent of the 
chapter.

It is completely reasonable to have two separate libraries in a 
configuration that matches the description, and to have one of those 
libraries be updated to a new version, which would cause the effect 
quite trivially from the user's perspective.  This is not an obscure 
case at all.  All he did was compact this into a simple 
easy-to-understand test case, which yes might be more obscure but also 
serves to illustrate the problem more clearly.

On 10/18/2016 05:52 PM, Alex Buckley wrote:
> I understand that you're going from executing A.class + B.class +
> Test.class to executing A.class + B.class[MODIFIED] + Test.class.
> However, because B.class[MODIFIED] was produced by a non-trivial
> sequence of recompilations, it's tantamount to a hex-edited version of
> the initial B.class. Ch.13 doesn't describe the binary compatibility of
> hex edits, only the binary compatibility of a single compilable change
> to a single compilation unit. I agree with Dan that the binary
> compatibility of adding a private method to an interface inherently
> assumes you immediately compile the interface.
>
> Alex
>
> On 10/18/2016 7:55 AM, Georgiy Rakov wrote:
>> I'd like to emphasize that in this case preexisting binaries supplied to
>> JVM during Test.main execution doesn't change and if they don't then,
>> according to my understanding, it doesn't matter how the modified B
>> class-file was produced.
>>
>> Thank you,
>> Georgiy.
>>
>> On 17.10.2016 21:15, Alex Buckley wrote:
>>> The key phrase is "with preexisting binaries". Given the initial
>>> A.class + B.class + Test.class, you get to make ONE change to ONE
>>> compilation unit that you recompile independently but inconsistently.
>>> The change you would like to make is adding a private method to B, but
>>> you can't make that change because of B's superinterface, so no
>>> independent recompilation is possible, and the question of whether the
>>> change is binary-incompatible is moot.
>>>
>>> Alex
>>>
>>> On 10/17/2016 10:26 AM, Georgiy Rakov wrote:
>>>> Hello Dan,
>>>>
>>>> comment [1] specifies following assertion and a note:
>>>>
>>>>     Adding an 'abstract', ***'private', or 'static'*** method to an
>>>>     interface does not break compatibility with preexisting binaries.
>>>>
>>>>     [Note: I believe we can make this assertion because "adding a
>>>>     method" means "adding a method that will compile", presumably?
>>>>     Private and static methods can introduce errors if a reference like
>>>>     I.m()V previously resolved to an abstract/default method in a
>>>>     superinterface, and now resolves to the private/static method in I.
>>>>     But that new method won't compile if there's a method with a
>>>>     matching signature in a superinterface of I.]
>>>>
>>>> Namely, the note reads:
>>>>
>>>>     ... "adding a method" means "adding a method that will compile" ...
>>>>
>>>> It's questionable if this is a valid point since spec should take into
>>>> account that a method added might be resulted from inconsistent
>>>> compilation. For instance:
>>>>
>>>> 1. First we compile sources A.java, B.java, Test.java presented below.
>>>>
>>>>     A.java:
>>>>     interface A {
>>>>          default void same() {}
>>>>     }
>>>>
>>>>     B.java:
>>>>     interface B extends A {
>>>>          //private void same() {}
>>>>     }
>>>>
>>>>     Test.java:
>>>>     class Test {
>>>>          public static void main(String[] argv) {
>>>>               B i = new B(){};
>>>>               i.same();
>>>>          }
>>>>     }
>>>>
>>>> 2. Then we compile sources A.java, B.java presented below (toggle
>>>> commenting 'same' method in A and B):
>>>>
>>>>     A.java:
>>>>     interface A {
>>>>          //default void same() {}
>>>>     }
>>>>
>>>>     B.java:
>>>>     interface B extends A {
>>>>          private void same() {}
>>>>     }
>>>>
>>>>
>>>> 3. Then we compile source A.java presented below (returning back A
>>>> class
>>>> file as it resulted from step 1):
>>>>
>>>>     A.java:
>>>>     interface A {
>>>>          default void same() {}
>>>>     }
>>>>
>>>> 4. Run Test.main(), this results in a run-time error:
>>>>
>>>>     Exception in thread "main" java.lang.IllegalAccessError: tried to
>>>>     access method B.same()V from class Test
>>>>
>>>> So adding a private method seems to cause breaking binary
>>>> compatibility.
>>>> The change between binaries resulted from step 1 and step 3 is B class
>>>> file with a private method added, the rest of the class files are the
>>>> same.
>>>>
>>>> Should it be considered as a spec issue?
>>>>
>>>> [1]
>>>> https://bugs.openjdk.java.net/browse/JDK-8072872?focusedCommentId=13610992
>>>>
>>>>
>>>>
>>>> Thank you,
>>>> Georgiy.
>>

-- 
- DML


More information about the compiler-dev mailing list