【问题标题】:Segmentation fault when calling backtrace() on Linux x86在 Linux x86 上调用 backtrace() 时出现分段错误
【发布时间】:2013-04-18 07:03:03
【问题描述】:

我正在尝试执行以下操作 - 为 pthreads 库编写一个包装器,该包装器将在它调用的每个 API 时记录一些信息。 我想记录的一条信息是堆栈跟踪。

以下是原始代码中可以按原样编译和运行的最小 sn-p。

初始化(文件libmutex.c):

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <dlfcn.h>

static int (*real_mutex_lock)(pthread_mutex_t *) __attribute__((__may_alias__));
static void *pthread_libhandle;

#ifdef _BIT64
#define PTHREAD_PATH      "/lib64/libpthread.so.0"
#else
#define PTHREAD_PATH      "/lib/libpthread.so.0"
#endif 

static inline void load_real_function(char* function_name, void** real_func) {
  char* msg;
  *(void**) (real_func) = dlsym(pthread_libhandle, function_name);
  msg = dlerror();
  if (msg != NULL)
    printf("init: real_%s load error %s\n", function_name, msg);
}

void __attribute__((constructor)) my_init(void) {
   printf("init: trying to dlopen '%s'\n", PTHREAD_PATH);
   pthread_libhandle = dlopen(PTHREAD_PATH, RTLD_LAZY);
   if (pthread_libhandle == NULL) {
     fprintf(stderr, "%s\n", dlerror());
     exit(EXIT_FAILURE);
  }
  load_real_function("pthread_mutex_lock", (void**) &real_mutex_lock);
}

包装器和对回溯的调用。 我已经尽可能多地从方法中删除了,所以是的,我知道我从不调用原始的 pthread_mutex_lock。

void my_backtrace(void) {
    #define SIZE 100
    void *buffer[SIZE];
    int nptrs;

    nptrs = backtrace(buffer, SIZE);
    printf("backtrace() returned %d addresses\n", nptrs);
}

int pthread_mutex_lock(pthread_mutex_t *mutex) {
  printf("In pthread_mutex_lock\n"); fflush(stdout);
  my_backtrace();
  return 0;
}

为了测试这个我使用这个二进制文件(文件tst_mutex.c):

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

int main (int argc, char *argv[]) {
  pthread_mutex_t x;

  printf("Before mutex\n"); fflush(stdout);
  pthread_mutex_lock(&x);
  printf("after  mutex\n");fflush(stdout);

  return 0;
}

这是所有这些的编译方式:

rm -f *.o *.so tst_mutex

cc -Wall -D_BIT64 -c -m64 -fPIC libmutex.c
cc -m64 -o libmutex.so -shared -fPIC -ldl -lpthread libmutex.o

cc -Wall -m64 tst_mutex.c  -o tst_mutex

然后运行

LD_PRELOAD=$(pwd)/libmutex.so ./tst_mutex

这会在 Linux x86 上因分段错误而崩溃。 在 Linux PPC 上,一切都完美无缺。 我尝试了几个版本的 GCC 编译器、GLIBC 库和 Linux 发行版 - 都失败了。

输出是

init: trying to dlopen '/lib64/libpthread.so.0'
Before mutex
In pthread_mutex_lock
In pthread_mutex_lock
In pthread_mutex_lock
...
...
./run.sh: line 1: 25023 Segmentation fault      LD_PRELOAD=$(pwd)/libmutex.so ./tst_mutex

建议这里有递归。 我查看了 backtrace() 的源代码 - 其中有 no 调用锁定机制。它所做的只是简单地遍历堆栈帧链表。 我也用 objdump 检查了库代码,但没有发现任何异常。

这里发生了什么? 任何解决方案/解决方法?

哦,也许是最重要的事情。这只发生在 pthread_mutex_lock 函数中!! 从任何其他重写的 pthread_* 函数打印堆栈都可以正常工作......

【问题讨论】:

  • 您尝试过 RTLD_NOW 吗?
  • 问题在于没有打开 pthreads 库。
  • 我尝试了您的步骤,但收到错误 ./tst_mutex: symbol lookup error: libmutex.so: undefined symbol: dlopen。我现在不打算解决这个问题,但重现问题的步骤中可能缺少某些东西。
  • 我猜backtrace 在内部某个地方调用pthread_mutex_lock,所以你最终会出现一个循环。当堆栈溢出时会发生段错误。为避免这种情况,您需要在挂钩时不要挂钩入口点。
  • @Gabriel:我已经编辑了这个问题。前两个代码段进入一个名为 libmutex.c 的文件 第三个代码段(测试)进入 tst_mutex.c #include 提供 dlopen 函数。

标签: linux gcc pthreads backtrace ld-preload


【解决方案1】:

这是一个堆栈溢出,由无限递归引起(正如@Chris Dodd 所说)。 backtrace() 函数运行不同的系统调用,这些系统调用是从使用 pthread 库编译的程序调用的,而没有使用 pthread 库。即使程序没有显式调用 pthread 函数。

这是一个简单的程序,它使用了 backtrace() 函数,没有使用任何 pthread 函数。

#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>

int main(void)
{
 void* buffer[100];
 int num_ret_addr;

 num_ret_addr=backtrace(buffer, 100); 
 printf("returned number of addr %d\n", num_ret_addr);

 return 0;
}

让我们在不链接到 pthread 的情况下编译它,并使用 strace 实用程序检查程序系统调用。输出中没有出现与互斥锁相关的系统调用。

$ gcc -o backtrace_no_thread backtrace.c
$ strace -o backtrace_no_thread.out backtrace_no_thread

不要编译将其链接到 pthread 库的相同代码,运行 strace 并查看其输出。

$ gcc -o backtrace_with_thread backtrace.c -lpthread
$ strace -o backtrace_with_thread.out backtrace_with_thread

这次输出包含与互斥锁相关的系统调用(它们的名称可能取决于平台)。这是在 X86 Linux 机器上获得的 strace 输出文件的片段。

futex(0x3240553f80, FUTEX_WAKE_PRIVATE, 2147483647) = 0
futex(0x324480d350, FUTEX_WAKE_PRIVATE, 2147483647) = 0

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-30
    • 1970-01-01
    • 2021-02-25
    • 1970-01-01
    • 2018-03-17
    • 2017-08-05
    • 2015-10-03
    • 2018-05-15
    相关资源
    最近更新 更多