dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.27k stars 4.73k forks source link

XML Serializer does not work correctly in "net8.0-ios" release mode #101041

Open jfversluis opened 6 months ago

jfversluis commented 6 months ago

Issue moved from dotnet/maui#21803


From @JeroenBer on Friday, April 12, 2024 5:21:07 PM

Description

Under certain conditions XML Serializer does not work correctly in "net8.0-ios" release mode. This means the AOT version on iOS device does not work correctly.

Steps to Reproduce

  1. Create an iOS app
  2. Add the testclass below
    • call the function XmlTests.TestVirtual(), it works perfectly in debug mode but throws an exception in release mode.
    • call the function XmlTests.TestFilledNullableDateTime(), , it works perfectly in debug mode but throws an exception in release mode.
  3. Build & deploy in release mode.
    public class ClassWithVirtual
    {
        public virtual double VirtualDoubleProperty{ get; set; }
    }

    public class ClassWithNullableDateTime : IClassInterface
    {
        public DateTime? DateTime { get; set; }
    }

    public interface IClassInterface
    {
        DateTime? DateTime { get; set; }
    }

    public class XmlTests
    {

        public void TestVirtual()
        {
            var serializer = new XmlSerializer(typeof(ClassWithVirtual));

            var obj = new ClassWithVirtual()
            {
                VirtualDoubleProperty = 123.456,
            };
            using var s = new MemoryStream();
            serializer.Serialize(s, obj);

            s.Position = 0;

            var obj2 = (ClassWithVirtual)serializer.Deserialize(s);
            if (obj2.VirtualDoubleProperty != obj.VirtualDoubleProperty)
                throw new Exception("VirtualDoubleProperty changed");
        }

        public void TestFilledNullableDateTime()
        {
            var serializer = new XmlSerializer(typeof(ClassWithNullableDateTime));

            var obj = new ClassWithNullableDateTime()
            {
                DateTime = DateTime.Now,
            };
            using var s = new MemoryStream();
            serializer.Serialize(s, obj);

            s.Position = 0;

            var obj2 = (ClassWithNullableDateTime)serializer.Deserialize(s);
            if (obj2.DateTime != obj.DateTime)
                throw new Exception("DateTime property changed");
        }
    }

There are at least 2 situations that will make Xml Serializer throw an exception in release mode:

  1. Use properties marked as virtual.
  2. Use properties that are also defined as setter properties in an interface that the class implements.

Link to public reproduction project repository

No response

Version with bug

Unknown/Other

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

iOS

Affected platform versions

No response

Did you find any workaround?

  1. Enable the interpreter but we don't want to do this because of performance (see also https://github.com/dotnet/maui/issues/13019).
  2. remove any virtual properties and interfaces with property setters on classes that are Xml Serialized.

Relevant log output

The following exceptions occur in release mode:

Using virtuals something like this:

System.InvalidOperationException : XmlSerializeErrorDetails,4,3 ---> System.ExecutionEngineException : Attempting to JIT compiled method '(wrapper delegate-invoke) void System.Action `<....SerializationTests.ClassWithVirtual, double>:invoke_callvirt_-void_T1_T2 (...)'while running in aot-only mode See http:.....

Using interfaces with properties setters for class also gives a similar exception.

jfversluis commented 6 months ago

Issue moved from dotnet/maui#21803


From @drasticactions on Saturday, April 13, 2024 3:42:08 PM

I believe this would be a runtime issue with Mono AOT. It's unrelated to the MAUI UI framework, outside of the fact that it works in debug mode because MAUIs templates enable the Interpreter by default for debug (hence the issue you linked, where people keep writing code that works because the interpreter happens to be on, but fails in Release mode). If you run this code in a .NET iOS app without the MAUI Template, it would fail in debug mode with the same JIT error. That it works in debug here is happenstance.

@rolfbjarne I'm not sure where this issue should go, what do you think?

jfversluis commented 6 months ago

Issue moved from dotnet/maui#21803


From @JeroenBer on Saturday, April 13, 2024 4:34:59 PM

I understand and agree, this is not MAUI UI. But is "net8.0-ios" part of MAUI ? It felt weird to put it in xamarin-macios, since it's no longer Xamarin. For people without a Xamarin history it's pretty inapprehensible where to report these things, also for finding documentation etc. The term Xamarin is still used in a lot of places. Even for people with Xamarin experience it's sometimes hard to understand.

jfversluis commented 6 months ago

Issue moved from dotnet/maui#21803


From @jfversluis on Monday, April 15, 2024 7:41:11 AM

Look related to https://github.com/dotnet/runtime/issues/99548

ivanpovazan commented 6 months ago

Probably with the similar root cause as: https://github.com/dotnet/runtime/issues/98428

JeroenBer commented 6 months ago

And probably also https://github.com/praeclarum/sqlite-net/issues/1067, I saw same behaviour there.