在 Fedora 25 上使用 LD_PRELOAD 导致分段错误
Using LD_PRELOAD on Fedora 25 causes Segmentation Fault
我在尝试使用很久以前编写的库时发现了一个奇怪的行为。主要问题是,当程序在 Fedora 25 上执行并使用 LD_PRELOAD 链接到我的库时,系统会引发分段错误。我对我的旧库做了一个小样本,以便轻松理解这个问题。
#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;
}
这段代码是使用这些参数编译的:
gcc -c -fPIC -O3 -Wall -o libtest.o libtest.c
gcc -shared -o libtest.so libtest.o
程序执行如下:
LD_PRELOAD=./libtest.so ./progtest
我发现“fprintf”行导致了段错误问题。所以我将“stdout”文件描述符更改为“stderr”,问题就消失了。
然后我在另一台机器上使用“stdout”文件描述符作为“fprintf”的输出测试了相同的代码运行 CentOS 7,并且在使用“stdout”和“stderr”的两种情况下都运行良好.
通过观察这些结果,我想知道我遗漏了什么以及为什么会这样。
Fedora 25 上安装的 GLibc 和 GCC 版本:
GNU ld version 2.26.1-1.fc25
gcc (GCC) 6.3.1 20161221 (Red Hat 6.3.1-1)
CentOS 7 上安装的 GLibc 和 GCC 版本:
GNU ld version 2.25.1-22.base.el7
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-11)
fprintf
本身在某些情况下可能需要使用malloc
。一个可能的原因是 stderr
是无缓冲的,而 stdout
是行缓冲的。 fprintf(stdout)
可能已经有一个缓冲区,或者它可能会尝试分配一个缓冲区,最终调用你的 malloc
,它再次调用 fprintf
,但它不能在同一个 FILE*
.
您可以使用标志防止重新进入,例如 (C11):
#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;
}
我在尝试使用很久以前编写的库时发现了一个奇怪的行为。主要问题是,当程序在 Fedora 25 上执行并使用 LD_PRELOAD 链接到我的库时,系统会引发分段错误。我对我的旧库做了一个小样本,以便轻松理解这个问题。
#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;
}
这段代码是使用这些参数编译的:
gcc -c -fPIC -O3 -Wall -o libtest.o libtest.c
gcc -shared -o libtest.so libtest.o
程序执行如下:
LD_PRELOAD=./libtest.so ./progtest
我发现“fprintf”行导致了段错误问题。所以我将“stdout”文件描述符更改为“stderr”,问题就消失了。
然后我在另一台机器上使用“stdout”文件描述符作为“fprintf”的输出测试了相同的代码运行 CentOS 7,并且在使用“stdout”和“stderr”的两种情况下都运行良好.
通过观察这些结果,我想知道我遗漏了什么以及为什么会这样。
Fedora 25 上安装的 GLibc 和 GCC 版本:
GNU ld version 2.26.1-1.fc25
gcc (GCC) 6.3.1 20161221 (Red Hat 6.3.1-1)
CentOS 7 上安装的 GLibc 和 GCC 版本:
GNU ld version 2.25.1-22.base.el7
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-11)
fprintf
本身在某些情况下可能需要使用malloc
。一个可能的原因是 stderr
是无缓冲的,而 stdout
是行缓冲的。 fprintf(stdout)
可能已经有一个缓冲区,或者它可能会尝试分配一个缓冲区,最终调用你的 malloc
,它再次调用 fprintf
,但它不能在同一个 FILE*
.
您可以使用标志防止重新进入,例如 (C11):
#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;
}