Skip to content

Commit 442f8eb

Browse files
authored
Fix serialization verification problem with Akka.IO messages (#4974)
* Fix serialization verification problem with Akka.IO messages * Wrap naked SocketAsyncEventArgs in a struct that inherits INoSerializationVerificationNeeded * Make the wrapper struct readonly * Expand exception message with their actor types * Update API Approver list
1 parent 5251f36 commit 442f8eb

13 files changed

+91
-49
lines changed

src/core/Akka.API.Tests/CoreAPISpec.ApproveCore.approved.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3256,7 +3256,7 @@ namespace Akka.IO
32563256
public static Akka.IO.Dns.Resolved Cached(string name, Akka.Actor.ActorSystem system) { }
32573257
public override Akka.IO.DnsExt CreateExtension(Akka.Actor.ExtendedActorSystem system) { }
32583258
public static Akka.IO.Dns.Resolved ResolveName(string name, Akka.Actor.ActorSystem system, Akka.Actor.IActorRef sender) { }
3259-
public abstract class Command
3259+
public abstract class Command : Akka.Actor.INoSerializationVerificationNeeded
32603260
{
32613261
protected Command() { }
32623262
}
@@ -3685,7 +3685,7 @@ namespace Akka.IO
36853685
{
36863686
protected Event() { }
36873687
}
3688-
public abstract class Message
3688+
public abstract class Message : Akka.Actor.INoSerializationVerificationNeeded
36893689
{
36903690
protected Message() { }
36913691
}
@@ -3792,7 +3792,7 @@ namespace Akka.IO
37923792
{
37933793
protected Event() { }
37943794
}
3795-
public abstract class Message
3795+
public abstract class Message : Akka.Actor.INoSerializationVerificationNeeded
37963796
{
37973797
protected Message() { }
37983798
}
@@ -3827,7 +3827,7 @@ namespace Akka.IO
38273827
public static readonly Akka.IO.UdpConnected.SuspendReading Instance;
38283828
}
38293829
}
3830-
public class UdpConnectedExt : Akka.IO.IOExtension
3830+
public class UdpConnectedExt : Akka.IO.IOExtension, Akka.Actor.INoSerializationVerificationNeeded
38313831
{
38323832
public UdpConnectedExt(Akka.Actor.ExtendedActorSystem system) { }
38333833
public UdpConnectedExt(Akka.Actor.ExtendedActorSystem system, Akka.IO.UdpSettings settings) { }

src/core/Akka.Tests/IO/TcpIntegrationSpec.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ class AckWithValue : Tcp.Event
4545

4646
public TcpIntegrationSpec(ITestOutputHelper output)
4747
: base($@"akka.loglevel = DEBUG
48+
akka.actor.serialize-creators = on
49+
akka.actor.serialize-messages = on
4850
akka.io.tcp.trace-logging = true
4951
akka.io.tcp.write-commands-queue-max-size = {InternalConnectionActorMaxQueueSize}", output: output)
5052
{ }
@@ -190,7 +192,7 @@ public void The_TCP_transport_implementation_should_properly_support_connecting_
190192
var targetAddress = new DnsEndPoint("localhost", boundMsg.LocalAddress.AsInstanceOf<IPEndPoint>().Port);
191193
var clientHandler = CreateTestProbe();
192194
Sys.Tcp().Tell(new Tcp.Connect(targetAddress), clientHandler);
193-
clientHandler.ExpectMsg<Tcp.Connected>(TimeSpan.FromMinutes(10));
195+
clientHandler.ExpectMsg<Tcp.Connected>(TimeSpan.FromSeconds(3));
194196
var clientEp = clientHandler.Sender;
195197
clientEp.Tell(new Tcp.Register(clientHandler));
196198
serverHandler.ExpectMsg<Tcp.Connected>();

src/core/Akka.Tests/IO/TcpListenerSpec.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ namespace Akka.Tests.IO
1919
public class TcpListenerSpec : AkkaSpec
2020
{
2121
public TcpListenerSpec()
22-
: base(@"akka.io.tcp.register-timeout = 500ms
22+
: base(@"
23+
akka.actor.serialize-creators = on
24+
akka.actor.serialize-messages = on
25+
akka.io.tcp.register-timeout = 500ms
2326
akka.io.tcp.max-received-message-size = 1024
2427
akka.io.tcp.direct-buffer-size = 512
2528
akka.actor.serialize-creators = on
26-
akka.io.tcp.batch-accept-limit = 2
27-
")
29+
akka.io.tcp.batch-accept-limit = 2")
2830
{ }
2931

3032
[Fact]

src/core/Akka.Tests/IO/UdpConnectedIntegrationSpec.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ public class UdpConnectedIntegrationSpec : AkkaSpec
2424

2525
public UdpConnectedIntegrationSpec(ITestOutputHelper output)
2626
: base(@"
27+
akka.actor.serialize-creators = on
28+
akka.actor.serialize-messages = on
2729
akka.io.udp-connected.nr-of-selectors = 1
2830
akka.io.udp-connected.direct-buffer-pool-limit = 100
2931
akka.io.udp-connected.direct-buffer-size = 1024

src/core/Akka.Tests/IO/UdpIntegrationSpec.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ public class UdpIntegrationSpec : AkkaSpec
2727

2828
public UdpIntegrationSpec(ITestOutputHelper output)
2929
: base(@"
30+
akka.actor.serialize-creators = on
31+
akka.actor.serialize-messages = on
3032
akka.io.udp.max-channels = unlimited
3133
akka.io.udp.nr-of-selectors = 1
3234
akka.io.udp.direct-buffer-pool-limit = 100

src/core/Akka.Tests/IO/UdpListenerSpec.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,21 @@
1313
using Akka.IO;
1414
using Akka.TestKit;
1515
using Xunit;
16+
using Xunit.Abstractions;
1617
using UdpListener = Akka.IO.UdpListener;
1718

1819
namespace Akka.Tests.IO
1920
{
2021
public class UdpListenerSpec : AkkaSpec
2122
{
22-
public UdpListenerSpec()
23-
: base(@"akka.io.udp.max-channels = unlimited
23+
public UdpListenerSpec(ITestOutputHelper output)
24+
: base(@"
25+
akka.actor.serialize-creators = on
26+
akka.actor.serialize-messages = on
27+
akka.io.udp.max-channels = unlimited
2428
akka.io.udp.nr-of-selectors = 1
2529
akka.io.udp.direct-buffer-pool-limit = 100
26-
akka.io.udp.direct-buffer-size = 1024")
30+
akka.io.udp.direct-buffer-size = 1024", output)
2731
{ }
2832

2933
[Fact]

src/core/Akka/Actor/ActorCell.Children.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
using System.Collections.Immutable;
1111
using System.Text;
1212
using System.Runtime.CompilerServices;
13+
using System.Runtime.Serialization;
1314
using System.Threading;
1415
using Akka.Actor.Internal;
16+
using Akka.Dispatch.SysMsg;
1517
using Akka.Serialization;
1618
using Akka.Util;
1719
using Akka.Util.Internal;
@@ -452,6 +454,7 @@ private IInternalActorRef MakeChild(Props props, string name, bool async, bool s
452454
if (_systemImpl.Settings.SerializeAllCreators && !systemService && !(props.Deploy.Scope is LocalScope))
453455
{
454456
var oldInfo = Serialization.Serialization.CurrentTransportInformation;
457+
object propArgument = null;
455458
try
456459
{
457460
if (oldInfo == null)
@@ -465,17 +468,24 @@ private IInternalActorRef MakeChild(Props props, string name, bool async, bool s
465468
{
466469
if (argument != null && !(argument is INoSerializationVerificationNeeded))
467470
{
471+
propArgument = argument;
468472
var serializer = ser.FindSerializerFor(argument);
469473
var bytes = serializer.ToBinary(argument);
470474
var ms = Serialization.Serialization.ManifestFor(serializer, argument);
471-
if(ser.Deserialize(bytes, serializer.Identifier, ms) == null)
475+
if (ser.Deserialize(bytes, serializer.Identifier, ms) == null)
472476
throw new ArgumentException(
473-
$"Pre-creation serialization check failed at [${_self.Path}/{name}]",
474-
nameof(name));
477+
$"Pre-creation serialization check failed at [${_self.Path}/{name}]",
478+
nameof(name));
475479
}
476480
}
477481
}
478482
}
483+
catch (Exception e)
484+
{
485+
throw new SerializationException(
486+
$"Failed to serialize and deserialize actor props argument of type {propArgument?.GetType()} for actor type [{props.Type}].",
487+
e);
488+
}
479489
finally
480490
{
481491
Serialization.Serialization.CurrentTransportInformation = oldInfo;

src/core/Akka/Actor/ActorCell.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using Akka.Dispatch.SysMsg;
1414
using Akka.Event;
1515
using System.Reflection;
16+
using System.Runtime.Serialization;
1617
using Akka.Serialization;
1718
using Akka.Util;
1819
using Assert = System.Diagnostics.Debug;
@@ -518,7 +519,16 @@ private Envelope SerializeAndDeserialize(Envelope envelope)
518519
if (unwrapped is INoSerializationVerificationNeeded)
519520
return envelope;
520521

521-
var deserializedMsg = SerializeAndDeserializePayload(unwrapped);
522+
object deserializedMsg;
523+
try
524+
{
525+
deserializedMsg = SerializeAndDeserializePayload(unwrapped);
526+
}
527+
catch (Exception e)
528+
{
529+
throw new SerializationException($"Failed to serialize and deserialize payload object [{unwrapped.GetType()}]. Envelope: [{envelope}], Actor type: [{Actor.GetType()}]", e);
530+
}
531+
522532
if (deadLetter != null)
523533
return new Envelope(new DeadLetter(deserializedMsg, deadLetter.Sender, deadLetter.Recipient), envelope.Sender);
524534
return new Envelope(deserializedMsg, envelope.Sender);

src/core/Akka/IO/Dns.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public class Dns : ExtensionIdProvider<DnsExt>
5959
/// <summary>
6060
/// TBD
6161
/// </summary>
62-
public abstract class Command
62+
public abstract class Command : INoSerializationVerificationNeeded
6363
{ }
6464

6565
/// <summary>

src/core/Akka/IO/Tcp.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public override TcpExt CreateExtension(ExtendedActorSystem system)
5353

5454
#region internal connection messages
5555

56-
internal abstract class SocketCompleted { }
56+
internal abstract class SocketCompleted : INoSerializationVerificationNeeded { }
5757

5858
internal sealed class SocketSent : SocketCompleted
5959
{

0 commit comments

Comments
 (0)