A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

66 lines
2.6 KiB

using System.Runtime.InteropServices;
namespace XEmbedSample;
/*
This is needed specifically for GtkSharp:
https://github.com/mono/SkiaSharp/issues/3038
https://github.com/GtkSharp/GtkSharp/issues/443
Instead of using plain DllImport they are manually calling dlopen with RTLD_GLOBAL and RTLD_LAZY flags:
https://github.com/GtkSharp/GtkSharp/blob/b7303616129ab5a0ca64def45649ab522d83fa4a/Source/Libs/Shared/FuncLoader.cs#L80-L92
Which causes libHarfBuzzSharp.so from HarfBuzzSharp to resolve some of the symbols from the system libharfbuzz.so.0
which is a _different_ harfbuzz version.
That results in a segfault.
Previously there was a workaround - https://github.com/mono/SkiaSharp/pull/2247 but it got
disabled for .NET Core / .NET 5+.
Why linux linker builds shared libraries in a way that makes it possible for them to resolve their own symbols from
elsewhere escapes me.
Here we are loading libHarfBuzzSharp.so from the .NET-resolved location, saving it, unloading the library
and then defining a custom resolver that would call dlopen with RTLD_NOW + RTLD_DEEPBIND
*/
public unsafe class HarfbuzzWorkaround
{
[DllImport("libc")]
static extern int dlinfo(IntPtr handle, int request, IntPtr info);
[DllImport("libc")]
static extern IntPtr dlopen(string filename, int flags);
private const int RTLD_DI_ORIGIN = 6;
private const int RTLD_NOW = 2;
private const int RTLD_DEEPBIND = 8;
public static void Apply()
{
if (RuntimeInformation.RuntimeIdentifier.Contains("musl"))
throw new PlatformNotSupportedException("musl doesn't support RTLD_DEEPBIND");
var libraryPathBytes = Marshal.AllocHGlobal(4096);
var handle = NativeLibrary.Load("libHarfBuzzSharp", typeof(HarfBuzzSharp.Blob).Assembly, null);
dlinfo(handle, RTLD_DI_ORIGIN, libraryPathBytes);
var libraryOrigin = Marshal.PtrToStringUTF8(libraryPathBytes);
Marshal.FreeHGlobal(libraryPathBytes);
var libraryPath = Path.Combine(libraryOrigin, "libHarfBuzzSharp.so");
NativeLibrary.Free(handle);
var forceLoadedHandle = dlopen(libraryPath, RTLD_NOW | RTLD_DEEPBIND);
if (forceLoadedHandle == IntPtr.Zero)
throw new DllNotFoundException($"Unable to load {libraryPath} via dlopen");
NativeLibrary.SetDllImportResolver(typeof(HarfBuzzSharp.Blob).Assembly, (name, assembly, searchPath) =>
{
if (name.Contains("HarfBuzzSharp"))
return dlopen(libraryPath, RTLD_NOW | RTLD_DEEPBIND);
return NativeLibrary.Load(name, assembly, searchPath);
});
}
}