RuedigerMoeller / fast-serialization

FST: fast java serialization drop in-replacement
Apache License 2.0
1.58k stars 247 forks source link

[Android] sun.misc.Unsafe issue when using D8 compiler #214

Open fmt-Println-MKO opened 7 years ago

fmt-Println-MKO commented 7 years ago

when using the new D8 Android Dex Compiler you get these errors on Android SDK Version 18, on Android version 23 till 26 this error does not appear. other version I haven't checked yet.

Could not find method sun.reflect.ReflectionFactory.getReflectionFactory, referenced from method org.nustaq.serialization.FSTDefaultClassInstantiator.findConstructorForSerializable

RuedigerMoeller commented 7 years ago

That's not related to unsafe. Actually this is the replacement api for unsafe. Did you use the androidconfiguration (this should fallback to objenesis instead of reflectionfactory) ?

fmt-Println-MKO commented 7 years ago

ah ok,

yes I use it: public static final FSTConfiguration FST_CONFIG = FSTConfiguration.createAndroidDefaultConfiguration();

static { FST_CONFIG.setShareReferences(false); FST_CONFIG.registerClass(String.class etc etc ); }

maybe the fallback doesn't work on older android versions ?

RuedigerMoeller commented 7 years ago

That's awkward as reflectionfactory is the only way to create objects without execution of defaultinitalizers which is obviously required for deserialization ..

RuedigerMoeller commented 7 years ago

Set shared refs to true and retry, its possible unsharedrefs have no test coverage

RuedigerMoeller commented 7 years ago

Does it work with setShareReferences(true) ?

In general don't use unshared ref mode unless you exactly know what consequences this has (no cycle detection, no ref restoration traded against a neglectable performance gain)

fmt-Println-MKO commented 7 years ago

doesn't change anything

still get a crash with these errors:

I/dalvikvm: Could not find method sun.misc.Unsafe.putBoolean, referenced from method org.nustaq.serialization.FSTClazzInfo$FSTFieldInfo.setBooleanValue

W/dalvikvm: VFY: unable to resolve virtual method 63528: Lsun/misc/Unsafe;.putBoolean (Ljava/lang/Object;JZ)V

D/dalvikvm: VFY: replacing opcode 0x6e at 0x0010

RuedigerMoeller commented 7 years ago

hm .. android configuration should not access unsafe .. strange. try the following:

public static final FSTConfiguration FST_CONFIG = FSTConfiguration.createAndroidDefaultConfiguration();

static {
FSTUtil.unFlaggedUnsafe = null; // <== <== <== <==
FST_CONFIG.setShareReferences(false);
FST_CONFIG.registerClass(String.class etc etc );
}

if unsafe is null, this should trigger fallback code, else I somehow introduced a regression or android detection is not working for some android releases

fmt-Println-MKO commented 7 years ago

even that doesn't work

maybe this new Dexer make something different.

RuedigerMoeller commented 7 years ago

Thanks for your help, have to check myself (may take some time as currentky don't have android setup)

akidee commented 6 years ago

Same problem on an Android device (SDK v 10) - using plain Java APIs, FST default or Android config, but without using D8. On younger SDK versions there is no problem with default or Android config. I have appended the same changes as above to the configuration:

    FSTUtil.unFlaggedUnsafe = null;
    FST_ANDROID.setShareReferences(false); // same result with true
    // FST_ANDROID.registerClass(String.class etc etc ); <- Registering any JDK classes needed?

Log with Android config:

[readObject() of more complex superclass is not called!]
D/dalvikvm: VFY: dead code 0x0013-0016 in Lorg/nustaq/serialization/FSTConfiguration;.asJsonString (Ljava/lang/Object;)Ljava/lang/String;
I/dalvikvm: Could not find method sun.reflect.ReflectionFactory.getReflectionFactory, referenced from method org.nustaq.serialization.FSTDefaultClassInstantiator.findConstructorForSerializable
W/dalvikvm: VFY: unable to resolve static method 48862: Lsun/reflect/ReflectionFactory;.getReflectionFactory ()Lsun/reflect/ReflectionFactory;
D/dalvikvm: VFY: replacing opcode 0x71 at 0x0048
D/dalvikvm: VFY: dead code 0x004b-005e in Lorg/nustaq/serialization/FSTDefaultClassInstantiator;.findConstructorForSerializable (Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
I/dalvikvm: Could not find method sun.misc.Unsafe.allocateInstance, referenced from method org.nustaq.serialization.FSTDefaultClassInstantiator.newInstance
W/dalvikvm: VFY: unable to resolve virtual method 48804: Lsun/misc/Unsafe;.allocateInstance (Ljava/lang/Class;)Ljava/lang/Object;
D/dalvikvm: VFY: replacing opcode 0x6e at 0x0008
I/dalvikvm: Could not find method sun.misc.Unsafe.allocateInstance, referenced from method org.nustaq.serialization.FSTDefaultClassInstantiator.newInstance
W/dalvikvm: VFY: unable to resolve virtual method 48804: Lsun/misc/Unsafe;.allocateInstance (Ljava/lang/Class;)Ljava/lang/Object;
D/dalvikvm: VFY: replacing opcode 0x6e at 0x0017
D/dalvikvm: VFY: dead code 0x000b-000b in Lorg/nustaq/serialization/FSTDefaultClassInstantiator;.newInstance (Ljava/lang/Class;Ljava/lang/reflect/Constructor;ZZ)Ljava/lang/Object;
D/dalvikvm: VFY: dead code 0x001a-001b in Lorg/nustaq/serialization/FSTDefaultClassInstantiator;.newInstance (Ljava/lang/Class;Ljava/lang/reflect/Constructor;ZZ)Ljava/lang/Object;
I/dalvikvm: Could not find method sun.misc.Unsafe.getBoolean, referenced from method org.nustaq.serialization.FSTClazzInfo$FSTFieldInfo.getBooleanValue
W/dalvikvm: VFY: unable to resolve virtual method 48813: Lsun/misc/Unsafe;.getBoolean (Ljava/lang/Object;J)Z
D/dalvikvm: VFY: replacing opcode 0x6e at 0x0010
D/dalvikvm: VFY: dead code 0x0013-0013 in Lorg/nustaq/serialization/FSTClazzInfo$FSTFieldInfo;.getBooleanValue (Ljava/lang/Object;)Z
I/dalvikvm: Could not find method sun.misc.Unsafe.getByte, referenced from method org.nustaq.serialization.FSTClazzInfo$FSTFieldInfo.getByteValue
W/dalvikvm: VFY: unable to resolve virtual method 48815: Lsun/misc/Unsafe;.getByte (Ljava/lang/Object;J)B
D/dalvikvm: VFY: replacing opcode 0x6e at 0x0010
D/dalvikvm: VFY: dead code 0x0013-0013 in Lorg/nustaq/serialization/FSTClazzInfo$FSTFieldInfo;.getByteValue (Ljava/lang/Object;)I
I/dalvikvm: Could not find method sun.misc.Unsafe.getChar, referenced from method org.nustaq.serialization.FSTClazzInfo$FSTFieldInfo.getCharValue
W/dalvikvm: VFY: unable to resolve virtual method 48818: Lsun/misc/Unsafe;.getChar (Ljava/lang/Object;J)C
D/dalvikvm: VFY: replacing opcode 0x6e at 0x0010
D/dalvikvm: VFY: dead code 0x0013-0013 in Lorg/nustaq/serialization/FSTClazzInfo$FSTFieldInfo;.getCharValue (Ljava/lang/Object;)I
I/dalvikvm: Could not find method sun.misc.Unsafe.getDouble, referenced from method org.nustaq.serialization.FSTClazzInfo$FSTFieldInfo.getDoubleValue
W/dalvikvm: VFY: unable to resolve virtual method 48821: Lsun/misc/Unsafe;.getDouble (Ljava/lang/Object;J)D
D/dalvikvm: VFY: replacing opcode 0x6e at 0x0010
D/dalvikvm: VFY: dead code 0x0013-0013 in Lorg/nustaq/serialization/FSTClazzInfo$FSTFieldInfo;.getDoubleValue (Ljava/lang/Object;)D
I/dalvikvm: Could not find method sun.misc.Unsafe.getFloat, referenced from method org.nustaq.serialization.FSTClazzInfo$FSTFieldInfo.getFloatValue
W/dalvikvm: VFY: unable to resolve virtual method 48824: Lsun/misc/Unsafe;.getFloat (Ljava/lang/Object;J)F
...
[readObject() of subclass is called, but now object is in incorrect state]

The main problem seems to be a broken Java implementation on this device, but it would be great if FST patched it.

RuedigerMoeller commented 6 years ago

with java 9 and higher, i am forced to use unsafe because of new reflection restriction, so it seems i have to branch the lib in order to satisfy both android and jdk restrictions :(

akidee commented 6 years ago

I see no problem. For the Android configuration, you just switch to the implementation that works:

At least offer an explicit option on Android whether reflection or Unsafe is used.

fmt-Println-MKO commented 6 years ago

@akidee this doesn't work, Java 9 is not supported in Android at all. Also the Dalvik / Art VM differs a lot from JVM.

so for Android Unsafe doesn't work at the moment

akidee commented 6 years ago

@fmt-Println-MKO The problem is that it doesn't work on an old Android device only. If Unsafe does not work on Android at all then why do the logs above show up while Serializable if broken? Anyway, I have to assert this result on an additional Android setup to be sure that it's not a bug on this device.

fmt-Println-MKO commented 6 years ago

@akidee W/dalvikvm: VFY: unable to resolve static method 48862: Lsun/reflect/ReflectionFactory W/dalvikvm: VFY: unable to resolve virtual method 48804: Lsun/misc/Unsafe;.

as you see these are two methods from sun, they are not available in Android.

@RuedigerMoeller maybe this lib could help: https://github.com/iamironz/unsafe

as you get a precompiled unsafe class with this dependency