fury icon indicating copy to clipboard operation
fury copied to clipboard

Sporadic java.lang.ArrayIndexOutOfBoundsException/Can't deserialize lambda if RuntimeException is deserialized

Open johannschenkl opened this issue 2 years ago • 9 comments

Search before asking

  • [X] I had searched in the issues and found no similar issues.

Version

0.4.1

Component(s)

Java

Minimal reproduce step

We are using fury as a replacement for jdk serialization in a java rpc application. If on the server side an exception is thrown, this exception in serialized and sent to the client. In some cases we seen and exception when the serialization is done. Thanks for your help and for that great project!

Fury setup:

var fury = Fury.builder() .withLanguage(Language.JAVA) .withRefTracking(true) .requireClassRegistration(false) .withAsyncCompilation(true).build();

Relevant parts of logs:

io.fury.serializer.LambdaSerializer.read(LambdaSerializer.java:88) io.fury.Fury.readRef(Fury.java:828) io.fury.resolver.FieldResolver.skipDataBy4(FieldResolver.java:433) com.mycompany.SomeExceptionFuryRefCompatibleCodec_1_815033865_986095905.readAndSetFields(SomeExceptionFuryRefCompatibleCodec_1_815033865_986095905.java:258) com.mycompany.SomeExceptionFuryRefCompatibleCodec_1_815033865_986095905.read(SomeExceptionFuryRefCompatibleCodec_1_815033865_986095905.java:324) com.mycompany.RemoteInvocationResultFuryRefCodec_1_815033865_718325701.readFields$(RemoteInvocationResultFuryRefCodec_1_815033865_718325701.java:111) com.mycompany.RemoteInvocationResultFuryRefCodec_1_815033865_718325701.read(RemoteInvocationResultFuryRefCodec_1_815033865_718325701.java:127) io.fury.Fury.readDataInternal(Fury.java:899) io.fury.Fury.readRef(Fury.java:801) io.fury.Fury.deserializeJavaObjectAndClass(Fury.java:1135) io.fury.Fury.deserializeJavaObjectAndClass(Fury.java:1121) com.mycompany.Serializer.deserialize(Serializer.java:35)

...

Caused by: Index -1 out of bounds for length 512 java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 512 io.fury.collection.IntArray.pop(IntArray.java:51) io.fury.resolver.MapRefResolver.reference(MapRefResolver.java:194) io.fury.builder.SerializedLambdaFuryRefCodec_1_1361449601.read(SerializedLambdaFuryRefCodec_1_1361449601.java:193) io.fury.serializer.LambdaSerializer.read(LambdaSerializer.java:85) io.fury.Fury.readRef(Fury.java:828) io.fury.resolver.FieldResolver.skipDataBy4(FieldResolver.java:433) com.mycompany.SomeExceptionFuryRefCompatibleCodec_1_815033865_986095905.readAndSetFields(SomeExceptionFuryRefCompatibleCodec_1_815033865_986095905.java:258) com.mycompany.SomeExceptionFuryRefCompatibleCodec_1_815033865_986095905.read(SomeExceptionFuryRefCompatibleCodec_1_815033865_986095905.java:324) com.mycompany.RemoteInvocationResultFuryRefCodec_1_815033865_718325701.readFields$(RemoteInvocationResultFuryRefCodec_1_815033865_718325701.java:111) com.mycompany.RemoteInvocationResultFuryRefCodec_1_815033865_718325701.read(RemoteInvocationResultFuryRefCodec_1_815033865_718325701.java:127) io.fury.Fury.readDataInternal(Fury.java:899) io.fury.Fury.readRef(Fury.java:801) io.fury.Fury.deserializeJavaObjectAndClass(Fury.java:1135) io.fury.Fury.deserializeJavaObjectAndClass(Fury.java:1121) com.mycompany.Serializer.deserialize(Serializer.java:35)

What did you expect to see?

The deserialized payload.

What did you see instead?

An ArrayIndexOutOfBoundsException.

Anything Else?

No response

Are you willing to submit a PR?

  • [ ] I'm willing to submit a PR!

johannschenkl avatar Apr 23 '24 08:04 johannschenkl

Hi @johannschenkl , thanks for reporting this bug. It seems that our current implementation has some inconsistency between interpreter mode and codegen mode. This has been reported in #1455, #1325 and #1176.

The fix won't be difficult. But none of this can provide reproduction code, so I can't debug to find out what's going wrong.

chaokunyang avatar Apr 23 '24 09:04 chaokunyang

Will it still raise execpetion if you disabled asyncCompilation?

chaokunyang avatar Apr 23 '24 09:04 chaokunyang

It would be really great if you can provide reproduction code. I try to fix it for a long time

chaokunyang avatar Apr 23 '24 09:04 chaokunyang

Hi @chaokunyang, thanks for the quick response. Currently, the issue is only reproducible on a qa machine and only for some users. I was not able to reproduce it by myself. As of yet, it only happend in conjunction with a serialized RuntimeException. I'll check if disabling asyncCompilation helps and if I can somehow build a test case.

johannschenkl avatar Apr 23 '24 09:04 johannschenkl

Hi @johannschenkl . Is this issue still persisits?

chaokunyang avatar Apr 27 '24 05:04 chaokunyang

Hi @chaokunyang, unfortunately yes. I'm still trying to get a reproducer working.

johannschenkl avatar Apr 29 '24 06:04 johannschenkl

We're self-managing Fury in a ThreadLocal, is that the issue, maybe?

private static final ThreadLocal<Fury> THE_FURY = ThreadLocal.withInitial(() -> {
        var fury = Fury.builder().withLanguage(Language.JAVA)
                .withRefTracking(true)
                .requireClassRegistration(false)
                .withAsyncCompilation(true)
                .suppressClassRegistrationWarnings(true) // as checker is enabled, see below
                .build();
        fury.getClassResolver().setClassChecker(...);
        return fury;
    });

I know there's also the ...buildThreadSafeFury/buildThreadLocalFury implementations. But we did not see a way to register a classchecker on them.

johannschenkl avatar Apr 29 '24 07:04 johannschenkl

This is right, or you can use org.apache.fury.ThreadLocalFury#ThreadLocalFury, which let you to set anything in the factory

chaokunyang avatar Apr 29 '24 08:04 chaokunyang

Hi @chaokunyang, sorry for the late response. After using the provided factory & disabling async compilation, the issue did not show up again.

johannschenkl avatar May 13 '24 06:05 johannschenkl