从递归学习 function call
- infinite.c
int func() { static int count = 0; return ++count && func();}int main() { return func();}
用 GDB 执行和测试,记得加上 -g:
$ gcc -o infinite infinite.c -g$ gdb -q infiniteReading symbols from infinite...done.(gdb) rStarting program: /tmp/infiniteProgram received signal SIGSEGV, Segmentation fault.0x00000000004004f8 in func () at infinite.c:33 return ++count && func();(gdb) p count$1 = 524032
如果将infinite.c 改为以下,重复上述动作:
int func(int x) { static int count = 0; return ++count && func(x++);}int main() { return func(0);}
将得到:
Program received signal SIGSEGV, Segmentation fault.0x0000000000400505 in func (x=1) at infinite.c:33 return ++count && func(x++);(gdb) p count$1 = 262016
继续修改 infinite.c 為以下,重复上述动作:
int func(int x) { static int count = 0; int y = x; // local var return ++count && func(x++);}int main() { return func(0);}
将得到以下:
Program received signal SIGSEGV, Segmentation fault.0x00000000004004de in func (x=) at infinite.c:11 int func(int x) {(gdb) p count$1 = 174677
stack 里面有 x (parameter), y (local variable), return address
- stack frame
观察UNIX Process 中的 stack 空间:
$ sudo cat /proc/1/maps | grep stack7fff7e13f000-7fff7e160000 rw-p 00000000 00:00 0 [stack]
60000Hex - 3f000Hex = 21000Hex = 135168Dec
135168 * 4 = 540672
这跟前面的数字很接近!
- return address 很重要,不管有没有选上,都要有 退路
sp = stack pointer; stack register
(AMD x86_64) A stack frame’s best friends are the two registers rsp and rbp, called the “stack pointer” and the “frame pointer”.
function prologue
function epilogue
(gdb) x /16gx $rsp
5.10. Borrow an
stack-based buffer overflow
- CVE-2015-7547
vulnerability in glibc’s DNS client-side resolver that is used to translate human-readable domain names, like google.com, into a network IP address. [读者可以网上自行搜索了解]
- Buffer Overflow : Example of Using GDB to Check Stack Memory(非常好的PPT文档)
准备 gdb-example.c,其內容为
#include void foo(char *input) { int a1 = 11; int a2 = 22; char buf[7]; strcpy(buf, input);}void main(int argc, char **argv) { foo(argv[1]);}
编译,记得加上 -g 和 -m32
用 i686 架构执行 GDB:
$ setarch i686 -R gdb -q ./gdb-example(gdb) break 6Breakpoint 1 at 0x804847a: file gdb-example.c, line 6.(gdb) run “whatever”Starting program: /tmp/gdb-example "whatever"Breakpoint 1, foo (input=0xffffd406 "whatever") at gdb-example.c:66 strcpy(buf, input);
观察 stack 內容:
(gdb) info frameStack level 0, frame at 0xffffd180:eip = 0x8048490 in foo (gdb-example.c:6); saved eip = 0x80484dacalled by frame at 0xffffd1b0source language c.Arglist at 0xffffd178, args: input=0xffffd40c "whatever"Locals at 0xffffd178, Previous frame’s sp is 0xffffd180Saved registers:ebp at 0xffffd178, eip at 0xffffd17c(gdb) x &a10xffffd15c: 0x0000000b(gdb) x &a20xffffd160: 0x00000016(gdb) x buf0xffffd165: 0x44f7f9c0(gdb) x 0xffffd1600xffffd160: 0x00000016
藏在 Heap 里细节
free() 释放的是 pointer 指向位于 heap 的连续内存,而非 pointer 本身占有的内存(*ptr)。
举例來说:
#include int main() { int *p = (int *) malloc(1024); free(p); free(p); return 0;}
编译不會有错误,但运行时会失败:
*** Error in './free': double free or corruption (top):0x000000000067a010 ***
倘若改为以下:
#include int main() { int *p = (int *) malloc(1024); free(p); p = NULL; free(p); return 0;}
则会编译和执行都成功。
因此,为了防止对同一个 pointer 作 free() 两次的操作,而导致程序失败,free() 后应该设定为 NULL。
[ 思考] 为什么 glibc 可以侦测出上述程序的 “double free or corruption” 呢?
malloc / free
在 GNU/Linux 里观察 malloc
事先安装 gdb套件
$ sudo apt install gdb gdb-dbg
GDB 操作:
$ gdb -q `which gdb`Reading symbols from /usr/bin/gdb...(gdb) start...Temporary breakpoint 1, main (argc=1, argv=0x7fffffffe4c8) at ./gdb/gdb.c:25...(gdb) p ((double(*)())pow)(2.,3.)$1 = 8(gdb) call malloc_stats()Arena 0:system bytes = 135168in use bytes = 28000Total (incl. mmap):system bytes = 135168in use bytes = 28000max mmap regions = 0max mmap bytes = 0$2 = -168929728(gdb) call malloc_info(0, stdout)
glibc 提供了 malloc_stats() 和 malloc_info() 这两个函数,可显示 process 的 heap 信息
延伸阅读
- 如何实现一个 malloc(https://kb.cnblogs.com/page/512454/)
- c malloc/free 初探 (https://descent-incoming.blogspot.com/2015/06/c-mallocfree.html)
- 用 C 语言编写一个简单的垃圾回收器(https://blog.csdn.net/lxw907304340/article/details/44420119)
原文: Writing a Simple Garbage Collector in C
https://blog.csdn.net/lxw907304340/article/details/44420119
https://sourceware.org/gdb/onlinedocs/gdb/Target-Description-Format.html
malloc: first-fit => https://github.com/jserv/mini-arm-os/blob/master/07-Threads/malloc.c