" /> " /> "/>

trans object of STL-class on interface which dynamicly load by dlopen

45 Views Asked by At

main.cpp

#include "string"
#include "unordered_map"
#include "iostream"

#include "dlfcn.h"

typedef void x(std::unordered_map<std::string, std::string> &);

int main(int argc, char **argv)
{
    auto handle = dlopen("./test3.so", RTLD_NOW);

    if(!handle)
    {
        std::cout << dlerror() << std::endl;
        return -1;
    }

    x *x;
    *(void **)&x = dlsym(handle, "x");

    // std::unordered_map<std::string, std::string> result{{"y", "Hello, cpp"}}; //ok
    std::unordered_map<std::string, std::string> result;    //failed if not dynamic link test3.so

    x(result);
    std::cout << result["x"] << std::endl;

    dlclose(handle);
    return 0;
}

test3.cpp

#include "unordered_map"
#include "string"
#ifdef __cplusplus
extern "C"
{
#endif
    void x(std::unordered_map<std::string, std::string> &result)
    {
        result["x"] = "Hello, world";
    }
#ifdef __cplusplus
}
#endif

if main.cpp build with gcc-11 while test3.cpp with gcc-4.8, the program would crash.

g++ -g -fpic -shared test3.cpp -o test3.so  //g++ version is 4.8
g++ -g main.cpp -ldl    //g++ version is 11
[zrar@CentOS7 cpp]$ ./a.out 
*** Error in `./a.out': munmap_chunk(): invalid pointer: 0x00007ffd3747f020 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x7340f)[0x7f2d328b340f]
/lib64/libc.so.6(+0x78c7e)[0x7f2d328b8c7e]
./test3.so(_ZN9__gnu_cxx13new_allocatorIPNSt8__detail15_Hash_node_baseEE10deallocateEPS3_m+0x20)[0x7f2d3263d506]
./test3.so(_ZNSt10_HashtableISsSt4pairIKSsSsESaIS2_ENSt8__detail10_Select1stESt8equal_toISsESt4hashISsENS4_18_Mod_range_hashingENS4_20_Default_ranged_hashENS4_20_Prime_rehash_policyENS4_17_Hashtable_traitsILb1ELb0ELb1EEEE21_M_deallocate_bucketsEPPNS4_15_Hash_node_baseEm+0x4a)[0x7f2d3263d342]
./test3.so(_ZNSt10_HashtableISsSt4pairIKSsSsESaIS2_ENSt8__detail10_Select1stESt8equal_toISsESt4hashISsENS4_18_Mod_range_hashingENS4_20_Default_ranged_hashENS4_20_Prime_rehash_policyENS4_17_Hashtable_traitsILb1ELb0ELb1EEEE13_M_rehash_auxEmSt17integral_constantIbLb1EE+0x188)[0x7f2d3263d08a]
./test3.so(_ZNSt10_HashtableISsSt4pairIKSsSsESaIS2_ENSt8__detail10_Select1stESt8equal_toISsESt4hashISsENS4_18_Mod_range_hashingENS4_20_Default_ranged_hashENS4_20_Prime_rehash_policyENS4_17_Hashtable_traitsILb1ELb0ELb1EEEE9_M_rehashEmRKm+0x2b)[0x7f2d3263cb4f]
./test3.so(_ZNSt10_HashtableISsSt4pairIKSsSsESaIS2_ENSt8__detail10_Select1stESt8equal_toISsESt4hashISsENS4_18_Mod_range_hashingENS4_20_Default_ranged_hashENS4_20_Prime_rehash_policyENS4_17_Hashtable_traitsILb1ELb0ELb1EEEE21_M_insert_unique_nodeEmmPNS4_10_Hash_nodeIS2_Lb1EEE+0x85)[0x7f2d3263c7eb]
./test3.so(_ZNSt8__detail9_Map_baseISsSt4pairIKSsSsESaIS3_ENS_10_Select1stESt8equal_toISsESt4hashISsENS_18_Mod_range_hashingENS_20_Default_ranged_hashENS_20_Prime_rehash_policyENS_17_Hashtable_traitsILb1ELb0ELb1EEELb1EEixEOSs+0xc2)[0x7f2d3263c3b6]
./test3.so(_ZNSt13unordered_mapISsSsSt4hashISsESt8equal_toISsESaISt4pairIKSsSsEEEixEOSs+0x2e)[0x7f2d3263c2f2]
./test3.so(x+0x43)[0x7f2d3263c138]
./a.out[0x40279a]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7f2d32861ac5]
./a.out[0x402661]
======= Memory map: ========
00400000-00402000 r--p 00000000 fd:00 100685803                          /home/zrar/Documents/cpp/a.out
00402000-0040a000 r-xp 00002000 fd:00 100685803                          /home/zrar/Documents/cpp/a.out
0040a000-0040f000 r--p 0000a000 fd:00 100685803                          /home/zrar/Documents/cpp/a.out
0040f000-00410000 r--p 0000e000 fd:00 100685803                          /home/zrar/Documents/cpp/a.out
00410000-00411000 rw-p 0000f000 fd:00 100685803                          /home/zrar/Documents/cpp/a.out
00aa2000-00ac3000 rw-p 00000000 00:00 0                                  [heap]
7f2d32636000-7f2d3263f000 r-xp 00000000 fd:00 100685761                  /home/zrar/Documents/cpp/test3.so
7f2d3263f000-7f2d3283e000 ---p 00009000 fd:00 100685761                  /home/zrar/Documents/cpp/test3.so
7f2d3283e000-7f2d3283f000 r--p 00008000 fd:00 100685761                  /home/zrar/Documents/cpp/test3.so
7f2d3283f000-7f2d32840000 rw-p 00009000 fd:00 100685761                  /home/zrar/Documents/cpp/test3.so
7f2d32840000-7f2d329e2000 r-xp 00000000 fd:00 452646                     /usr/lib64/libc-2.18.so
7f2d329e2000-7f2d32be2000 ---p 001a2000 fd:00 452646                     /usr/lib64/libc-2.18.so
7f2d32be2000-7f2d32be6000 r--p 001a2000 fd:00 452646                     /usr/lib64/libc-2.18.so
7f2d32be6000-7f2d32be8000 rw-p 001a6000 fd:00 452646                     /usr/lib64/libc-2.18.so
7f2d32be8000-7f2d32bec000 rw-p 00000000 00:00 0 
7f2d32bec000-7f2d32c01000 r-xp 00000000 fd:00 1527643                    /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f2d32c01000-7f2d32e00000 ---p 00015000 fd:00 1527643                    /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f2d32e00000-7f2d32e01000 r--p 00014000 fd:00 1527643                    /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f2d32e01000-7f2d32e02000 rw-p 00015000 fd:00 1527643                    /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f2d32e02000-7f2d32f03000 r-xp 00000000 fd:00 1459                       /usr/lib64/libm-2.18.so
7f2d32f03000-7f2d33102000 ---p 00101000 fd:00 1459                       /usr/lib64/libm-2.18.so
7f2d33102000-7f2d33103000 r--p 00100000 fd:00 1459                       /usr/lib64/libm-2.18.so
7f2d33103000-7f2d33104000 rw-p 00101000 fd:00 1459                       /usr/lib64/libm-2.18.so
7f2d33104000-7f2d331ed000 r-xp 00000000 fd:00 18326                      /usr/lib64/libstdc++.so.6.0.19
7f2d331ed000-7f2d333ed000 ---p 000e9000 fd:00 18326                      /usr/lib64/libstdc++.so.6.0.19
7f2d333ed000-7f2d333f5000 r--p 000e9000 fd:00 18326                      /usr/lib64/libstdc++.so.6.0.19
7f2d333f5000-7f2d333f7000 rw-p 000f1000 fd:00 18326                      /usr/lib64/libstdc++.so.6.0.19
7f2d333f7000-7f2d3340c000 rw-p 00000000 00:00 0 
7f2d3340c000-7f2d3340e000 r-xp 00000000 fd:00 452582                     /usr/lib64/libdl-2.18.so
7f2d3340e000-7f2d3360e000 ---p 00002000 fd:00 452582                     /usr/lib64/libdl-2.18.so
7f2d3360e000-7f2d3360f000 r--p 00002000 fd:00 452582                     /usr/lib64/libdl-2.18.so
7f2d3360f000-7f2d33610000 rw-p 00003000 fd:00 452582                     /usr/lib64/libdl-2.18.so
7f2d33610000-7f2d33630000 r-xp 00000000 fd:00 230826                     /usr/lib64/ld-2.18.so
7f2d33812000-7f2d33818000 rw-p 00000000 00:00 0 
7f2d3382e000-7f2d33830000 rw-p 00000000 00:00 0 
7f2d33830000-7f2d33831000 r--p 00020000 fd:00 230826                     /usr/lib64/ld-2.18.so
7f2d33831000-7f2d33832000 rw-p 00021000 fd:00 230826                     /usr/lib64/ld-2.18.so
7f2d33832000-7f2d33833000 rw-p 00000000 00:00 0 
7ffd37461000-7ffd37482000 rw-p 00000000 00:00 0                          [stack]
7ffd375d0000-7ffd375d2000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted
[zrar@CentOS7 cpp]$ ldd a.out 
        linux-vdso.so.1 (0x00007ffc793ca000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007ff2ebd37000)
        libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007ff2eba2f000)
        libm.so.6 => /lib64/libm.so.6 (0x00007ff2eb72d000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007ff2eb517000)
        libc.so.6 => /lib64/libc.so.6 (0x00007ff2eb16b000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ff2ebf3b000)
[zrar@CentOS7 cpp]$ ldd test3.so
        linux-vdso.so.1 (0x00007ffeff7c6000)
        libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fb3c0764000)
        libm.so.6 => /lib64/libm.so.6 (0x00007fb3c0462000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fb3c024c000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fb3bfea0000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fb3c0c76000)

if main.cpp build with test3.so in linking list, the program would run normaly.

g++ -g -fpic -shared test3.cpp -o test3.so  //g++ version is 4.8
g++ -g main.cpp -Wl,-rpath,'$ORIGIN' -ldl test3.so    //g++ version is 11
[zrar@CentOS7 cpp]$ ./a.out 
Hello, world
[zrar@CentOS7 cpp]$ ldd ./a.out 
        linux-vdso.so.1 (0x00007ffea6bb9000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007fd670b7f000)
        test3.so => /home/zrar/Documents/cpp/test3.so (0x00007fd670975000)
        libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fd67066d000)
        libm.so.6 => /lib64/libm.so.6 (0x00007fd67036b000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fd670155000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fd66fda9000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fd670d83000)
[zrar@CentOS7 cpp]$ ldd test3.so
        linux-vdso.so.1 (0x00007ffc91596000)
        libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fc484378000)
        libm.so.6 => /lib64/libm.so.6 (0x00007fc484076000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fc483e60000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fc483ab4000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fc48488a000)

In my requirment, I want to dynamicly load a plugin(may be built with other-release gcc) and trans STL object directly(host and plugin are both written in cpp, and wrapping of class in c-style is a complexity work) in plugin interface.

2

There are 2 best solutions below

0
Employed Russian On

I do not have g++-4.8 handy, but chances are that if you compile the following code with g++-4.8 and g++-11, then run nm foo.o | grep Function, you will get different mangled name.

#include <unordered_map>
#include <string>
void Function(std::unordered_map<std::string, std::string>& result) {}

Using g++-11 I get this:

0000000000000000 T _Z8FunctionRSt13unordered_mapINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_St4hashIS5_ESt8equal_toIS5_ESaISt4pairIKS5_S5_EEE

If the function name is different between the two compilers, then this function is not ABI-compatible, and you can't do what you want.

By marking the function as extern "C" you've hidden this ABI incompatibility from the compiler, but if you lie to the compiler (sooner or later) it will get you.

(If the function name is the same, GCC developers made a mistake.)

wrapping of class in c-style is a complexity work) in plugin interface

Too bad. If the requirement is for different compilers (gcc-4.x and gcc-11.x are different compilers for all practical purposes) then there is no shortcut -- you must ensure ABI compatibility, and the only sure way to achieve that is to only transfer C structs across the interface.

0
tangle1990 On

Well, there is certain diffencence between dynamic-link and dynamic-load.

  1. if library is dynamic linked, the library could see symbol in main program
  2. if library is dynamic loaded, the library couldn't see symbol in main program unless the main program is built with option -export-dynamic.

In the former test

  • a.out dynamic load test3.so, a hash bucket is allocate with main program's function but deallocate with test3.so's function, so a.out will crash.
  • a.out dynamic load test3.so, hash bucket allocate and deallocate both are define in main program, so a.out is normal