You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// Throwing an exception here is better than returning a null pointer, because that will crash the process when the pointer is dereferenced
173
+
// (and none of the callers can do anything useful with a null pointer anyway).
174
+
thrownewObjectDisposedException($"This object (of type {GetType().Name}) does not have a data pointer anymore, possibly because of a race condition. Please file a bug at https://github.com/dotnet/macios/issues.");
// We need to delay the deletion of the native memory pointed to by data_handle until
1037
+
// after this instance has been collected. A CriticalHandle seems to fit this purpose like glove, until
1038
+
// you realize that a CriticalHandle is only kept alive until the parent object _becomes finalizable_,
1039
+
// not _is collected_, which is very different - in other words, resurrected objects don't keep CriticalHandles
1040
+
// they contain alive. This is a problem because every single managed NSObject instance is resurrected, and we
1041
+
// need the native memory to stay alive after resurrection.
1042
+
//
1043
+
// So this solution depends on a few bits:
1044
+
// * At this point, this instance may have become finalizable, but the native memory shouldn't have been freed yet.
1045
+
// * The original NSObjectDataHandle (aka CriticalHandle) will be collected in this/upcoming GC cycle, and can't
1046
+
// be trusted to keep the native memory alive anymore.
1047
+
// * So we just create a new one, pointing to the same native memory, and replace the original NSObjectDataHandle (aka
1048
+
// CriticalHandle) with it
1049
+
// * This works, because since this instance has become / will become resurrected, it's not finalizable anymore,
1050
+
// and it will keep the new NSObjectDataHandle instance (and the native memory it points to) alive.
1051
+
// * Now if this instance is deemed finalizable, and then resurrected *again*, bad things will likely happen. This
1052
+
// is a bit more unlikely though, because we don't re-register the finalizer for execution, so unless somebody
1053
+
// else does that, it's quite unlikely this instance will become resurrected a second time.
1054
+
varprevious_data=data_handle;
1055
+
if(previous_dataisnull){
1056
+
varmsg=$"This object (of type {GetType().Name}) does not have an existing data pointer, possibly because of a race condition. Please file a bug at https://github.com/dotnet/macios/issues.");
varmsg=$"This object (of type {GetType().Name}) does not have valid data pointer, possibly because of a race condition. Please file a bug at https://github.com/dotnet/macios/issues.");
1071
+
#if CONSISTENCY_CHECKS
1072
+
thrownewInvalidOperationException(msg);
1073
+
#else
1074
+
Runtime.NSLog(msg);
1075
+
return;
1076
+
#endif
1077
+
}
1078
+
1079
+
previous_data.Invalidate();
1080
+
// Don't dispose previous_data, because another thread might be referencing it, and trying to access its pointer - which is still valid.
1081
+
// The GC will dispose of previous_data when its not accessible anymore.
0 commit comments