[runtime] Throw a managed exception instead of trying to call a null function pointer if the runtime tries to call a function that has been linked away. (#4770)

* [runtime] Throw a managed exception instead of trying to call a null function pointer if the runtime tries to call a function that has been linked away.

* [tests] Add new file for Xamarin.Mac tests.

* Direct people to file issues in github.
This commit is contained in:
Rolf Bjarne Kvinge 2018-09-10 10:56:02 +02:00 коммит произвёл GitHub
Родитель 72c3b33284
Коммит 385592b128
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
10 изменённых файлов: 106 добавлений и 5 удалений

Просмотреть файл

@ -522,3 +522,8 @@ There are a few reasons this may happen:
* It could be a bug in Xamarin.Mac. If this is the case, please file a bug at
[https://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=Xamarin.Mac).
### <a name="MM8028"/>MM8028: The runtime function {function} has been linked away.
This usually indicates a bug in Xamarin.Mac, because runtime functions should
not be linked away if they're needed. Please [submit an issue](https://github.com/xamarin/xamarin-macios/wiki/Submitting-Bugs-&-Suggestions).

Просмотреть файл

@ -2541,3 +2541,8 @@ There are a few reasons this may happen:
* It could be a bug in Xamarin.iOS. If this is the case, please file a bug at
[https://bugzilla.xamarin.com](https://bugzilla.xamarin.com/enter_bug.cgi?product=iOS).
### <a name="MT8028"/>MT8028: The runtime function {function} has been linked away.
This usually indicates a bug in Xamarin.iOS, because runtime functions should
not be linked away if they're needed. Please [submit an issue](https://github.com/xamarin/xamarin-macios/wiki/Submitting-Bugs-&-Suggestions).

Просмотреть файл

@ -27,10 +27,24 @@ struct Delegates {
static struct Delegates delegates = { 0 };
static guint32
create_linked_away_exception (const char *func)
{
char *msg = xamarin_strdup_printf ("The runtime function %s has been linked away.", func);
guint32 gchandle = xamarin_create_product_exception (8028, msg);
xamarin_free (msg);
return gchandle;
}
<# foreach (var d in delegates) { #>
<#= d.CReturnType #>
<#= d.EntryPoint #> (<#= d.CArgumentSignature #>)
{
<#if (d.ExceptionHandling && d.OnlyDynamicUsage) {#>if (delegates.<#= d.EntryPoint.Substring ("xamarin_".Length) #> == NULL) {
*exception_gchandle = create_linked_away_exception ("<#= d.EntryPoint.Substring ("xamarin_".Length) #>");
return<# if (d.CReturnType != "void") { #> (<#= d.CReturnType #>) 0<# } #>;
}
<#}#>
<# if (d.CReturnType != "void") { #>return <# } #>delegates.<#= d.EntryPoint.Substring ("xamarin_".Length) #> (<#= d.CArgumentNames #>);
}

Просмотреть файл

@ -2424,14 +2424,18 @@ xamarin_process_managed_exception (MonoObject *exception)
void
xamarin_throw_product_exception (int code, const char *message)
{
xamarin_process_managed_exception_gchandle (xamarin_create_product_exception (code, message));
}
guint32
xamarin_create_product_exception (int code, const char *message)
{
guint32 exception_gchandle = 0;
guint32 handle = xamarin_create_product_exception_for_error (code, message, &exception_gchandle);
if (exception_gchandle != 0) {
xamarin_process_managed_exception_gchandle (exception_gchandle);
} else {
xamarin_process_managed_exception_gchandle (handle);
}
if (exception_gchandle != 0)
return exception_gchandle;
return handle;
}
void

Просмотреть файл

@ -233,6 +233,7 @@ void xamarin_process_nsexception_using_mode (NSException *ns_exception, bool t
void xamarin_process_managed_exception (MonoObject *exc);
void xamarin_process_managed_exception_gchandle (guint32 gchandle);
void xamarin_throw_product_exception (int code, const char *message);
guint32 xamarin_create_product_exception (int code, const char *message);
NSString * xamarin_print_all_exceptions (MonoObject *exc);
id xamarin_invoke_objc_method_implementation (id self, SEL sel, IMP xamarin_impl);

Просмотреть файл

@ -0,0 +1,16 @@
using System;
using System.Runtime.InteropServices;
namespace ObjCRuntime {
public static class Messaging {
internal const string LIBOBJC_DYLIB = "/usr/lib/libobjc.dylib";
public struct objc_super {
public IntPtr Handle;
public IntPtr SuperHandle;
}
[DllImport (LIBOBJC_DYLIB, EntryPoint = "objc_msgSend")]
public extern static void void_objc_msgSend_IntPtr_bool_bool (IntPtr receiver, IntPtr selector, IntPtr a, bool b, bool c);
}
}

Просмотреть файл

@ -245,5 +245,49 @@ namespace Xamarin.BindingTests
ObjCBlockTester.CallProtocolWithBlockReturnValue (pb, required, instance);
}
}
[Test]
[TestCase (true, true)]
[TestCase (true, false)]
[TestCase (false, true)]
[TestCase (false, false)]
public void LinkedAway (bool required, bool instance)
{
if (!(TestRuntime.IsLinkAll && TestRuntime.IsOptimizeAll))
Assert.Ignore ("This test is only applicable if optimized & linking all assemblies.");
using (var pb = new FakePropertyBlock ()) {
try {
Messaging.void_objc_msgSend_IntPtr_bool_bool (Class.GetHandle (typeof (ObjCBlockTester)), Selector.GetHandle ("setProtocolWithBlockProperties:required:instance:"), pb.Handle, required, instance);
Assert.Fail ("Expected an MT8028 error");
} catch (RuntimeException re) {
Assert.AreEqual (8028, re.Code, "Code");
Assert.AreEqual ("The runtime function get_block_wrapper_creator has been linked away.", re.Message, "Message");
}
}
}
// Each method here will show a warning like this:
// MT4174: Unable to locate the block to delegate conversion method for the method ...
// This is expected.
// This is 'fake' because it doesn't implement the ProtocolWithBlockProperties protocol,
// which means that XI won't be able to find the delegate<->block conversion methods
// (either at runtime or build time).
// The point of this test is to ensure that we don't crash when the runtime tries
// to find those conversion methods, and instead finds that many required functions
// have been linked away (which happen when _forcing_ the dynamic registrar to be linked away).
public class FakePropertyBlock : NSObject {
[Export ("myOptionalProperty")]
public SimpleCallback MyOptionalProperty { get; set; }
[Export ("myRequiredProperty")]
public SimpleCallback MyRequiredProperty { get; set; }
[Export ("myOptionalStaticProperty")]
public static SimpleCallback MyOptionalStaticProperty { get; set; }
[Export ("myRequiredStaticProperty")]
public static SimpleCallback MyRequiredStaticProperty { get; set; }
}
}
}

Просмотреть файл

@ -68,6 +68,7 @@
</Compile>
<Compile Include="RuntimeTest.cs" />
<Compile Include="CodeBehind.cs" />
<Compile Include="Messaging.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\tests\test-libraries\libtest.m">

Просмотреть файл

@ -80,6 +80,7 @@
</Compile>
<Compile Include="RuntimeTest.cs" />
<Compile Include="CodeBehind.cs" />
<Compile Include="Messaging.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\tests\test-libraries\libtest.m">

Просмотреть файл

@ -655,4 +655,14 @@ partial class TestRuntime
}
}
class LinkerSentinel { }
public static bool IsOptimizeAll {
get {
#if OPTIMIZEALL
return true;
#else
return false;
#endif
}
}
}