Search code examples
c++opencvshared-librariesdynamic-linkingdynamic-loading

Reduce exported symbols of a third party library


I have code that works fine, but if I link my project to a third party lib libabc.so (source unavailable), then all of the sudden I get a segmentation fault.

I have a main that looks like this

#include <opencv2/imgcodecs.hpp>
#include "Abc.h"

int main(int argc, char **argv)
{
    Abc dummyAbc;
    auto img = cv::imread("dummy.png");
    cv::imwrite("123.png", img);
    return 0;
}

The CMakeList.txt is as follows

cmake_minimum_required(VERSION 3.1)
set(CMAKE_C_STANDARD 11)
find_package(OpenCV COMPONENTS core highgui imgcodecs)
include_directories(${OpenCV_INCLUDE_DIR})

add_executable(my_project Main.cpp)
target_link_libraries(my_project ${OpenCV_LIBRARIES} abc)

This compiles well, but segfault when running. If I remove the line

Abc dummyAbc;

then all works fine (i.e. there is no problem with missing file, or opencv).

If I inspect the stack of the segfault, I see that:

Thread 1 "my_project" received signal SIGSEGV, Segmentation fault.
0x00007fdea96836b3 in png_destroy_write_struct () from /usr/local/lib/libabc.so

where png_destroy_write_struct is being called by cv::imwrite.

Both libpng.so and libabc.so (!!) export png_destroy_write_struct it actually exports all of the libpng API (which I assume it was statically linked to?). I assume this is the problem? I do no want openCV to see whatever libabc.so exports... How can I do this?

I tried to use objcopy --prefix-symbols abc_ libabc.so but somehow it did not help, now the crash happens at abc_png_destroy_write_struct.


Solution

  • I assume this is the problem?

    Yes: that is very likely: libabc.so has statically linked (probably different version of) libpng, and introduces symbol conflict.

    I do no want openCV to see whatever libabc.so exports... How can I do this?

    You can't. You must contact libabc.so developer, and tell them to hide libpng symbols.

    The only other option (for single process execution) is to dynamically load libabc.so.

    This can be done via dlopen("liabc.so.", RTLD_LOCAL), and even that may not work (depending on exactly how libabc.so was linked) -- it may cause libabc.so to bind to your version of libpng, and crash.

    On Linux, you could also possibly use dlmopen(LM_ID_NEWLM, "libabc.so", ...) which will completely isolate libabc.so from the rest of your code, and may work if libabc.so was linked to include all of its dependencies (or you can bring them into the new loader namespace explicitly).

    Finally, as Eljay commented here, you could use inter-process communication and have a completely separate process load libabc.so. This will have much worse performance than using libabc.so directly, but is better than nothing.