Linux 在Fedora 25上使用LD_预加载会导致分段错误
当我试图使用我很久以前写的库时,我发现了一个奇怪的行为。主要问题是,当程序在Fedora 25上执行并使用LD_PRELOAD链接到我的库时,系统会引发分段错误。我对我的旧图书馆做了一个小样本,以便于理解这个问题Linux 在Fedora 25上使用LD_预加载会导致分段错误,linux,gcc,glibc,ld-preload,Linux,Gcc,Glibc,Ld Preload,当我试图使用我很久以前写的库时,我发现了一个奇怪的行为。主要问题是,当程序在Fedora 25上执行并使用LD_PRELOAD链接到我的库时,系统会引发分段错误。我对我的旧图书馆做了一个小样本,以便于理解这个问题 #include <stdio.h> #include <stdlib.h> #include <malloc.h> extern void *__libc_malloc(size_t size); void *malloc(size_t siz
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
extern void *__libc_malloc(size_t size);
void *malloc(size_t size)
{
void *ptr = __libc_malloc(size);
fprintf(stdout, "Malloc(%d)->(%p)\n", (int) size, ptr);
return ptr;
}
程序执行如下:
LD_PRELOAD=./libtest.so ./progtest
我发现“fprintf”线路导致SEGFULT问题。因此,我将“stdout”文件描述符更改为“stderr”,问题就解决了
然后,我在另一台运行CentOS 7的机器上,使用“stdout”文件描述符作为“fprintf”的输出,测试了相同的代码,使用“stdout”和“stderr”在这两种情况下都运行良好
通过观察这些结果,我想知道我遗漏了什么,为什么会发生这种情况
Fedora 25上安装的GLibc和GCC版本:
GNU ld版本2.26.1-1.fc25
gcc(gcc)6.3.1 20161221(红帽6.3.1-1)
CentOS 7上安装的GLibc和GCC版本:
GNU ld版本2.25.1-22.base.el7
gcc(gcc)4.8.5 20150623(红帽4.8.5-11)
fprintf
本身在某些情况下可能需要使用malloc
。一个可能的原因是stderr
是无缓冲的,而stdout
是行缓冲的fprintf(stdout)
可能已经有一个缓冲区,或者它可能尝试分配一个缓冲区,最后调用您的malloc
,它再次调用fprintf
,但它不会重新进入同一文件*
您可以使用标志(如(C11))防止重新进入:
#包括
#包括
线程\u本地布尔内部\u malloc=false;
void*malloc(大小){
void*ptr=uuu libc_malloc(大小);
如果(!in_malloc){
内部_malloc=真;
fprintf(标准值,“Malloc(%zd)->(%p)\n)”,大小,ptr;
内部_malloc=假;
}
返回ptr;
}
另一种方法是放弃使用fprintf,而是将snprintf用于本地缓冲区,并调用write()输出由snprintf@nos这可能会奏效,尽管我仍然担心snprintf
可能涉及分配。
LD_PRELOAD=./libtest.so ./progtest
#include <stdbool.h>
#include <threads.h>
thread_local bool inside_malloc = false;
void *malloc(size_t size) {
void *ptr = __libc_malloc(size);
if (!inside_malloc) {
inside_malloc = true;
fprintf(stdout, "Malloc(%zd)->(%p)\n", size, ptr);
inside_malloc = false;
}
return ptr;
}