-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Nullable Reference Types & ICustomMarshaler #50144
Comments
cc: @jeffhandley |
Thanks for filing this, @jonpryor, and for providing all of these details! We've been treating changes to nullable annotations as bug fixes and documenting them in dotnet/docs#21202 by adding (unchecked) items into the issue description to capture the aggregated changes. If the changes are agreed upon, we can bypass the API review process and go straight to PR. |
Fixes: dotnet#50144 Re-review the [`ICustomMarshaler` interface][0] in the context of Nullable Reference Types, so that `null` is allowed *everywhere*. Do so because `ICustomMarshaler` is an interface which dates to .NET 1.0, and existing interface implementations already assume that `null` can be used as parameters or return values, including existing unit tests within this repo! ```diff --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ICustomMarshaler.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ICustomMarshaler.cs @@ -6,17 +6,13 @@ namespace System.Runtime.InteropServices namespace System.Runtime.InteropServices { // This the base interface that must be implemented by all custom marshalers. public interface ICustomMarshaler { - object MarshalNativeToManaged(IntPtr pNativeData); + object? MarshalNativeToManaged(IntPtr pNativeData); - IntPtr MarshalManagedToNative(object ManagedObj); + IntPtr MarshalManagedToNative(object? ManagedObj); void CleanUpNativeData(IntPtr pNativeData); - void CleanUpManagedData(object ManagedObj); + void CleanUpManagedData(object? ManagedObj); int GetNativeDataSize(); } ``` Additional rationale: a cursory [search through GitHub][1] finds numerous examples which return or accept `null`, including: * [`TestLucene.CrapLord.Utf8ConstCustomMarshaler`][2]: allows `MarshalManagedToNative(null)`. * [`Script.DebugMarshaler`][3]: `MarshalNativeToManaged(IntPtr.Zero)` can return `null`, via `Marshal.PtrToStringAuto(IntPtr.Zero)`. * [`FFmpeg.AutoGen.UTF8Marshaler`][4]: returns `null` on `MarshalNativeToManaged(IntPtr.Zero)`, and allows `MarshalManagedToNative(null)`. * [`Microsoft.Win32.Security.SecurityAttributesMarshaler`][5]: returns `null` for `MarshalNativeToManaged(IntPtr.Zero)` and accepts `MarshalManagedToNative(null)`. Updating `ICustomMarshaler` to use `object?` instead of `object` will allow these (and other) existing types to be updated to use C#8 Nullable Reference Types without requiring semantic changes or disabling the nullability checks around `ICustomMarshaler`. [0]: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.icustommarshaler?view=net-5.0 [1]: https://github.com/search?q=ICustomMarshaler+marshalnativetomanaged+language%3Acsharp&type=Code [2]: https://github.com/ststeiger/WebRansack/blob/5da604ea4bbc9f35fa35c512b81f8d049fe47ed6/TestLucene/CrapLord/Marshallers/Utf8ConstCustomMarshaler.cs [3]: https://github.com/defin/jrm-code-project/blob/0716e271f449b52bfabe4c2fefe8fc5e62902f42/LScript/DebugMarshaler.cs [4]: https://github.com/jiangguang5201314/VideoRender/blob/b0fc7f172001673138b6bfd193f4ed71f46d4802/AVMedia/AVMedia/FFmpeg/ConstCharPtrMarshaler.cs [5]: https://github.com/dineshkummarc/FlexWikiCore-2.1.0.274/blob/9b83495ac92a2d72a2be63bacfdff0662941fca5/FlexWikiCore-2.1.0.274-Source/lib/Win32Security/src/SecurityAttributesMarshaler.cs
The Mono & .NET runtime marshaler will never pass |
Regardless, thanks for raising and discussing this, @jonpryor. |
Background and Motivation
The
ICustomMarshaler
interface should be re-reviewed in the context of Nullable Reference Types, in thatnull
should be allowed everywhere. This is becauseICustomMarshaler
is an interface which dates to .NET 1.0, and existing interface implementations already assume thatnull
can be used as parameters or return values.Proposed API
Usage Examples
Mono.Posix
has had a type implementingICustomMarshaler
since 2005 which allowsnull
values to be used:https://github.com/mono/mono/blob/2020-02/mcs/class/Mono.Posix/Mono.Unix.Native/FileNameMarshaler.cs#L59-L75
Note: Above code is C# 1, and doesn't use nullable reference types, hence
object
and notobject?
.Mono.Posix is not unique here; a cursory search through GitHub finds numerous examples which return or accept
null
:TestLucene.CrapLord.Utf8ConstCustomMarshaler
: allowsMarshalManagedToNative(null)
.Script.DebugMarshaler
:MarshalNativeToManaged(IntPtr.Zero)
can returnnull
, viaMarshal.PtrToStringAuto(IntPtr.Zero)
.FFmpeg.AutoGen.UTF8Marshaler
returnsnull
onMarshalNativeToManaged(IntPtr.Zero)
, and allowsMarshalManagedToNative(null)
.Microsoft.Win32.Security.SecurityAttributesMarshaler
: returnsnull
forMarshalNativeToManaged(IntPtr.Zero)
and acceptsMarshalManagedToNative(null)
.Alternative Designs
If
ICustomMarshaler
isn't updated to allow the long-standing practice of accepting and returningnull
values, then existing code will need to be "uglified" to disable the warning around appropriate blocks of code, e.g.https://github.com/mono/mono.posix/blob/25c94683fb9c5ec667d38382904a85d813aaaadf/src/Mono.Unix/Mono.Unix.Native/FileNameMarshaler.cs#L69-L86
Risks
This will cause new warnings to be emitted for any newly written code which implements the
ICustomMarshaler
interface, and such new code doesn't allow/permit `nulls.This change will make it easier to "reasonably" migrate existing code which already supports
null
values.The text was updated successfully, but these errors were encountered: