Serious serialization problem: SUID-member is ignored

I noticed a serious bug in the serialization / deserialization of object instances where the SUID-member (private static final long serialVersionUID) is set to a certain value (in my case 1L). The MOE ignores this value and calculates the SUID based on the class (members, methods, constructors …). I noticed this buggy behaviour for both serialization and deserialization. I tested it in both directions: by deserialization of an Serializable instance (serialized by Oracle’s Java VM with fixed SUID 1L) on MOE and by deserialization of an Serializable instance (serialized by MOE with fixed SUID 1L) on Oracle’s Java VM. In both cases it failed with the exception message of that kind: “Incompatible class (SUID) …”
This problem doesn’t occur when using serialization / deserialization in MOE only if the class doesn’t change between serialization and deserialization.

This is a very serious bug and should be fixed as soon as possible.

Dear Ulrich,

thanks for bringing this into our attention. Can you confirm, that if you try the same on Android (version 5 or 6), you get the behavior that you expect, so a class serialized with Oracle JVM can be deserialized with Android?

Thanks,
Gergely

Dear Gergely,

the deserialization of our serialized instances (serialized on PC using Oracle’s JDK Java VM, with a private final static serialVersionUID set to 1L) on Android 4, 5, 6, 7 always worked as intended.

Regards,
Ulrich

Dear Ulrich,

can you please confirm, that the serialVersionUID members were in the final build (and not removed by ProGuard)? You can check this in the build/moe/main/proguard folder in the output.jar using a bytecode decompiler.

Thanks,
Gergely

Dear Gergely,

I checked that and the serialVersionUID-member was missing in the decompiled bytecode. But when a class implements the Serializable interface that member (private final static long serialVersionUID) is very important for the serialization and deserialization behaviour and should definitely never ever be removed by proguard.
The Oracle JVM, Android’s Dalvik VM and RoboVM, which I had used before, were and are behaving correctly in this context.

Thanks & regards,
Ulrich

Dear Gergely,

I tried to fix the problem by adding the following rule to proguard-rules.pro (in the project’s gradle scripts):

-keepclassmembers class * {
private static final long serialVersionUID;
}

Unfortunatley it didn’t prevent the problem from occuring. The member serialVersionUID is still missing in the decompiled bytecode.

Tanks & regards,
Ulrich

Dear Ulrich,

when you use ProGuard, you need to tell it explicitly, that it should keep the fields and methods related to Serialization. This is true for every Java platform (including Oracle JVM and Android). The difference is, that MOE always uses ProGuard.

You can add the following to the proguard.append.cfg in the root of your MOE module:

-keepnames class * implements java.io.Serializable
-keepclassmembers class * implements java.io.Serializable {
    static final long serialVersionUID;
    private void writeObject(java.io.ObjectOutputStream);
    private void readObject(java.io.ObjectInputStream);
    Object writeReplace();
    Object readResolve();
}

I am not sure yet if we should add these rules to the default ProGuard configuration as well, or just document this. I opened a GH issue to track this:

2 Likes

Dear Gergely,

thank you - that solved the problem.

Regards,
Ulrich