rubyffi.so

How to unload or specify binary .so library with FFI::Library in ruby?


I have an ethon gem that loads the libcurl library in lines:

ffi_lib_flags :now, :global
ffi_lib ['ibcurl.so', 'libcurl.so.4']
extend Ethon::Curls::Functions # it attaches functions from libcurl

I make a monkey-patch

ffi_lib_flags :now, :global
ffi_lib '/home/myuser/libs/libcurl.so'
attach_function :easy_impersonate, :curl_easy_impersonate, [:pointer, :string, :int], :int # attach custom function from patched libcurl
extend Ethon::Curls::Functions # it attaches default functions from patched libcurl

FFI finds the curl_easy_impersonate function, but when I call it, I get a code 48 (in libcurl documentation it means that no such function was found).

However, if I replace the line directly in the gem ffi_lib ['libcurl.so', 'libcurl.so.4'] with ffi_lib '/home/myuser/libs/libcurl.so', calling this function returns 0 and it works as I want it to. I gather this is because FFI accesses the library loaded by the gem first.

QUESTION: Is there any way to unload this library with FFI, or explicitly specify which library to use for function calls?

P.S. I want to do it with monkey-patch, I don't want to fork the gem to change just one line, it will be inconvenient to support it in production.

Tried to remove attached methods, find libcurl library object with method ffi_libraries to remove, tried to find any trail of loaded libcurl, but couldn't find it.


Solution

  • I don't think the FFI library provides a way to unload a loaded library.

    If you need to "unload" a library, you will need to handle this outside of the FFI::Library itself. You could try restart your Ruby process.

    Or you could try this before your FFI bindings are loaded, you can set the LD_LIBRARY_PATH environment variable to specify the directory where your patched libcurl.so is located. This way alters the library search path used by the loader and allows your Ruby script to pick up the patched libcurl.so from the specified directory in LD_LIBRARY_PATH.