You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用AddressSanitizer时dlsym拦截引发DEADLYSIGNAL的问题排查与解决求助

AddressSanitizer时dlsym拦截引发DEADLYSIGNAL的问题排查与解决求助

我正在尝试通过LD_PRELOAD机制拦截dlsym调用,同时为了调试这个拦截库,我使用AddressSanitizer(ASAN)编译它。但目前遇到了行为不一致的问题:有时程序能正常运行,拦截功能符合预期;但有时会直接崩溃,抛出AddressSanitizer:DEADLYSIGNAL错误。

最小复现代码(crash_preload.c)

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef void* (*dlsym_t)(void*, const char*);
static dlsym_t real_dlsym = NULL;
static int in_dlsym = 0;
static bool moduleLoaded = false;

__attribute__((constructor)) static void onModuleLoad() {
    moduleLoaded = true;
}

static int numCalls = 0;

static void setup_real_dlsym() {
    // Try loading the specific symbol version from GLIBC
    real_dlsym = (dlsym_t)dlvsym(RTLD_NEXT, "dlsym", "GLIBC_2.2.5");
    if (!real_dlsym) {
        real_dlsym = (dlsym_t)dlvsym(RTLD_NEXT, "dlsym", "GLIBC_2.17");
    }
    if (!real_dlsym) {
        fprintf(stderr, "Failed to resolve dlsym from GLIBC_2.2.5 or GLIBC_2.17\n");
        exit(1);
    }
    // Call dlsym through the resolved symbol to get the unversioned one
    real_dlsym = (dlsym_t)real_dlsym(RTLD_NEXT, "dlsym");
    if (!real_dlsym) {
        fprintf(stderr, "Failed to resolve final dlsym via resolved dlsym\n");
        exit(1);
    }
}

void* dlsym(void* handle, const char* symbol) {
    numCalls++;
    if (!real_dlsym) {
        setup_real_dlsym();
    }
    if (in_dlsym || !real_dlsym) {
        return NULL; // prevent recursion
    }
    if (moduleLoaded) {
        printf("Intercepted dlsym: %s, numCalls: %d\n", symbol, numCalls);
    }
    in_dlsym = 1;
    void* result = real_dlsym(handle, symbol);
    in_dlsym = 0;
    return result;
}

构建与运行命令

gcc -fsanitize=address -fPIC -shared -o crash_preload.so crash_preload.c -ldl
LD_PRELOAD=/lib/x86_64-linux-gnu/libasan.so.6:`readlink -f crash_preload.so` python

问题详情与猜测

  • 不一致的行为:
    • 有时Python可以正常启动,dlsym拦截功能完全生效
    • 有时会立即崩溃,输出AddressSanitizer:DEADLYSIGNAL错误

我怀疑问题的根源在于:libasan会在我的拦截库的静态变量完成初始化之前就调用dlsym。这种情况下,堆内存可能还未完成初始化,dlsym内部的malloc调用会导致不可预测的内存损坏,最终触发未定义行为。

但我现在卡在了调试环节——崩溃发生在程序的早期初始化阶段,我无法在这个阶段轻松添加调试输出。想请教各位:

  • 有没有方法可以解决这个初始化顺序导致的问题?
  • 针对这种早期初始化阶段的崩溃,有什么有效的调试手段?

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 11:54:34