Skip to content

Workaround for MacOS issue on Applie Silicon related to dynamic linking #268

@ekr1

Description

@ekr1

A mentioned in a previously closed comment section, there is an issue on Apple Silicon where, depending on which other gems are used, ruby-oci8 might crash with a SIGSEGV when initiating the connection to Oracle.

There is a workaround that solves the problem for my particular combination of gems, see the quote below. Also note that I had a test case where I was able to reproduce individual gems creating the problem - but after a later MacOS upgrade, I was not able to get it to run even with no other gems loaded at all (i.e. the issue already happened with the absolut minimum of "stuff" loaded by ruby and bundle themselves).

As mentioned there, I find it very hard to imagine how ruby-oci8 would prevent that problem from happening: the root cause lies squarly on the way the Oracle libraries are built. Neither can ruby-oci8 catch the SIGSEGV (ruby does not allow that), nor can it possibly detect whether some other dylib has already been bound to a function required by the Oracle dylibs. By the time ruby-oci8 is loaded, it might already be too late.

But maybe there is a way to inform the user about this issue in some way? Some gems output warnings or helpful notices like this during the bundle install when they are first downloaded/compiled. Maybe it would make sense to alert the user of this possible issue. Or heck, at the very least place a comment in the code near the line where it happens (oci8.rb:133) though that may be spurious - in theory it could happen with any call into the flat-namespaced Oracle libs.

I found some time to delve into this again. The issue can be worked around by using this command to instruct the MacOS dyld loader to load one of the Oracle libraries first, guaranteed:

export DYLD_INSERT_LIBRARIES=$OCI_DIR/libnnz.dylib

This goes into a rbenv exec hook like so (if you're using rbenv):

 ~$ cat .rbenv/rbenv.d/exec/fix_oci8.bash
echo "fix_oci8.bash: inserting DYLD_INSERT_LIBRARIES for Oracle"
export DYLD_INSERT_LIBRARIES=$OCI_DIR/libnnz.dylib

The script will then always automatically be sourced just before the final, actual ruby executable is invoked. It seems to work even with more convoluted commands like bundle exec rails cucumber which go through multiple layers of wrappers...

I assume the only way this can really go wrong is if there also is another library that tries to access the same symbols as the Oracle libs and also uses the flat-namespaces model instead of the 2-level variant. But, knock on wood, so far it does seem to work for my particular case.

Alas, I don't see how ruby-oci8 could integrate this as a fix itself - by the time ruby-oci8 is invoked, it is too late already, and SIGSEGV cannot be trapped by ruby code.

Originally posted by @ekr1 in #257

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions