Skip to content
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

[BUG] Regression: libHarfBuzzSharp.so uses symbols from the system libharfbuzz.so.0 which causes SIGSEGV #3038

Open
kekekeks opened this issue Oct 15, 2024 · 5 comments
Labels

Comments

@kekekeks
Copy link
Contributor

kekekeks commented Oct 15, 2024

This was previously fixed by #2247, however LibraryLoader is only used for netfx builds, net6.0 build doesn't contain it anymore.

As of the issue details, see the original PR

Repro:

Use GtkSharp and the following code:

class Program
{    
    static void Main(string[] args)
    {
        // Causes SIGSEGV
        Gtk.Application.Init();
        var font = new HarfBuzzSharp.Font(new Face((_, _) => null));
        font.TryGetGlyph(65, out _);

        Console.WriteLine("Survived");
    }
}
@kekekeks
Copy link
Contributor Author

I suspect that the proper solution would be to generate some wrappers with HBSharp_ prefix and mark the list of the symbols as private.

@kekekeks
Copy link
Contributor Author

Also, linking with -Bsymbolic could help too:

-Bsymbolic
  When creating a shared library, bind references to global symbols to the 
  definition within the shared library, if any. Normally, it is possible 
  for a program linked against a shared library to override the definition 
  within the shared library. 

  This option is only meaningful on ELF platforms which support shared libraries.

-Bsymbolic-functions
  When creating a shared library, bind references to global function symbols 
  to the definition within the shared library, if any.  

  This option is only meaningful on ELF platforms which support shared libraries.

@mattleibow
Copy link
Contributor

Are things different after the work in #2917 by @maxkatz6 ? Is there a way to control the imports in .NET so when we invoke it, the symbols are the ones we just have in the same binary vs some random one that was loaded by the process at some point before?

@kekekeks
Copy link
Contributor Author

It's not about the way the .NET or app itself resolve functions nor about the way they call those.

It's about native symbols being misresolved by the native linux shared library loader when it lazy-loads parts of libHarfBuzzSharp.so

Unlike PE files, ELF shared libraries were designed to emulate static libraries, so the naming space is process-global and it's possible to accidentally replace internally used symbols that are externally visible.

i. e. the following happens:

  1. libA.so exports Foo and Bar, Foo internally calls Bar.
  2. libB.so exports its own Bar and got loaded in a way that can provide Bar to other libraries
  3. Linux shared library loader overrides all calls to Bar in libA.so to use Bar from libB.so, even if libB.so was just exporting some random symbol with the same name, without asking libA.so or libB.so if they want that or not (remember, symbol name space is process global and symbols can come from any source).

It can even happen if libB.so was loaded after libA.so.

Yes, this is rather unexpected and surprising behavior, but the person who decided for it to work like that is probably not even alive today.

The previous workaround was passing RTLD_DEEPBIND to dlopen to override that behavior and to force all symbols from libHarfBuzzSharp that are used from libHarfBuzzSharp itself to always be resolved correctly.

Note, that the issue doesn't manifest itself in every scenario and provided repro requires GtkSharp specifically, because GtkSharp uses RTLD_GLOBAL flag when loading libgtk.so.3. It's not possible to workaround by loading libgtk.so.3 without that flag, because it will later be "upgraded" to RTLD_GLOBAL when GtkSharp would call dlopen. It's not limited, however, to GtkSharp and can happen with other library combinations.

The workaround I'm currently using is to load libHarfBuzzSharp.so with NativeLibrary API, extract the path to it via dlinfo+RTLD_DI_ORIGIN, unload, load again with RTLD_DEEPBIND and define native library resolver for libHarfBuzzSharp with custom dlopen. However that only works with glibc-based Linux systems.

There are two ways to solve this issue:

  1. link libHarfBuzzSharp with -Bsymbolic (needs checking)
  2. add a prefix to every single exported symbol so there won't be any possible name clashes.

@mattleibow
Copy link
Contributor

I see.

Are you able to build skia with -Bsymbolic and test?

Option 2 is a lot more work so hopefully option 1 works. I typically just exposed everything in the harfbuzz library via the generator, so it will be a lot to wrap.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants