提问人:zkh 提问时间:2/24/2023 最后编辑:Employed Russianzkh 更新时间:2/25/2023 访问量:106
使用 printf 在 malloc 中创建运行时存根时出现分段错误
Segmentation fault when making a runtime stub in malloc using printf
问:
我正在根据CSAPP一书的原理做一些关于动态库的实验,当我运行链接我的运行时存根库的程序时,我遇到了分段错误。
库如下。
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
// int data;
void *malloc(size_t size) {
void *(*mallocp)(size_t size);
char *error;
mallocp = (void*(*)(size_t))dlsym(RTLD_NEXT, "malloc");
if ((error = dlerror()) != NULL) {
fputs(error, stderr);
exit(1);
}
char *ptr = NULL;
ptr = (char*)mallocp(size);
// printf("malloc(%d) @ %p\n", (int)size, 0);
return ptr;
}
run 来编译它。
然后编译 main,它只是调用 malloc。 并运行可执行文件,然后在启动过程中出现分段错误。gcc -fpic -shared dynamic.cpp -ldl -o dynamic.so -g
gcc -g test.cpp
export LD_PRELOAD
注释掉 printf 后,它工作正常。 有人告诉我这是因为 printf 调用了 malloc。然后会发生什么?他们循环往复?那为什么是segmenattion的错误呢? 代码与书中几乎相同。我想这与我的 printf 的 gcc 的实现有关。 为了在我的库中使用 printf,我应该怎么做?
答:
注释掉 printf 后,它工作正常。有人告诉我这是因为 printf 调用了 malloc。
是的。
然后会发生什么?他们循环往复?
是的。
那为什么是segmenattion的错误呢?
因为你得到了无限的递归,这会导致(鼓声!堆栈溢出。
您的计算机没有无限堆栈。
P.S. 在 GDB 下运行二进制文件会很有启发性。
附注
export LD_PRELOAD
和。。。
这是一件相对危险的事情:以这种方式设置将影响(并导致崩溃)当前 shell 中的所有命令。LD_PRELOAD
最好只为下一个命令设置变量,如下所示:
$ env LD_PRELOAD=./dynamic.so ./a.out
如果使用和类似的 shell,你也可以做等效的:bash
$ LD_PRELOAD=./dynamic.so ./a.out
更新:
事实是,我使用了 gdb,它说 seg 错误发生在启动期间,而没有提供任何其他信息。
在处理像 这样的低级例程时,你需要有创造力。使用这个答案中的技巧,您可以毫不费力地弄清楚发生了什么。malloc
您还需要从外部连接 GDB -- 如果您在使用 GDB 命令之前进行设置,则会影响您的 shell。LD_PRELOAD
run
LD_PRELOAD
下面是一个示例:
$ cat dynamic.c
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
volatile int done = 0;
void *malloc(size_t size) {
void *(*mallocp)(size_t size);
char *error;
while (!done) { }
mallocp = (void*(*)(size_t))dlsym(RTLD_NEXT, "malloc");
if ((error = dlerror()) != NULL) {
fputs(error, stderr);
exit(1);
}
char *ptr = NULL;
ptr = (char*)mallocp(size);
printf("malloc(%d) @ %p\n", (int)size, 0);
return ptr;
}
$ gcc -g -fPIC -o dynamic.so dynamic.c
$ LD_PRELOAD=./dynamic.so ./a.out &
[1] 476197
$ gdb -p 476197
0x00007f52b5f5a156 in malloc (size=1) at dynamic.c:11
11 while (!done) { }
(gdb) bt
#0 0x00007f52b5f5a156 in malloc (size=1) at dynamic.c:11
#1 0x0000561590f6814b in main () at main.c:1
(gdb) set var done = 1
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00007f52b5ea7e2f in __GI__dl_catch_exception (exception=exception@entry=0x7ffc04e7d070, operate=0x7f52b5dde3b0 <dlsym_doit>, args=0x7ffc04e7d110) at ./elf/dl-error-skeleton.c:175
175 ./elf/dl-error-skeleton.c: No such file or directory.
(gdb) bt 20
#0 0x00007f52b5ea7e2f in __GI__dl_catch_exception (exception=exception@entry=0x7ffc04e7d070, operate=0x7f52b5dde3b0 <dlsym_doit>, args=0x7ffc04e7d110) at ./elf/dl-error-skeleton.c:175
#1 0x00007f52b5ea7f4f in __GI__dl_catch_error (objname=0x7ffc04e7d0c8, errstring=0x7ffc04e7d0d0, mallocedp=0x7ffc04e7d0c7, operate=<optimized out>, args=<optimized out>) at ./elf/dl-error-skeleton.c:227
#2 0x00007f52b5ddddc7 in _dlerror_run (operate=operate@entry=0x7f52b5dde3b0 <dlsym_doit>, args=args@entry=0x7ffc04e7d110) at ./dlfcn/dlerror.c:138
#3 0x00007f52b5dde455 in dlsym_implementation (dl_caller=<optimized out>, name=<optimized out>, handle=<optimized out>) at ./dlfcn/dlsym.c:54
#4 ___dlsym (handle=<optimized out>, name=<optimized out>) at ./dlfcn/dlsym.c:68
#5 0x00007f52b5f5a179 in malloc (size=1024) at dynamic.c:13
#6 0x00007f52b5dce76c in __GI__IO_file_doallocate (fp=0x7f52b5f2c760 <_IO_2_1_stdout_>) at ./libio/filedoalloc.c:101
#7 0x00007f52b5ddbf50 in __GI__IO_doallocbuf (fp=0x7f52b5f2c760 <_IO_2_1_stdout_>) at ./libio/libioP.h:947
#8 __GI__IO_doallocbuf (fp=fp@entry=0x7f52b5f2c760 <_IO_2_1_stdout_>) at ./libio/genops.c:342
#9 0x00007f52b5ddb318 in _IO_new_file_overflow (f=0x7f52b5f2c760 <_IO_2_1_stdout_>, ch=-1) at ./libio/fileops.c:744
#10 0x00007f52b5dda4de in _IO_new_file_xsputn (n=7, data=<optimized out>, f=0x7f52b5f2c760 <_IO_2_1_stdout_>) at ./libio/libioP.h:947
#11 _IO_new_file_xsputn (f=0x7f52b5f2c760 <_IO_2_1_stdout_>, data=<optimized out>, n=7) at ./libio/fileops.c:1196
#12 0x00007f52b5db53ae in outstring_func (done=0, length=7, string=<error reading variable: Cannot access memory at address 0x4e7d2e0>, s=0x7f52b5f2c760 <_IO_2_1_stdout_>) at ../libio/libioP.h:947
#13 __vfprintf_internal (s=0x7f52b5f2c760 <_IO_2_1_stdout_>, format=<error reading variable: Cannot access memory at address 0x4e7d2e0>, ap=ap@entry=0x7ffc04e7d820, ) at ./stdio-common/vfprintf-internal.c:767
#14 0x00007f52b5dab4fb in __printf (format=<optimized out>) at ./stdio-common/printf.c:33
#15 0x00007f52b5f5a1e8 in malloc (size=1024) at dynamic.c:21
#16 0x00007f52b5dce76c in __GI__IO_file_doallocate (fp=0x7f52b5f2c760 <_IO_2_1_stdout_>) at ./libio/filedoalloc.c:101
#17 0x00007f52b5ddbf50 in __GI__IO_doallocbuf (fp=0x7f52b5f2c760 <_IO_2_1_stdout_>) at ./libio/libioP.h:947
#18 __GI__IO_doallocbuf (fp=fp@entry=0x7f52b5f2c760 <_IO_2_1_stdout_>) at ./libio/genops.c:342
在这里你可以清楚地看到呼叫呼叫...malloc
printf
malloc
此时的堆栈有多深?
(gdb) bt -4
#42923 __vfprintf_internal (s=0x7f52b5f2c760 <_IO_2_1_stdout_>, format=<error reading variable: Cannot access memory at address 0x567a1c0>, ap=ap@entry=0x7ffc0567a700, ) at ./stdio-common/vfprintf-internal.c:767
#42924 0x00007f52b5dab4fb in __printf (format=<optimized out>) at ./stdio-common/printf.c:33
#42925 0x00007f52b5f5a1e8 in malloc (size=1) at dynamic.c:21
#42926 0x0000561590f6814b in main () at main.c:1
它有 42926 个级别深。
评论
LD_DEBUG
评论