SerialVersionUIDAdder generates incorrect serialVersionUIDs for anonymous classes compiled using 1.6 VMs
Chris Dennis <[email protected]>
| Newsgroups | gmane.comp.java.objectweb.asm |
|---|---|
| Message-ID | <[email protected]> |
Hi All,
Feeding the attached class (when compiled under 1.6) through an
adapter chain containing just the SerialVersionUIDAdder (and then
dumping) generates the following output:
==================================
// class version 50.0 (50)
// access flags 48
final class Test$1 extends Test {
// compiled from: Test.java
OUTERCLASS Test null
// access flags 8
static INNERCLASS Test$1 null null
// access flags 0
<init>()V
L0
LINENUMBER 4 L0
ALOAD 0
INVOKESPECIAL Test.<init> ()V
RETURN
MAXSTACK = 1
MAXLOCALS = 1
// access flags 24
final static J serialVersionUID = -76581618747421564
}
==================================
The calculated serialVersionUID is different from the value serialver
reports:
Test$1: static final long serialVersionUID = 7846639601304304217L;
The value serialver reports is the same as on 1.4 and 1.5 JVMs, which
ASM correctly matches in those VMs. The only difference between the
compiled classes are the access flags of the class: 1.5 and 1.4 report
SUPER (0x0020), 1.6 reports SUPER|FINAL (0x0030) (and the class file
version, obviously).
I believe this is because the change introduced previously to fix
serialVersionUID values for nested classes was incorrect. Inspecting
the Sun 1.6 Hotspot sources reveals this code:
==================================
hotspot/src/share/vm/oops/instaceKlass.cpp::compute_modifier_flags(...)
(loop over InnerClass attribute list omitted)
int ioff = inner_class_list_h->ushort_at(i +
instanceKlass::inner_class_inner_class_info_offset);
// Inner class attribute can be zero, skip it.
// Strange but true: JVM spec. allows null inner class refs.
if (ioff == 0) continue;
// only look at classes that are already loaded
// since we are looking for the flags for our self.
symbolOop inner_name = ik->constants()->klass_name_at(ioff);
if ((ik->name() == inner_name)) {
// This is really a member class.
access = inner_class_list_h->ushort_at(i +
instanceKlass::inner_class_access_flags_offset);
break;
}
==================================
As you can see the condition under which the inner class access flags
are used is just that the class name of the inner class attribute
(class name in the constant pool @ inner_class_info_offset - saved to
inner_name) matches the class name of the class being inspected (ik-
>name()). It follows therefore that the visitInnerClass method of
SerialVersionUIDAdder should be:
==================================
public void visitInnerClass(final String aname, final String
outerName, final String innerName, final int attr_access) {
if ((name != null) && name.equals(aname)) {
this.access = attr_access;
}
super.visitInnerClass(aname, outerName, innerName, attr_access);
}
==================================
The previous check will fail for anonymous inner classes since they
have null constant pool references for outer_class_info and
inner_name. This means anonymous classes ended up using the modifiers
of the class (which gained the FINAL flag in 1.6) thus making their
calculated serialVersionUID values incorrect on 1.6. I've attached a
patch that solves this, and tested it with both the testcase for this
bug, and also the original testcase that Simon Goldsmith provided
(Frob.java) and everything works correctly under all JVM versions.
Thanks,
Chris
P.S. I've also filed this as a bug on the bug tracker.
Test.java
(application/octet-stream, 139 B) - not displayed
inner_class_svuid.patch
(application/octet-stream, 1.1 KB)
Index: src/org/objectweb/asm/commons/SerialVersionUIDAdder.java
===================================================================
--- src/org/objectweb/asm/commons/SerialVersionUIDAdder.java (revision 1410)
+++ src/org/objectweb/asm/commons/SerialVersionUIDAdder.java (working copy)
@@ -286,16 +286,8 @@
* the class file in favor of the access bits InnerClass attribute.
*/
public void visitInnerClass(final String aname, final String outerName, final String innerName, final int attr_access) {
- if (outerName != null && innerName != null && name != null) {
- int len = name.length();
- int ilen = innerName.length();
- int olen = outerName.length();
- if (len == olen + 1 + ilen
- && this.name.startsWith(outerName) && this.name.endsWith(innerName)
- && this.name.charAt(olen) == '$')
- {
- this.access = attr_access;
- }
+ if ((name != null) && name.equals(aname)) {
+ this.access = attr_access;
}
super.visitInnerClass(aname, outerName, innerName, attr_access);
}
message-footer.txt
(text/plain, 238 B)
-- You receive this message as a subscriber of the [email protected] mailing list. To unsubscribe: mailto:[email protected] For general help: mailto:[email protected]?subject=help OW2 mailing lists service home page: http://www.ow2.org/wws