Skip to content

[release/9.0.1xx] [src/runtime] Don't allow native code to resolve a weak reference for an object in the finalizer queue. #23086

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions runtime/runtime.m
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
void* set_gchandle_tramp;
void* get_flags_tramp;
void* set_flags_tramp;
void* retainWeakReference_tramp;
};

enum InitializationFlags : int {
Expand Down Expand Up @@ -180,6 +181,7 @@
(void *) &xamarin_set_gchandle_trampoline,
(void *) &xamarin_get_flags_trampoline,
(void *) &xamarin_set_flags_trampoline,
(void *) &xamarin_retainWeakReference_trampoline,
};

static struct InitializationOptions options = { 0 };
Expand Down
40 changes: 40 additions & 0 deletions runtime/trampolines.m
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,15 @@
return ((func_objc_msgSendSuper) objc_msgSendSuper) (&sup, sel);
}

BOOL
xamarin_invoke_objc_method_implementation_BOOL (id self, SEL sel, IMP xamarin_impl)
{
struct objc_super sup;
find_objc_method_implementation (&sup, self, sel, xamarin_impl);
typedef BOOL (*func_objc_msgSendSuper) (struct objc_super *sup, SEL sel);
return ((func_objc_msgSendSuper) objc_msgSendSuper) (&sup, sel);
}

#if MONOMAC
id
xamarin_copyWithZone_trampoline1 (id self, SEL sel, NSZone *zone)
Expand Down Expand Up @@ -804,6 +813,37 @@
return self;
}

BOOL
xamarin_retainWeakReference_trampoline (id self, SEL sel)
{
GCHandle gchandle = xamarin_get_gchandle (self);
uint32_t flags = 0;
MonoObject *mobj = NULL;
bool isInFinalizerQueue = false;

if (gchandle != INVALID_GCHANDLE) {
MONO_THREAD_ATTACH;
mobj = xamarin_gchandle_get_target (gchandle);
if (mobj != NULL) {
flags = xamarin_get_nsobject_flags (mobj);
isInFinalizerQueue = (flags & NSObjectFlagsInFinalizerQueue) == NSObjectFlagsInFinalizerQueue;
}
MONO_THREAD_DETACH;
}

#if defined(DEBUG_REF_COUNTING)
PRINT ("xamarin_retainWeakReference_trampoline (%s Handle=%p) gchandle: %i flags: %x mobj: %p isInFinalizerQueue: %i\n",
class_getName ([self class]), self, gchandle, flags, mobj, isInFinalizerQueue);
#endif

// Do not allow any weak references to be resolved if the managed wrapper has been scheduled for finalization,
// all kinds of bad things happen when native code tries to use such an object.
if (isInFinalizerQueue)
return FALSE;

/* Invoke the real release method */
return xamarin_invoke_objc_method_implementation_BOOL (self, sel, (IMP) xamarin_retainWeakReference_trampoline);
}

// We try to use the associated object API as little as possible, because the API does
// not like recursion (see bug #35017), and it calls retain/release, which we might
Expand Down
1 change: 1 addition & 0 deletions runtime/xamarin/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ void xamarin_log_managed_exception (MonoObject *exception, MarshalManagedExcep
void xamarin_log_objectivec_exception (NSException *exception, MarshalObjectiveCExceptionMode mode);

id xamarin_invoke_objc_method_implementation (id self, SEL sel, IMP xamarin_impl);
BOOL xamarin_invoke_objc_method_implementation_BOOL (id self, SEL sel, IMP xamarin_impl);
MonoType * xamarin_get_nsnumber_type ();
MonoType * xamarin_get_nsvalue_type ();
MonoClass * xamarin_get_inativeobject_class ();
Expand Down
1 change: 1 addition & 0 deletions runtime/xamarin/trampolines.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ void xamarin_stret_trampoline (void *buffer, id self, SEL sel, ...);
float xamarin_fpret_single_trampoline (id self, SEL sel, ...);
double xamarin_fpret_double_trampoline (id self, SEL sel, ...);
void xamarin_release_trampoline (id self, SEL sel);
BOOL xamarin_retainWeakReference_trampoline (id self, SEL sel);
void xamarin_calayer_release_trampoline (id self, SEL sel);
id xamarin_retain_trampoline (id self, SEL sel);
void xamarin_dealloc_trampoline (id self, SEL sel);
Expand Down
3 changes: 3 additions & 0 deletions src/ObjCRuntime/DynamicRegistrar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,9 @@ bool RegisterMethod (ObjCMethod method)
case Trampoline.SetFlags:
tramp = Method.SetFlagsTrampoline;
break;
case Trampoline.RetainWeakReference:
tramp = Method.RetainWeakReferenceTrampoline;
break;
default:
throw ErrorHelper.CreateError (4144, "Cannot register the method '{0}.{1}' since it does not have an associated trampoline. Please file a bug report at https://github.com/dotnet/macios/issues/new", method.DeclaringType.Type.FullName, method.Name);
}
Expand Down
4 changes: 4 additions & 0 deletions src/ObjCRuntime/Method.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ internal unsafe static IntPtr GetFlagsTrampoline {
internal unsafe static IntPtr SetFlagsTrampoline {
get { return Runtime.options->Trampolines->set_flags_tramp; }
}

internal unsafe static IntPtr RetainWeakReferenceTrampoline {
get { return Runtime.options->Trampolines->retainWeakReference_tramp; }
}
#endif // !COREBUILD
}
}
53 changes: 33 additions & 20 deletions src/ObjCRuntime/Registrar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ public override bool IsImplicit {
case Trampoline.SetGCHandle:
case Trampoline.GetFlags:
case Trampoline.SetFlags:
case Trampoline.RetainWeakReference:
return true;
default:
return false;
Expand Down Expand Up @@ -2115,6 +2116,13 @@ ObjCType RegisterTypeUnsafe (TType type, ref List<Exception> exceptions)
Signature = "v@:i",
IsStatic = false,
}, ref exceptions);

objcType.Add (new ObjCMethod (this, objcType, null) {
Selector = "retainWeakReference",
Trampoline = Trampoline.RetainWeakReference,
Signature = $"{GetBoolEncoding ()}@:",
IsStatic = false,
}, ref exceptions);
}

// Find conform_to_protocol
Expand Down Expand Up @@ -2650,6 +2658,29 @@ protected string GetExportedTypeName (TType type)
return GetExportedTypeName (type, GetRegisterAttribute (type));
}

string GetBoolEncoding ()
{
// map managed 'bool' to ObjC BOOL = 'unsigned char' in OSX and 32bit iOS architectures and 'bool' in 64bit iOS architectures
#if MTOUCH || MMP || BUNDLER
switch (App.Platform) {
case ApplePlatform.iOS:
case ApplePlatform.TVOS:
return "B";
case ApplePlatform.MacOSX:
case ApplePlatform.MacCatalyst:
return IsARM64 ? "B" : "c";
default:
throw ErrorHelper.CreateError (71, Errors.MX0071, App.Platform, App.ProductName);
}
#else
#if MONOMAC || __MACCATALYST__
return IsARM64 ? "B" : "c";
#else
return "B";
#endif
#endif
}

protected string ToSignature (TType type, ObjCMember member, ref bool success, bool forProperty = false)
{
bool isNativeEnum;
Expand All @@ -2670,26 +2701,7 @@ protected string ToSignature (TType type, ObjCMember member, ref bool success, b
case "System.UInt64": return "Q";
case "System.Single": return "f";
case "System.Double": return "d";
case "System.Boolean":
// map managed 'bool' to ObjC BOOL = 'unsigned char' in OSX and 32bit iOS architectures and 'bool' in 64bit iOS architectures
#if MTOUCH || MMP || BUNDLER
switch (App.Platform) {
case ApplePlatform.iOS:
case ApplePlatform.TVOS:
return "B";
case ApplePlatform.MacOSX:
case ApplePlatform.MacCatalyst:
return IsARM64 ? "B" : "c";
default:
throw ErrorHelper.CreateError (71, Errors.MX0071, App.Platform, App.ProductName);
}
#else
#if MONOMAC || __MACCATALYST__
return IsARM64 ? "B" : "c";
#else
return "B";
#endif
#endif
case "System.Boolean": return GetBoolEncoding ();
case "System.Void": return "v";
case "System.String":
return forProperty ? "@\"NSString\"" : "@";
Expand Down Expand Up @@ -2845,5 +2857,6 @@ enum Trampoline {
SetGCHandle,
GetFlags,
SetFlags,
RetainWeakReference,
}
}
1 change: 1 addition & 0 deletions src/ObjCRuntime/Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ internal struct Trampolines {
public IntPtr set_gchandle_tramp;
public IntPtr get_flags_tramp;
public IntPtr set_flags_tramp;
public IntPtr retainWeakReference_tramp;
}
#pragma warning restore 649

Expand Down
13 changes: 13 additions & 0 deletions tools/common/StaticRegistrar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2661,6 +2661,8 @@ string GetObjCSignature (ObjCMethod method, List<Exception> exceptions)
return "-(bool) xamarinSetGCHandle: (GCHandle) gchandle flags: (enum XamarinGCHandleFlags) flags";
else if (method.CurrentTrampoline == Trampoline.CopyWithZone1 || method.CurrentTrampoline == Trampoline.CopyWithZone2)
return "-(id) copyWithZone: (NSZone *)zone";
else if (method.CurrentTrampoline == Trampoline.RetainWeakReference)
return "-(BOOL) retainWeakReference";

var sb = new StringBuilder ();
var isCtor = method.CurrentTrampoline == Trampoline.Constructor;
Expand Down Expand Up @@ -3477,6 +3479,13 @@ bool SpecializeTrampoline (AutoIndentStringBuilder sb, ObjCMethod method, List<E
sb.AppendLine ("return xamarin_copyWithZone_trampoline2 (self, _cmd, zone);");
sb.AppendLine ("}");
return true;
case Trampoline.RetainWeakReference:
sb.WriteLine ("-(BOOL) retainWeakReference");
sb.WriteLine ("{");
sb.WriteLine ("\treturn xamarin_retainWeakReference_trampoline (self, _cmd);");
sb.WriteLine ("}");
sb.WriteLine ();
return true;
}

var customConformsToProtocol = method.Selector == "conformsToProtocol:" && method.Method.DeclaringType.Is ("Foundation", "NSObject") && method.Method.Name == "InvokeConformsToProtocol" && method.Parameters.Length == 1;
Expand Down Expand Up @@ -3536,6 +3545,10 @@ bool TryGetReturnType (ObjCMethod method, string descriptiveMethodName, List<Exc
rettype = ToSimpleObjCParameterType (method.NativeReturnType, descriptiveMethodName, exceptions, method.Method);
return true;
}
case Trampoline.RetainWeakReference:
rettype = "BOOL";
isCtor = false;
return true;
case Trampoline.Constructor:
rettype = "id";
isCtor = true;
Expand Down