From 25fc6c84d1aa295cb4d14ad30b28b4de084e6cbe Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Wed, 7 Dec 2022 15:53:15 +0100 Subject: [PATCH] [dotnet-linker] Handle null fields in BackingFieldDelayHandler as unmarked fields. Fixes #16957. (#16970) The BackingFieldDelayHandler will temporarily remove the body of Dispose methods, and then for every field accessed in the Dispose method that was preserved by the linker, we'll keep the corresponding code in the Dispose method (otherwise we'd remove the code). This is a way to remove fields that are _only_ accessed (and nulled out) in the Dispose method. However, we were running into a problem with determining if a field was marked by the linker: if the field is in a generic type, and that field was not marked by the linker, the linker might have actually removed the field from the containing type before we're processing the Dispose methods, and we'd find a null field definition where no null field definition was expected (eventually resulting in an ArgumentNullException). Fix this by treating a null field definition as an unmarked field. Also add a test. Fixes https://github.com/xamarin/xamarin-macios/issues/16957. --- tests/linker/CommonLinkAnyTest.cs | 14 ++++++++++++++ tools/dotnet-linker/BackingFieldDelayHandler.cs | 6 ++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/linker/CommonLinkAnyTest.cs b/tests/linker/CommonLinkAnyTest.cs index 867bbb9ee3..040aefe68c 100644 --- a/tests/linker/CommonLinkAnyTest.cs +++ b/tests/linker/CommonLinkAnyTest.cs @@ -52,5 +52,19 @@ namespace LinkAnyTest { Assert.IsNotNull (AppContext.GetData ("PINVOKE_OVERRIDE"), "PINVOKE_OVERRIDE"); } #endif + +#if !__WATCHOS__ + [Test] + public void BackingFieldInGenericType () + { + // https://github.com/dotnet/linker/issues/3148 +#if __MACOS__ + var view = new AppKit.NSView (); +#else + var view = new UIKit.UIView (); +#endif + GC.KeepAlive (view.HeightAnchor); + } +#endif // !__WATCHOS__ } } diff --git a/tools/dotnet-linker/BackingFieldDelayHandler.cs b/tools/dotnet-linker/BackingFieldDelayHandler.cs index 08c1b8412f..fd06fe81f1 100644 --- a/tools/dotnet-linker/BackingFieldDelayHandler.cs +++ b/tools/dotnet-linker/BackingFieldDelayHandler.cs @@ -70,8 +70,10 @@ namespace Xamarin.Linker { foreach (var ins in body.Instructions) { switch (ins.OpCode.OperandType) { case OperandType.InlineField: - var field = (ins.Operand as FieldReference)?.Resolve (); - if (!context.Annotations.IsMarked (field)) { + var fr = ins.Operand as FieldReference; + var field = fr?.Resolve (); + var isMarked = field is not null && context.Annotations.IsMarked (field); + if (!isMarked) { var store_field = ins; var load_null = ins.Previous; var load_this = ins.Previous.Previous;