akkadotnet / akka.net

Canonical actor model implementation for .NET with local + distributed actors in C# and F#.
http://getakka.net
Other
4.69k stars 1.04k forks source link

PersistenceMessageSerializer.FromBinary does not account for null #4863

Closed CumpsD closed 3 years ago

CumpsD commented 3 years ago

https://github.com/akkadotnet/akka.net/blob/b76b98af84232b45327cc8d0a336d39434d9018c/src/core/Akka.Persistence/Serialization/PersistenceMessageSerializer.cs#L151 gets called from https://github.com/akkadotnet/akka.net/blob/dev/src/core/Akka/Serialization/Serialization.cs#L418 which passes in a null causing type.GetTypeInfo().IsGenericType to crash.

I found this by running SnapshotStoreSerializationSpec which crashed with:

Xunit.Sdk.TrueException
Failed: Expected a message of type Akka.Persistence.LoadSnapshotResult, but received {LoadSnapshotFailed<Cause: System.ArgumentNullException: Value cannot be null. (Parameter 'type')
   at System.Reflection.IntrospectionExtensions.GetTypeInfo(Type type)
   at Akka.Persistence.Serialization.PersistenceMessageSerializer.FromBinary(Byte[] bytes, Type type)
   at Akka.Serialization.Serialization.Deserialize(Byte[] bytes, Int32 serializerId, String manifest)
   at Akka.Persistence.PostgreSql.Snapshot.PostgreSqlQueryExecutor.<>c__DisplayClass18_0.<.ctor>b__1(Type type, Object payload, String manifest, Nullable`1 serializerId) in Akka.Persistence.PostgreSql\Snapshot\PostgreSqlQueryExecutor.cs:line 125
   at Akka.Persistence.PostgreSql.Snapshot.PostgreSqlQueryExecutor.ReadSnapshot(DbDataReader reader) in Akka.Persistence.PostgreSql\Snapshot\PostgreSqlQueryExecutor.cs:line 370
   at Akka.Persistence.PostgreSql.Snapshot.PostgreSqlQueryExecutor.SelectSnapshotAsync(DbConnection connection, CancellationToken cancellationToken, String persistenceId, Int64 maxSequenceNr, DateTime maxTimestamp) in Akka.Persistence.PostgreSql\Snapshot\PostgreSqlQueryExecutor.cs:line 239
   at Akka.Persistence.PostgreSql.Snapshot.PostgreSqlQueryExecutor.SelectSnapshotAsync(DbConnection connection, CancellationToken cancellationToken, String persistenceId, Int64 maxSequenceNr, DateTime maxTimestamp) in Akka.Persistence.PostgreSql\Snapshot\PostgreSqlQueryExecutor.cs:line 239
   at Akka.Persistence.PostgreSql.Snapshot.PostgreSqlQueryExecutor.SelectSnapshotAsync(DbConnection connection, CancellationToken cancellationToken, String persistenceId, Int64 maxSequenceNr, DateTime maxTimestamp) in Akka.Persistence.PostgreSql\Snapshot\PostgreSqlQueryExecutor.cs:line 240
   at Akka.Persistence.Sql.Common.Snapshot.SqlSnapshotStore.LoadAsync(String persistenceId, SnapshotSelectionCriteria criteria)
   at Akka.Util.Internal.AtomicState.CallThrough[T](Func`1 task)
   at Akka.Util.Internal.AtomicState.CallThrough[T](Func`1 task)>} (type Akka.Persistence.LoadSnapshotFailed) instead  from [akka://PostgreSqlSnapshotStoreSerializationSpec/deadLetters]
Expected: True
Actual:   False
   at Akka.TestKit.Xunit2.XunitAssertions.Fail(String format, Object[] args)
   at Akka.TestKit.TestKitBase.InternalExpectMsgEnvelope[T](Nullable`1 timeout, Action`2 assert, String hint, Boolean shouldLog)
   at Akka.TestKit.TestKitBase.InternalExpectMsg[T](Nullable`1 timeout, Action`2 assert, String hint)
   at Akka.TestKit.TestKitBase.ExpectMsg[T](Predicate`1 isMessage, Nullable`1 timeout, String hint)
   at Akka.Persistence.TCK.Serialization.SnapshotStoreSerializationSpec.SnapshotStore_should_serialize_AtLeastOnceDeliverySnapshot()

Relevant part:

System.ArgumentNullException: Value cannot be null. (Parameter 'type')

The call source was

_deserialize = (type, payload, manifest, serializerId) =>
{
    if (serializerId.HasValue)
        return Serialization.Deserialize((byte[])payload, serializerId.Value, manifest);

    // Support old writes that did not set the serializer id
    var deserializer = Serialization.FindSerializerForType(type, Configuration.DefaultSerializer);

    // TODO: hack. Replace when https://github.com/akkadotnet/akka.net/issues/3811
    return Serialization.WithTransport(Serialization.System, () => deserializer.FromBinary((byte[])payload, type));
};
Arkatufus commented 3 years ago

Thank you for the report, the PR should fix it.