57763

Wrapped function is only called from linked library when linking as -static

Edit: Made title a bit clearer.

I am trying to wrap glibc's __assert_fail and __assert_perror_fail functions with my own that log the messages using syslog.

I have verified that if I fail an assert my functions get called. The problem lies in libzmq's assertions. libzmq's assertions only invoke my wrapper functions when I build with -static.

<strong>NOTES</strong>

    <li>

    I patched libzmq to call __assert_* instead of fprintf(stderr, ...), and I have verified that it correctly calls __assert_*.

    </li> <li>

    I also patched libzmq to randomly have assertion failures from within the zmq_assert macros so that I can easily reproduce. If the patch is wanted, I will put it up.

    </li> </ul>

    Here is some test code

    #include <stdlib.h>
    #include <stdio.h>
    #include <assert.h>
    #include <errno.h>
    #include <string.h>
    #include <zmq.h>
    
    extern "C" void
    __wrap___assert_perror_fail(int __errnum, const char *__file,
                                unsigned int __line, const char *__function)
    {
            fprintf(stderr, "TESTING123:: %s:%u %s: Unexpected error: %s.\n",
                    __file, __line, __function, strerror(__errnum));
            abort();
    }
    
    extern "C" void
    __wrap___assert_fail(const char *__assertion, const char *__file,
                         unsigned int __line, const char *__function)
    {
            fprintf(stderr, "TESTING123:: %s:%u %s: Assertion '%s' failed.\n",
                    __file, __line, __function, __assertion);
            abort();
    }
    
    int main()
    {
    #ifdef DO_ASSERT
            assert(1 == 0);
    #endif
            void *ctx = zmq_init(0);
            void *req = zmq_socket(ctx, ZMQ_REQ);
            void *rep = zmq_socket(ctx, ZMQ_REQ);
            zmq_bind(rep, "inproc://inproc-1");
            zmq_connect(req, "inproc://inproc-1");
            unsigned long long c = 0;
            while (1) {
                    zmq_msg_t msg;
    
                    zmq_msg_init_size(&msg, 1024);
                    zmq_send(req, &msg, 0);
                    zmq_msg_close(&msg);
    
                    zmq_msg_init(&msg);
                    zmq_recv(rep, &msg, 0);
                    zmq_send(rep, &msg, 0);
                    zmq_msg_close(&msg);
    
                    zmq_msg_init(&msg);
                    zmq_recv(req, &msg, 0);
                    zmq_msg_close(&msg);
    
                    ++c;
                    if (c % 1000000 == 0) {
                            fprintf(stderr, "processed %llu messages\n", c);
                    }
            }
            return 0;
    }
    
    
    

    Which I build 4 ways with/without DO_ASSERT, dynamic/static

    $ g++ -DDO_ASSERT -o t-me-dyn t.cc -Wl,-wrap,__assert_fail -Wl,-wrap,__asser_perror_fail -lzmq -lpthread -luuid -lrt 
    $ g++ -static -DDO_ASSERT -o t-me-sta t.cc -Wl,-wrap,__assert_fail -Wl,-wrap,__asser_perror_fail -lzmq -lpthread -luuid -lrt 
    $ g++ -o t-zmq-dyn t.cc -Wl,-wrap,__assert_fail -Wl,-wrap,__asser_perror_fail -lzmq -lpthread -luuid -lrt 
    $ g++ -static -o t-zmq-sta t.cc -Wl,-wrap,__assert_fail -Wl,-wrap,__asser_perror_fail -lzmq -lpthread -luuid -lrt 
    /usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.1/../../../../lib/libzmq.a(libzmq_la-ip.o): In function 'zmq::resolve_ip_interface(sockaddr_storage*, unsigned int*, char const*)':
    (.text+0x49b): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
    
    
    

    And I get the following when running them

    $ for bin in t-{me,zmq}-{dyn,sta}; do echo ==== $bin ====; ./$bin; done
    ==== t-me-dyn ====
    TESTING123:: t.cc:29 int main(): Assertion '1 == 0' failed.
    Aborted
    ==== t-me-sta ====
    TESTING123:: t.cc:29 int main(): Assertion '1 == 0' failed.
    Aborted
    ==== t-zmq-dyn ====
    t-zmq-dyn: lb.cpp:142: int zmq::lb_t::send(zmq_msg_t*, int): Assertion 'rc == 0' failed.
    Aborted
    ==== t-zmq-sta ====
    TESTING123:: lb.cpp:142 int zmq::lb_t::send(zmq_msg_t*, int): Assertion 'rc == 0' failed.
    Aborted
    
    
    

    So what am I doing wrong? According to man ld

    If you link other code with this file using --wrap malloc, then all calls to "malloc" will call the function "__wrap_malloc" instead.

    which is not what I am seeing.

    Answer1:

    Your mental model of how --wrap linker option works is likely all wrong.

    It's quite simple really: when you are linking a particular ELF executable or shared library with --wrap foo, all the linker does is:

      <li>if it sees a reference to foo, it replaces it with a reference to __wrap_foo,</li> <li>if it sees a reference to __real_foo, it replaces with a reference to foo.</li> </ul>

      I repeat, that is all it does. In particular, since you have not relinked libzmq.so with --wrap, libzmq.so continues to call __assert_fail (i.e. no renaming whatsoever is happening inside libzmq.so).

      In order to interpose libc function, forget the --wrap.

      Instead, simply define a new __assert_fail in your main executable. When you do that, your definition will get called regardless of whether the call comes from the main executable, or from libzmq.so (or from anywhere else).

      If you don't want to call the version of __assert_fail from libc, you are done. If you do, you'll have to look it up dynamically (via dlsym).

Recommend

  • Does System.Timers.Timer terminates on aborting its working Thread?
  • Uncaught exception in a callback from a 3rd party static library
  • Is there a way to get puppeteer's waitUntil “networkidle” to only consider XHR (ajax) requests?
  • llvm reports error declared with incompatible types in different translation units
  • How to initialize const members of structs on the heap
  • Was my query successful?
  • Visual Studio debug assertion failed dialog unresonsive
  • Get raw packet data from Qt application
  • Is it possible to specify `panic = “abort”` for a specific target?
  • Running ffmpeg.exe through windows service fails to complete while dealing with large files
  • .NET Drag and drop ; Show dragged borders or image such as Windows do
  • Avoid throwing expectation_failure when expectation parser fails
  • Is it possible to specify `panic = “abort”` for a specific target?
  • Return value from system() when using SIGINT default handler
  • caught segfault error in R
  • ClearCase: Stop making baseline if there are checkouts
  • Is there an easy way to abort with status code 429?
  • Wrapped function is only called from linked library when linking as -static
  • Interfacing C++ with Rust - returning CString panics
  • C# controlling threads (resume/suspend)
  • Where to set LEIN_ROOT?
  • ActiveRecord: abort datetime parsing if value is invalid
  • Load in models dynamically in Laravel 5.1
  • R6010 abort() has been called
  • Try to load image with Highgui.imread (OpenCV + Android)
  • From an action, get a post variable, output to page, then halt execution
  • Kill unload function in JS?
  • Program doesn't stop after exception
  • Canceling async httpwebrequests
  • C++ std::set comparator
  • How to solve “undefined reference to function” error?
  • powershell Get-Counter -ComputerName parameter on Windows 7
  • How to read piped content in C?
  • std::remove_copy_if_ valgrind bytes in block are possibly lost in loss record
  • Appending Character to Character Array In C
  • Ajax calls do not work in IE unless you fiddle with security settings
  • AES padding and writing the ciphertext to a disk file
  • Convert array of 8 bytes to signed long in C++
  • Linker errors when using intrinsic function via function pointer
  • LevelDB C iterator