[Foundation] Don't dispose tagged pointers. Fixes #21425.
TODO: better description. Fixes https://github.com/xamarin/xamarin-macios/issues/21425.
This commit is contained in:
Родитель
209de6f297
Коммит
6a514490e0
|
@ -573,6 +573,9 @@
|
|||
<!-- Set default ValidateObjectPointers value -->
|
||||
<_ValidateObjectPointers Condition="'$(_ValidateObjectPointers)' == ''">false</_ValidateObjectPointers>
|
||||
|
||||
<!-- Set default DisposeTaggedPointers value -->
|
||||
<_DisposeTaggedPointers Condition="'$(_DisposeTaggedPointers)' == ''">true</_DisposeTaggedPointers>
|
||||
|
||||
<_CustomLinkerOptions>
|
||||
AreAnyAssembliesTrimmed=$(_AreAnyAssembliesTrimmed)
|
||||
AssemblyName=$(AssemblyName).dll
|
||||
|
@ -687,6 +690,7 @@
|
|||
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.IsManagedStaticRegistrar" Value="$(_IsManagedStaticRegistrarFeature)" Trim="true" />
|
||||
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.IsNativeAOT" Value="$(_IsNativeAOTFeature)" Trim="true" />
|
||||
<RuntimeHostConfigurationOption Include="ObjCRuntime.Class.ValidateObjectPointers" Value="$(_ValidateObjectPointers)" Trim="true" />
|
||||
<RuntimeHostConfigurationOption Include="ObjCRuntime.NSObject.DisposeTaggedPointers" Value="$(_DisposeTaggedPointers)" Trim="true" />
|
||||
|
||||
<!-- Mark all assemblies to be copied if we're not linking any assemblies -->
|
||||
<ResolvedFileToPublish
|
||||
|
|
|
@ -998,13 +998,49 @@ namespace Foundation {
|
|||
handle = NativeHandle.Zero;
|
||||
}
|
||||
|
||||
// This option is turned on by setting _DisposeTaggedPointers property to true in the project file.
|
||||
static bool dispose_tagged_pointers;
|
||||
static bool DisposeTaggedPointers {
|
||||
get => dispose_tagged_pointers;
|
||||
set => dispose_tagged_pointers = value;
|
||||
}
|
||||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
return;
|
||||
disposed = true;
|
||||
|
||||
if (handle != NativeHandle.Zero) {
|
||||
/* Tagged pointer is limited to 64bit, which is all we support anyway.
|
||||
*
|
||||
* The tagged pointer bit is:
|
||||
*
|
||||
* Arm64: most significant bit
|
||||
* Simulators (both on arm64 and x64 desktops): most significant bit
|
||||
* Desktop/x64 (macOS + Mac Catalyst): least significant bit
|
||||
* Ref: https://github.com/apple-oss-distributions/objc4/blob/89543e2c0f67d38ca5211cea33f42c51500287d5/runtime/objc-internal.h#L603-L672
|
||||
*/
|
||||
#if __MACOS__ || __MACCATALYST__
|
||||
ulong _OBJC_TAG_MASK;
|
||||
if (Runtime.IsARM64CallingConvention) {
|
||||
_OBJC_TAG_MASK = 1UL << 63;
|
||||
} else {
|
||||
_OBJC_TAG_MASK = 1UL;
|
||||
}
|
||||
#else
|
||||
const ulong _OBJC_TAG_MASK = 1UL << 63;
|
||||
#endif
|
||||
|
||||
bool isTaggedPointer;
|
||||
unchecked {
|
||||
var ulongHandle = (ulong) (IntPtr) handle;
|
||||
isTaggedPointer = (ulongHandle & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
|
||||
}
|
||||
|
||||
if (!DisposeTaggedPointers && isTaggedPointer) {
|
||||
// don't dispose tagged pointers.
|
||||
FreeData (); // still need to do this though.
|
||||
} else if (handle != NativeHandle.Zero) {
|
||||
if (disposing) {
|
||||
ReleaseManagedRef ();
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<linker>
|
||||
<assembly fullname="Microsoft.macOS">
|
||||
<type fullname="Foundation.NSObject">
|
||||
<method signature="System.Boolean get_DisposeTaggedPointers()" body="stub" feature="Foundation.NSObject.DisposeTaggedPointers" featurevalue="false" value="false" />
|
||||
<method signature="System.Boolean get_DisposeTaggedPointers()" body="stub" feature="Foundation.NSObject.DisposeTaggedPointers" featurevalue="true" value="true" />
|
||||
</type>
|
||||
<type fullname="ObjCRuntime.Dlfcn">
|
||||
<method signature="System.Void WarnOnce()" body="stub" feature="System.Diagnostics.Debugger.IsSupported" featurevalue="false" />
|
||||
</type>
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
using System;
|
||||
|
||||
using Foundation;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace MonoTouchFixtures.ObjCRuntime {
|
||||
|
||||
[TestFixture]
|
||||
[Preserve (AllMembers = true)]
|
||||
public class TaggedPointerTest {
|
||||
|
||||
[Test]
|
||||
public void TaggedPointersArentDisposed ()
|
||||
{
|
||||
var notificationData =
|
||||
"""
|
||||
{
|
||||
action = "action";
|
||||
aps =
|
||||
{
|
||||
category = "ee";
|
||||
"content-available" = dd;
|
||||
"mutable-content" = cc;
|
||||
sound = bb;
|
||||
"thread-id" = "aa";
|
||||
};
|
||||
"em-account" = "a";
|
||||
"em-account-id" = "b";
|
||||
"em-body" = "c";
|
||||
"em-date" = "d";
|
||||
"em-from" = "e";
|
||||
"em-from-address" = "f";
|
||||
"em-notification" = g;
|
||||
"em-notification-id" = h;
|
||||
"em-subject" = "i";
|
||||
"gcm.message_id" = j;
|
||||
"google.c.a.e" = k;
|
||||
"google.c.fid" = l;
|
||||
"google.c.sender.id" = m;
|
||||
}
|
||||
""";
|
||||
|
||||
var data = NSData.FromString (notificationData);
|
||||
var fmt = NSPropertyListFormat.OpenStep;
|
||||
var userInfo = (NSMutableDictionary) NSPropertyListSerialization.PropertyListWithData (data, NSPropertyListReadOptions.Immutable, ref fmt, out var error);
|
||||
var apsKey = new NSString ("aps");
|
||||
// Iteration here should not throw ObjectDisposedExceptions
|
||||
foreach (var kv in userInfo) {
|
||||
apsKey.Dispose ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче