Hi Dan,

On 6/23/2016 5:03 PM, Dan Smith wrote:
On Jun 23, 2016, at 2:04 PM, Roger Riggs <roger.ri...@oracle.com> wrote:

Hi Dan,

On 6/23/2016 2:53 PM, Dan Smith wrote:
On Jun 23, 2016, at 11:37 AM, Roger Riggs <roger.ri...@oracle.com>
  wrote:

Hi Dan,

I was concerned about inter-operation between versions because serialized 
objects
are passed between Java runtimes with different versions and both need to 
compute
the same serial version uid (if it is not explicitly declared). The older java 
runtimes will
compute the serial version uid without regard to your change.

If javac always turns on the ACC_FINAL bit and using -target 8 and then the 
class file
is executed in a Java 8 runtime, it seems like it would compute a different 
value
which would be in compatible change.  It might be safer to introduce this change
only with the new class file version number.

Ugh, this is a good point.  Hadn't thought about that use case.

How should we compare these two compatibility risks?:

(1) Using identical class binaries on two sides of a pipe, but running 
different JDK versions, a class has different UIDs on the two sides.

Go back to the rationale for not including ACC_FINAL in the modifiers used in 
SUID?
I'm not clear on that part (other than its a current bug, not spec compliant).
Reflection could report final based on the 'implicitly' final spec for 
anonymous classes.
Or reflection needs to be classfile version aware.

It is simpler to just hash whatever bits are there and not modify them.
It won't break because of compiler changes or re-compiles.
Rationale: javac would like to change the bits generated for anonymous inner 
classes -- specifically, by setting the ACC_FINAL bit, where it has been left 
unset in the past -- but doesn't want to disrupt clients who use serialization. 
 (Why not?  To be nice, mostly -- trying to avoid (2).)  If we can force these 
new classes to have the same UID as the old classes, then there's no problem.

Except, oops, we can't redefine the implicit UID definition without introducing 
interop problems between different JDK versions -- that's (1).

I don't think it's necessarily bad for ObjectStreamClass to manipulate the bits 
before hashing them -- we already mask out lots of flags, per the serialization 
spec -- but the problem here is that any change to the hashing behavior (for a 
class that legally exists with an older class file version) is going to 
introduce incompatibilities between different versions of the java.io API.
True, as long as the modification of the bits is according to some stable *specification*. I think that means the classfile specification, since the runtime does not mandate class files from javac.

Changing the behavior of reflection doesn't help: you end up with the same 
problem, a single binary class having different UIDs depending on which version 
of the Java APIs is being used.  (Besides, using reflection to obfuscate the 
actual contents of a class file is something we should avoid.)
ok

(2) Using class binaries compiled from different versions of javac on two sides 
of a pipe, but running the same JDK versions, a class has different UIDs on the 
two sides.

Your suggestion to use "-target" helps to reduce the likelihood of (1).  But 
there may still be classes that are broken in this scenario.  Some examples:
- Really old classes that had ACC_FINAL set (it has been turned on and off once 
or twice in javac over the years)
- Classes that target 9, but a bytecode rewriter converts to run on 8, without 
tweaking ACC_FINAL

Not your problem, different rules apply to different class file versions, tools 
need to respect/ deal with it.
There are no rules that say that the 'inner_class_access_flags' value for an 
anonymous inner class (as defined by Class.isAnonymousClass) must be ACC_FINAL, 
or must not be ACC_FINAL.  Both are totally fine, as far as the JVM is 
concerned.

The reason we want to change javac's behavior is because the *language 
specification* says the class is 'final', which ought to constrain the subset 
of anonymous inner classes that are generated by compilers for the Java 
language.
ok, and you are not trying to impose that on arbitrary class files.

...

So (1) is a much narrower problem, but also more serious: users can reasonably 
consider a failure to serialize/deserialize with identical class binaries to be 
a bug; they can't really complain about a new compiler version spitting out 
different bytes.

I would suggest javac to produce the same ACC_FINAL bits as it did before for 
each -target version.
(I know it looks like a hack, but a compatible one).
Correct it for 9 and leave the SUID computation alone.
Okay, so I interpret this to mean you think (2) is tolerable, at least where 
the two binaries for the anonymous class have different version numbers?
yes,

No change is needed to the computed SUID or ObjectStreamClass; it uses whatever is in the class file.

Thanks, Roger

Reply via email to