Please do not reply to this email- if you want to comment on the bug, go to the URL shown below and enter your comments there.
Changed by [EMAIL PROTECTED] http://bugzilla.ximian.com/show_bug.cgi?id=80332 --- shadow/80332 2006-12-20 15:33:35.000000000 -0500 +++ shadow/80332.tmp.15774 2006-12-20 15:33:35.000000000 -0500 @@ -0,0 +1,179 @@ +Bug#: 80332 +Product: Mono: Class Libraries +Version: 1.2 +OS: +OS Details: +Status: NEW +Resolution: +Severity: +Priority: Wishlist +Component: CORLIB +AssignedTo: [EMAIL PROTECTED] +ReportedBy: [EMAIL PROTECTED] +QAContact: [EMAIL PROTECTED] +TargetMilestone: --- +URL: +Cc: +Summary: info.AddValue(String, Object,Type) causes corrupt Binary Serialization + +I have an existing library which does the following. + +And is more completely: + +class MySerializableClass : ISerializable { + // Note we store the enum value as an Int32, just in case + // it was ever to change format... + public void GetObjectData(SerializationInfo info, +StreamingContext context) + { + // *** This is line the causes the problem *** + // m_fooCode is "enum FooByteEnum : byte { ... }" + info.AddValue("FooCode", this.m_fooCode, typeof(Int32)); + } + + protected DummySerializableClass(SerializationInfo info, +StreamingContext context) + { + this.m_fooCode = (FooByteEnum)info.GetInt32("FooCode"); + } +} +(Where m_fooCode is "enum FooByteEnum : byte { ... }"). + +Now in hindsight I agree that the use of the AddValue method is a bit +odd, perhaps with an explicit cast, and also just using AddValue +(String,Int32) directly, being better... + +However with binary serialization on the MSFT CLR it works, but when I +run the library's unit-tests on the Mono CLR it fails at deserialization +time with: "System.Runtime.Serialization.SerializationException : +Unexpected binary element: 0". Further testing shows that there is also +an error when the MSFT CLR too is used to read the Mono output +("System.Runtime.Serialization.SerializationException: Binary stream '0' +does not contain a valid BinaryHeader. Possible causes are invalid stream +or object version change between serialization and deserialization."). + +Manual decoding of the binary output shows that the MSFT version writes +{type=Int32 value=xx-xx-xx-xx}, whereas Mono writes {type=Int32 +value=FooByteEnum=xx}. Not too surprising the deserialization fails. :-, +( + +My full decoding of the output created by the initial example is as +follows. This is by the use of the nice document, +http://primates.ximian.com/~lluis/dist/binary_serialization_format.htm + +* MSFT 2.0.50727.42.bin +Header +00 01 00 00 00 FF FF FF FF 01 00 00 00 00 00 00 00 Assembly +0C, 02 00 00 00 ID=2 +43, +4D 6F 6E 6F 42 75 67 4E 75 6D 30 32 2C 20 56 65 +72 73 69 6F 6E 3D 31 2E 30 2E 30 2E 30 2C 20 43 +75 6C 74 75 72 65 3D 6E 65 75 74 72 61 6C 2C 20 50 75 62 6C 69 63 4B 65 +79 54 6F 6B 65 6E 3D 6E +75 6C 6C + "MonoBugNum02, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" +ExternalObject +05, 01 00 00 00 ID=1 +2F, +4D 6F 6E 6F 42 75 67 4E 75 6D 32 2E 4D 6F 6E 6F +42 75 67 4E 75 6D 30 32 2B 44 75 6D 6D 79 53 65 +72 69 61 6C 69 7A 61 62 6C 65 43 6C 61 73 73 + " MonoBugNum2.MonoBugNum02+DummySerializableClass" +01 00 00 00 Num. Fields +07, 46 6F 6F 43 6F 64 65 "FooCode" +00 type-tag=Primitive +08 type-spec=Int32 +02 00 00 00 In Assembly ID=2 +values[]= +02 00 00 00 (Int32)=2 +End +0B + +* Mono 2.0.50727.42.bin +00 01 00 00 00 FF FF FF FF 01 00 00 00 00 00 00 00 Assembly +0C, 02 00 00 00 ID=2 +0C, 4D 6F 6E 6F 42 75 67 4E 75 6D 30 32 "MonoBugNum02" +ExternalObject +05, 01 00 00 00 ID=1 +2F, 4D 6F 6E 6F 42 75 67 4E 75 6D 32 2E 4D 6F 6E 6F +42 75 67 4E 75 6D 30 32 2B 44 75 6D 6D 79 53 65 +72 69 61 6C 69 7A 61 62 6C 65 43 6C 61 73 73 + " MonoBugNum2.MonoBugNum02+DummySerializableClass" +01 00 00 00 NumFields=1 +07, 46 6F 6F 43 6F 64 65 "FooCode" +00 type-tag=Primitive +08 type-spec=Int32 +02 00 00 00 In Assembly ID=2 +values[]= +ExternalObject +05, 03 00 00 00 ID=3 +20, 4D 6F 6E 6F 42 75 67 4E 75 6D 32 2E 4D 6F 6E 6F +42 75 67 4E 75 6D 30 32 2B 46 6F 6F 45 6E 75 6D + " MonoBugNum2.MonoBugNum02+FooEnum" +01 00 00 00 NumFields=1 +07, 76 61 6C 75 65 5F 5F "value__" +00 type-tag=Primitive +02 type-spec=Byte +02 00 00 00 In Assembly ID=2 +values[]= +02 (Byte)=2 +End +0B + +So we can see why the exception is "Unexpected binary element: 0...". +The deserializer is told that the type of the value is Int32 and thus +goes and reads the value as the next four bytes. In the corrupt case it +thus reads "05, 03 00 00" as the value, which is actually the start of an +block describing the enum object, and starts reading again at +"00 20, 4D 6F, ...", with 0 not being a valid value. + + +Now I can't work out what the AddValue(String, Object, Type) overload is +really intended for, and is intended to do. My best guess is that one +passes the Type value so that it can check that the value you pass is of +the correct type for that field. This is _slightly_ backed-up by the +MSDN documentation: "The Type to associate with the current object. This +parameter must always be the type of the object itself or of one of its +base classes.", the summary text is: "Adds a value into the +SerializationInfo store, where value is associated with name and is +serialized as being of Type type." + +So I set to writing a set of unit-tests to show that the MSFT version +will prohibit the writing of a value that is not of the correct type. +However I couldn't get it to throw in any case, getting as far as the +following without exception on writing: + + [Serializable] + class Foo { public Foo() { } } + [Serializable] + class Bar { public Bar() { } } +... + Foo value = new Foo(); + info.AddValue("Name", value, typeof(Bar)); + +So it (apparently) never throws! I haven't yet looked at the output from +that case to see what on earth it does write... + + +One way to stop this class of corrupt output is to do that that check. +Something like the following I presume: + + void AddValue(String name, Object value, Type type) { + // Per MSDN: + // type--"This parameter must always be the type of + // the object itself or of one of its base classes.". + if(!type.InstanceOf(value)) { + throw new ArgumentException(...); + } + ... ... + } + + +I've attached some of my test code. Compile the C# file as a command- +line app. Then if running on Windows, in a Mono Command Prompt, run +RunBothWays.cmd. It will run each of the following on both CLRs: simple +round-trip test (fails on Mono), writes the output to disk named per the +CLR, and then reads the opposite file back in. The last shows that both +CLRs fail on reading the Mono-produced output. There are also some NUnit +unit-tests in there two; the ones *aiming* to show that AddValue/3 would +fail if passed an inconsistent value and type... _______________________________________________ mono-bugs maillist - [email protected] http://lists.ximian.com/mailman/listinfo/mono-bugs
