Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable DefaultValueAttributeSupport in partial trim mode. #9525

Merged

Conversation

matouskozak
Copy link
Member

Currently, users can experience runtime crashes related to the use of DefaultValue attributes (taking type and string) without any trim warnings (see dotnet/runtime#109724). This is because the trim warnings are disable in partial trim mode and this use-case of DefaultValue attributes is not trim compatible.

Workaround around this is to enable _DefaultValueAttributeSupport to prevent customer apps from crashing without trim warnings. App will still crash in TrimMode="full" but user would get warned during compile time.

Copy link
Contributor

@dellis1972 dellis1972 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Is there any way to unit test this on one of our one device tests?

@jonathanpeppers
Copy link
Member

Should we just add Sven's minimal repro:

To a new test in a new System.Xml folder here:

@matouskozak
Copy link
Member Author

@jonathanpeppers
Copy link
Member

It looks like a projitems file needed an update, I pushed this change.

We used to share the files between Xamarin & .NET; it could be refactored in the future.

@matouskozak
Copy link
Member Author

The failures are related:

System.InvalidOperationException : XmlTypeReflectionError, System.XmlTests.C
----> System.ArgumentException : RuntimeInstanceNotAllowed

at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel , String , ImportContext , String , XmlAttributes , Boolean , Boolean , RecursionLimiter )
   at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel , String , ImportContext , String , XmlAttributes , RecursionLimiter )
   at System.Xml.Serialization.XmlReflectionImporter.ImportElement(TypeModel , XmlRootAttribute , String , RecursionLimiter )
   at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type , XmlRootAttribute , String )
   at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
   at System.Xml.Serialization.XmlSerializer..ctor(Type type)
   at System.XmlTests.XmlSerializerTest.TrimmingDefaultValueAttribute()
   at System.Reflection.MethodBaseInvoker.InterpretedInvoke_Method(Object obj, IntPtr* args)
   at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object , BindingFlags )
--ArgumentException
   at System.ComponentModel.DefaultValueAttribute.get_Value()
   at System.Xml.Serialization.XmlAttributes..ctor(ICustomAttributeProvider )
   at System.Xml.Serialization.XmlReflectionImporter.GetAttributes(MemberInfo )
   at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping , StructModel , Boolean , String , RecursionLimiter )
   at System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel , String , Boolean , XmlAttributes , RecursionLimiter )
   at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel , String , ImportContext , String , XmlAttributes , Boolean , Boolean , RecursionLimiter )

@jonathanpeppers
Copy link
Member

It passed in Debug mode, which was broken before?

image

This app has TrimMode=full:

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<AndroidLinkTool Condition=" '$(AndroidLinkTool)' == '' ">r8</AndroidLinkTool>
<TrimMode Condition=" '$(TrimMode)' == '' ">full</TrimMode>

Can the test check a feature flag at runtime (AppContext.TryGetSwitch), and ignore in some cases? Ideally we'd get a green test in Debug and the rest ignore.

@matouskozak
Copy link
Member Author

matouskozak commented Nov 19, 2024

It passed in Debug mode, which was broken before?

image

This app has TrimMode=full:

<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<AndroidLinkTool Condition=" '$(AndroidLinkTool)' == '' ">r8</AndroidLinkTool>
<TrimMode Condition=" '$(TrimMode)' == '' ">full</TrimMode>

Can the test check a feature flag at runtime (AppContext.TryGetSwitch), and ignore in some cases? Ideally we'd get a green test in Debug and the rest ignore.

No, it was the release (related to illink) that was broken but the "fix" is only for TrimMode="partial" so if the test are running in full trim mode then they will fail. We can either extend the "fix" to all trim modes or just add the _DefaultValueAttributeSupportto

<!-- Trimmer switches required for tests -->
<JsonSerializerIsReflectionEnabledByDefault>true</JsonSerializerIsReflectionEnabledByDefault>

Note: I limited the "fix" to partial mode because that's where no trim warnings are shown and yet it failed. In full mode the warnings will show potential issues so that users can add approriate feature switches if needed.

@jonathanpeppers
Copy link
Member

Let me add an extra test run, that runs the tests with TrimMode=partial.

@jonathanpeppers
Copy link
Member

I think it's working now:

image

I reran, because there are some other random, http failures.

@jonathanpeppers jonathanpeppers merged commit 5588e7d into dotnet:main Nov 20, 2024
57 checks passed
jonathanpeppers added a commit that referenced this pull request Nov 20, 2024
…=partial` (#9525)

Context: dotnet/runtime#109724

In .NET 9, certain apps could crash with:

    System.ArgumentException: RuntimeInstanceNotAllowed
      ?, in object DefaultValueAttribute.get_Value()
      ?, in new XmlAttributes(ICustomAttributeProvider)
      ?, in XmlAttributes XmlReflectionImporter.GetAttributes(MemberInfo)
      ?, in bool XmlReflectionImporter.InitializeStructMembers(StructMapping, StructModel, bool, string, RecursionLimiter)
      ?, in StructMapping XmlReflectionImporter.ImportStructLikeMapping(StructModel, string, bool, XmlAttributes, RecursionLimiter)

.NET's concept of `$(PublishTrimmed)` is used to decide which trimmer
feature switches are toggled. This is normally set for both Debug &
Release, but Android only sets it for Release. This means that the
`$(_DefaultValueAttributeSupport)` feature switch is not set properly
in some cases, which causes the crash.

For now, we can set `$(_DefaultValueAttributeSupport)` for
`TrimMode=partial`, the default in .NET MAUI apps.

See #9526 for how we might
better address this in the future.

In order to test this change:

* Add a `XmlSerializerTest` to `Mono.Android-Tests`

* Run a copy of `Mono.Android-Tests` with `-p:TestsFlavor=TrimModePartial`

* Also set `$(_DefaultValueAttributeSupport)` for `TrimMode=full` in
  our test project, so `XmlSerializerTest` will pass in that mode as
  well.

Co-authored-by: Jonathan Peppers <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants