mfc socket onreceive函数不被调用_你所不知道的C语言:函数调用篇(续)

从递归学习 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

66d19c86797b3eb022e4065606176b4d.png

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

5f7dbd474ca9846bbacf99bb120e8206.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值