Skip to content

Commit

Permalink
[trimming] Enable $(_DefaultValueAttributeSupport) for `$(TrimMode)…
Browse files Browse the repository at this point in the history
…=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 <jonathan.peppers@microsoft.com>
  • Loading branch information
matouskozak and jonathanpeppers committed Nov 20, 2024
1 parent 84a95ef commit 20f08bd
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 1 deletion.
10 changes: 10 additions & 0 deletions build-tools/automation/azure-pipelines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,16 @@ extends:
artifactSource: bin/Test$(XA.Build.Configuration)/$(DotNetTargetFramework)-android/Mono.Android.NET_Tests-Signed.aab
artifactFolder: $(DotNetTargetFramework)-NoAot

- template: /build-tools/automation/yaml-templates/apk-instrumentation.yaml@self
parameters:
configuration: $(XA.Build.Configuration)
testName: Mono.Android.NET_Tests-TrimModePartial
project: tests/Mono.Android-Tests/Runtime-Microsoft.Android.Sdk/Mono.Android.NET-Tests.csproj
testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)TrimModePartial.xml
extraBuildArgs: -p:TestsFlavor=TrimModePartial -p:TrimMode=partial
artifactSource: bin/Test$(XA.Build.Configuration)/$(DotNetTargetFramework)-android/Mono.Android.NET_Tests-Signed.aab
artifactFolder: $(DotNetTargetFramework)-TrimModePartial

- template: /build-tools/automation/yaml-templates/apk-instrumentation.yaml@self
parameters:
configuration: $(XA.Build.Configuration)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@
<UseNativeHttpHandler Condition="'$(UseNativeHttpHandler)' == ''">true</UseNativeHttpHandler>
<BuiltInComInteropSupport Condition="'$(BuiltInComInteropSupport)' == ''">false</BuiltInComInteropSupport>
<JsonSerializerIsReflectionEnabledByDefault Condition="'$(JsonSerializerIsReflectionEnabledByDefault)' == '' and '$(TrimMode)' == 'partial'">true</JsonSerializerIsReflectionEnabledByDefault>
<!-- Set to disable throwing behavior, see: https://github.com/dotnet/runtime/issues/109724 -->
<_DefaultValueAttributeSupport Condition="'$(_DefaultValueAttributeSupport)' == '' and '$(TrimMode)' == 'partial'">true</_DefaultValueAttributeSupport>
<MetricsSupport Condition="'$(MetricsSupport)' == ''">false</MetricsSupport>
<AndroidAvoidEmitForPerformance Condition="'$(AndroidAvoidEmitForPerformance)' == ''">$(AvoidEmitForPerformance)</AndroidAvoidEmitForPerformance>
<AndroidAvoidEmitForPerformance Condition="'$(AndroidAvoidEmitForPerformance)' == ''">true</AndroidAvoidEmitForPerformance>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System.Text\EncodingTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System.Text.Json\JsonSerializerTest.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System.Threading\InterlockedTest.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System.Xml\XmlSerializer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Java.Interop\JavaObjectExtensionsTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Xamarin.Android.Net\AndroidClientHandlerTests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Xamarin.Android.Net\AndroidMessageHandlerTests.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
<AndroidLinkTool Condition=" '$(AndroidLinkTool)' == '' ">r8</AndroidLinkTool>
<TrimMode Condition=" '$(TrimMode)' == '' ">full</TrimMode>
<!-- Trimmer switches required for tests -->
<JsonSerializerIsReflectionEnabledByDefault>true</JsonSerializerIsReflectionEnabledByDefault>
<JsonSerializerIsReflectionEnabledByDefault Condition="'$(TrimMode)' == 'full'">true</JsonSerializerIsReflectionEnabledByDefault>
<_DefaultValueAttributeSupport Condition="'$(TrimMode)' == 'full'">true</_DefaultValueAttributeSupport>
</PropertyGroup>

<ItemGroup>
Expand Down
23 changes: 23 additions & 0 deletions tests/Mono.Android-Tests/System.Xml/XmlSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Xml.Serialization;
using System.ComponentModel;

using NUnit.Framework;

namespace System.XmlTests {
public class C {
[DefaultValue(typeof(C), "c")]
public Type? T { get; }
}

[TestFixture]
public class XmlSerializerTest {

[Test]
public void TrimmingDefaultValueAttribute ()
{
// Context: https://github.com/dotnet/runtime/issues/109724
var s = new XmlSerializer(typeof(C));
_ = new C().T; // Prevent C.T from being removed by trimming
}
}
}

0 comments on commit 20f08bd

Please sign in to comment.