4

編集:タイトルを少し明確にしました。

__assert_failを使用してメッセージをログに記録する独自の glibcと__assert_perror_fail関数をラップしようとしていますsyslog

アサートに失敗すると、関数が呼び出されることを確認しました。問題は libzmq のアサーションにあります。libzmq のアサーションは、.NET でビルドした場合にのみラッパー関数を呼び出します-static

ノート

  • __assert_*の代わりに呼び出すように libzmq にパッチを適用fprintf(stderr, ...)し、正しく呼び出すことを確認しました__assert_*

  • また、簡単に再現できるように、zmq_assert マクロ内からランダムにアサーション エラーが発生するように libzmq にパッチを適用しました。パッチが欲しいなら、私はそれを上げます。

ここにいくつかのテストコードがあります

#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;
}

DO_ASSERT、動的/静的の有無にかかわらず、私は4つの方法を構築します

$ 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

そして、それらを実行すると次のようになります

$ 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

それで、私は何を間違っていますか?によるとman ld

--wrap malloc を使用して他のコードをこのファイルにリンクすると、"malloc" へのすべての呼び出しで代わりに関数 "__wrap_malloc" が呼び出されます。

これは私が見ているものではありません。

4

1 に答える 1

2

--wrapリンカー オプションがどのように機能するかについてのあなたのメンタル モデルは、すべて間違っている可能性があります。

本当に簡単です。特定の ELF 実行可能ファイルまたは共有ライブラリを とリンクする場合--wrap fooリンカーは次のことを行います。

  • への参照が見つかった場合、それを へfooの参照に置き換えます__wrap_foo
  • への参照がある場合は、への参照__real_fooに置き換えますfoo

繰り返しますが、それだけです。特に、 と再リンクlibzmq.soしていないため--wraplibzmq.soは引き続き呼び出します__assert_fail(つまり、 内で名前の変更はまったく行われませんlibzmq.so)。

libc関数を挿入するには、 --wrap.

代わりに、メインの実行可能ファイルでnewを定義するだけです。__assert_failこれを行うと、呼び出しがメインの実行可能ファイルからのものであるか、または他の場所からのものであるかに関係なく、定義が呼び出されますlibzmq.so

__assert_failのバージョンをlibc から呼び出したくない場合は、これで完了です。その場合は、( 経由でdlsym) 動的に検索する必要があります。

于 2012-10-07T04:04:12.513 に答える