4

I have an enum with flags that I decorate with the [ProtoMember] attribute that serializes and deserializes fine on my local box running Win7 x64.

However my use case involves serializing on a server running Windows Server 2008 R2 Enterprise 64-bit and deserializing on my local box. When I deserialize, I get the exception:"Overflow Exception was unhandled; Arithmetic operation resulted in an overflow". It seems to be thrown from ProtoBuf.Serializers.CompiledSerializer.ProtoBuf.Serializers.IProtoSerializer.Read(Object value, ProtoReader source).

I tried changing the enum to an int and serializing on server/deserializing locally works. I would like to use the enum instead of an int. What am I doing wrong?

Not sure if this is pertinent information but the executable I run on the server is built on my local box.

The enum is from a referenced external dll. When I duplicate the enum code in my solution, deserializing works. The exception is only thrown when I am using an enum from an external dll (where I suspect the source code isn't known) and the enum value is larger than (it seems) 128. In my case, Status.Zeta and Status.All threw the exception; other enum values deserialized properly. The enum is defined as such:

[Flags]
public enum Status
{
    None = 0,
    Alpha = 1,
    Beta = 8,
    Gamma = 16,
    Delta = 32,
    Epsilon = 64,
    Zeta = 132,
    All = 255,
}

I cannot change the code in the dll. How can I make this work? Do I need a .proto file? I am trying to avoid this if possible.

JohnC
  • 335
  • 3
  • 12
  • Can you clarify the version of the library you are using? Also: any chance you can show the enum (or part of it) that is failing? What is the underlying type of the enum? – Marc Gravell Dec 27 '12 at 08:58
  • Marc, I was hoping you would respond -- thanks. I am using r602>Full>net30>protobuf-net.dll. I will append some code to my question in a bit. – JohnC Dec 27 '12 at 16:42
  • Very strange. I created a console test app to replicate the problem and it doesn't show up. – JohnC Dec 27 '12 at 17:24
  • I did some testing and I got the same exception even when deserializing on my local machine. I'm updating the question with my findings. – JohnC Dec 27 '12 at 20:31
  • are the enum values perhaps really really big? like 2^31 and higher? – Marc Gravell Dec 27 '12 at 20:40
  • I just updated my question. It seems like values above 128 throw the exception. – JohnC Dec 27 '12 at 21:12
  • intriguing! That doesn't sound right.... – Marc Gravell Dec 27 '12 at 22:14

2 Answers2

3

This only impacts enums that are : byte

D'oh! Spot the brain-dead error:

case ProtoTypeCode.SByte: Emit(OpCodes.Conv_Ovf_U1); break;
case ProtoTypeCode.Byte: Emit(OpCodes.Conv_Ovf_I1); break;

This will be reversed and deployed later today. Thanks.

To explain properly: byte is unsigned (0 to 255), sbyte is signed (-128 to 127); Conv_Ovf_U1 is basically IL for "convert to byte, checking for overflow" (like how the checked keyword in C# works), and Conv_Ovf_I1 is "convert to sbyte, checking for overflow". Hence any value over 127 was triggering the overflow flag, causing an exception. This is fixed in r614, now deployed.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thanks for looking into this! I just circled back to this problem. I tried looking for r614 on the homepage but saw that the latest available for download is still r602. How can I get the latest (possibly binary) with this fix? – JohnC Jan 04 '13 at 19:45
  • @JohnC ah, my bad. I updated nuget but not google code. I'll fire up my VM to upload it... of course, that said: it is much easier to keep up to date using nuget ;p – Marc Gravell Jan 04 '13 at 19:45
  • Unreal response time! I just tested it and it works! Thank you for everything you've done on protobuf-net. – JohnC Jan 04 '13 at 19:52
  • I'll be sure to check out nuget too :) – JohnC Jan 04 '13 at 19:55
1

That is indeed a bit strange. There could be differences in the CLR that affect ProtoBuf (for instance, the CLR ships with a number of different GCs). Comparing the Machine.config files from the two machines might expose some differences.

As for solving the problem, you could try marking the enum itself with ProtoContract and each enum member with ProtoMember. The latter allows you to set a Value property for ProtoBuf to use. You can also set the DataFormat to Fixed and see if that works better than the default.

You can find some examples here.

Morten Mertner
  • 9,414
  • 4
  • 39
  • 56
  • I don't understand the part about "comparing the Machine.config files"? Pardon me, I'm very new to protobuf in general. As for marking the enum as [ProtoContract], I can't do that because I don't own that code. – JohnC Dec 27 '12 at 16:40
  • Machine.config is the configuration file installed by the .NET framework (and as such therefore has nothing to do with ProtoBuf). You'll find it in the framework installation folder and there is a fresh copy for every CLR version. If you're targeting .NET 4.0 or newer on a 64-bit Windows, you should be able to find it in `C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config`. Note that this is a long shot: your error is most likely elsewhere (e.g. different versions of ProtoBuf being used, or some such). – Morten Mertner Dec 27 '12 at 22:13