Skip to content

Commit e48d16c

Browse files
committedApr 27, 2023
[release/6.0.4xx-xcode14.3] [tests] Find a workaround for #xamarin/maccore@2668.
1. Mono changed dyld lookup to start looking in directories in NATIVE_DLL_SEARCH_DIRECTORIES before the actual given path, even when the given path is absolute [1]. 2. This turned out to break Mac Catalyst, because when a DllImport says a P/Invoke is in "/System/Library/Frameworks/SceneKit.framework/SceneKit", Mono would try loading by prefixing the directories in NATIVE_DLL_SEARCH_DIRECTORIES. We add the Contents/MonoBundle directory to NATIVE_DLL_SEARCH_DIRECTORIES, so Mono would try to load "/path/to/my.app/Contents/MonoBundle//System/Library/Frameworks/SceneKit.framework/SceneKit", and things would go wrong. 3. We found a workaround: add "/" to NATIVE_DLL_SEARCH_DIRECTORIES. This works on Ventura, but apparently not on older macOS version, because the actual path we pass to dlopen ends up being "///System/Library/Frameworks/SceneKit.framework/SceneKit" (note the three initial slashes instead of a single slash). 4. Add a second workaround, where we add a dll import resolver to load exactly the path we want to load. [1]: dotnet/runtime@5a1baeb [2]: dotnet/runtime#85255 Technical sidenote: Why trying to load "/path/to/my.app/Contents/MonoBundle//System/Library/Frameworks/SceneKit.framework/SceneKit" turned out so bad on Mac Catalyst is not obvious. What happens is this: * The app calls 'dlopen ("/path/to/my.app/Contents/MonoBundle//System/Library/Frameworks/SceneKit.framework/SceneKit")' * dlopen checks if this is a Mac Catalyst override of a macOS system framework, by prefixing "/System/iOSSupport" and trying to load that. So dlopen would try to load "/System/iOSSupport/path/to/my.app/Contents/MonoBundle//System/Library/Frameworks/SceneKit.framework/SceneKit", which would obviously fail. * Then dlopen would try a few more fallbacks, eventually trying "/System/Library/Frameworks/SceneKit.framework/SceneKit", and successfully loading that library. * Unfortunately "/System/Library/Frameworks/SceneKit.framework/SceneKit" is the wrong library to load for Mac Catalyst ("/System/iOSSupport/System/Library/Frameworks/SceneKit.framework/SceneKit" is the correct version). These two libraries are incompatible, and calling one when you mean to call the other will do nasty things like corrupting the stack. This is a backport of dotnet#18159.
1 parent 0390600 commit e48d16c

File tree

1 file changed

+22
-0
lines changed

1 file changed

+22
-0
lines changed
 

‎tests/monotouch-test/AppDelegate.cs

+22
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System;
33
using System.Collections.Generic;
44
using System.Reflection;
5+
using System.Runtime.InteropServices;
56
using Foundation;
67
using UIKit;
78
using MonoTouch.NUnit.UI;
@@ -66,12 +67,33 @@ public override bool FinishedLaunching (UIApplication app, NSDictionary options)
6667

6768
static void Main (string[] args)
6869
{
70+
#if __MACCATALYST__
71+
NativeLibrary.SetDllImportResolver (typeof (NSObject).Assembly, DllImportResolver);
72+
NativeLibrary.SetDllImportResolver (typeof (AppDelegate).Assembly, DllImportResolver);
73+
#endif
6974
// Make sure we have at least one reference to the bindings project so that mcs doesn't strip the reference to it.
7075
GC.KeepAlive (typeof(Bindings.Test.UltimateMachine));
7176

7277
UIApplication.Main (args, null, typeof (AppDelegate));
7378
}
7479

80+
#if __MACCATALYST__
81+
// This is a workaround for a temporary issue in the .NET runtime
82+
// See https://github.com/xamarin/maccore/issues/2668
83+
// The issue is present in .NET 7.0.5, and will likely be fixed in .NET 7.0.6.
84+
static IntPtr DllImportResolver (string libraryName, global::System.Reflection.Assembly assembly, DllImportSearchPath? searchPath)
85+
{
86+
switch (libraryName) {
87+
case "/System/Library/Frameworks/SceneKit.framework/SceneKit":
88+
case "/System/Library/Frameworks/SceneKit.framework/Versions/A/SceneKit":
89+
var rv = NativeLibrary.Load (libraryName);
90+
Console.WriteLine ($"DllImportResolver callback loaded library \"{libraryName}\" from a P/Invoke in \"{assembly}\" => 0x{rv.ToString ("x")}");
91+
return rv;
92+
default:
93+
return IntPtr.Zero;
94+
}
95+
}
96+
#endif
7597
public static void PresentModalViewController (UIViewController vc, double duration)
7698
{
7799
var bckp = window.RootViewController;

0 commit comments

Comments
 (0)