michaeledgar / protobuf-net

Automatically exported from code.google.com/p/protobuf-net
0 stars 0 forks source link

Deserialization from XML does not produce an error or return correctly deserialized object #356

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago

What steps will reproduce the problem?
1. Serialize an object to XML string and convert the string to a byte array
2. use byte array in a MemoryStream as stream for Protobuf deserialization
1+2 are in the code below (it's an NUnit test)

What is the expected output? What do you see instead?
I expected one of two things:
1. Deserialization from XML is supported and the object is correctly 
deserialized
Or 2. An exception upon protobuf deserialization and/or return of null

What version of the product are you using? On what operating system?
I'm using the NuGet package 2.0.0.628 on Windows7 (64-bit)

Please provide any additional information below.

using System.Text;
using System.Xml;

namespace test
{
    using System;
    using System.IO;
    using System.Xml.Serialization;
    using NUnit.Framework;
    using ProtoBuf;

    [XmlType]
    public class SimpleObject : IEquatable<SimpleObject>
    {
        private double _value;
        private String _name;

        [XmlElement(Order = 1)]
        public double Value { get { return _value; } set { _value = value; } }
        [XmlElement(Order = 2)]
        public String Name { get { return _name; } set { _name = value; } }

        /// <summary>
        /// Revert to the default settings
        /// </summary>
        public void ToDefaults()
        {
            _value = 10.0;
            _name = "Default name";
        }

        public bool Equals(SimpleObject other)
        {
            if (null == other) 
                return false;

            return (Math.Abs(Value - other.Value) < 1e-12 &&
                    Name.Equals(other.Name, StringComparison.OrdinalIgnoreCase));
        }
    }

    [TestFixture]
    public class TestIncorrectStream
    {
        [Test]
        public void TestDeserializationFromXml()
        {
            SimpleObject original = new SimpleObject();
            original.ToDefaults();

            // assert that Equals routine works
            Assert.That(original.Equals(original));

            // serialize to XML text
            StringBuilder sb = new StringBuilder();
            XmlWriter writer = XmlWriter.Create(sb);
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(SimpleObject));
            xmlSerializer.Serialize(writer, original);
            Console.WriteLine(sb.ToString());

            // use XML text as input stream for XML deserialization
            byte[] bytes = Encoding.Unicode.GetBytes(sb.ToString());
            Assert.That(bytes.Length > 0);
            MemoryStream ms = new MemoryStream(bytes);
            SimpleObject fromXml = (SimpleObject)xmlSerializer.Deserialize(ms);
            Assert.That(original.Equals(fromXml));

            // rewind the stream and deserialize using Protobuf 
            ms.Seek(0L, SeekOrigin.Begin);
            SimpleObject fromProtobuf = Serializer.Deserialize<SimpleObject>(ms);

            // either deserialization from XML works or
            // it should not give an object instance (either return null or throw Exception)
            Assert.That(fromProtobuf == null || original.Equals(fromProtobuf));
        }
    }
}

Original issue reported on code.google.com by mennod...@gmail.com on 14 Feb 2013 at 8:52

GoogleCodeExporter commented 9 years ago
Oh, and as to why this is relevant: I switched from XML serialization to 
Protobuf recently (both in Base64 but that is not relevant to the problem 
outlined above). All the settings in userspace still hold the Base64-converted 
XML strings and I noticed that when I use these strings to deserialize using 
Protobuf that there is no error but that the object returned is not 
deserialized only constructed.

Original comment by mennod...@gmail.com on 14 Feb 2013 at 8:54

GoogleCodeExporter commented 9 years ago
For the record, I'm using NuGet package 2.0.0.621, not 2.0.0.628 (typo)

Original comment by mennod...@gmail.com on 15 Feb 2013 at 7:11

GoogleCodeExporter commented 9 years ago
Strictly speaking, the behavior is undefined when giving it invalid data; in 
this case, it was breaking out because at the start of the data it detected 
what looked like an "end group", which terminates an object.

In an *attempt* to better detect this, I am playing locally with 2 additional 
checks:

- a check on unconsumed buffered data (note that there is still an edge case if 
the fault is at the end of the buffer boundary)
- restrict the end-of-group special handling to cases where we expect it

both of these individually make your scenario fail (which is what we want). I'm 
just working through some possible false-positives the regression suite, but I 
think we can do a better job of detecting craziness.

But ultimately: "GIGO". We can *try* to detect obviously bad data - but some 
types of bad data can accidentally satisfy any arbitrary tests we put in.

Original comment by marc.gravell on 15 Feb 2013 at 8:52

GoogleCodeExporter commented 9 years ago
Fixed in r628

Original comment by marc.gravell on 15 Feb 2013 at 8:56