| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566 |
- 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) ?? string.Empty;
- 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);
- });
-
- }
- }
|