gpt4 book ai didi

c - mmap 导致堆栈损坏,涉及内核?

转载 作者:太空狗 更新时间:2023-10-29 11:44:38 25 4
gpt4 key购买 nike

这段代码出现段错误:

#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>

#define CHUNKSIZE 4096

int main(int argc, char **argv) {
printf("Hallo!\n"); // does not segfault without this line

void* first_chunk = mmap(NULL, CHUNKSIZE, PROT_NONE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
void* next_chunk_addr = (void*) ((char*)first_chunk + CHUNKSIZE);
mmap(next_chunk_addr, CHUNKSIZE, PROT_NONE, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, 0, 0);

printf("Bumm!\n"); // segfaults
}

即使第二个 mmap 调用的地址无效,我相信我应该得到 MAP_FAILED 而不是损坏的堆栈。

GDB 给我这个:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a94104 in _IO_file_xsputn () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) bt
#0 0x00007ffff7a94104 in _IO_file_xsputn () from /lib/x86_64-linux-gnu/libc.so.6
#1 0x00007ffff7a8ad79 in puts () from /lib/x86_64-linux-gnu/libc.so.6
#2 0x0000000000400591 in main (argc=1, argv=0x7fffffffdf28) at test.cpp:14
(gdb) x/i $rip
=> 0x7ffff7a94104 <_IO_file_xsputn+324>: mov %dl,(%r8,%rax,1)

他为什么要尝试从 0x7ffff7ff8000 读取,这与他应该打印的内容无关?

在另一台机器上,我们得到了这个堆栈跟踪和相关代码:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b0985a in mmap64 () at ../sysdeps/unix/syscall-template.S:81
81 ../sysdeps/unix/syscall-template.S: No such file or directory.

这与内核端有关系吗?

这发生在三个不同的 Linux 系统上,使用 gcc 和 clang。在 OS X 下什么也不会发生。

最佳答案

内核的行为完全符合预期。请注意 mmap(2) documentation 中的这句话在 MAP_FIXED 上:

If the memory region specified by addr and len overlaps pages of any existing mapping(s), then the overlapped part of the existing mapping(s) will be discarded.

如果你做 strace(1)该程序的一部分,您会看到正在发生的事情:

...
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0710755000
write(1, "Hallo!\n", 7) = 7
mmap(NULL, 4096, PROT_NONE, MAP_SHARED|MAP_ANONYMOUS, 0, 0) = 0x7f0710754000
mmap(0x7f0710755000, 4096, PROT_NONE, MAP_SHARED|MAP_FIXED|MAP_ANONYMOUS, 0, 0) = 0x7f0710755000
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV (core dumped) +++

printf() 的第一次调用(如您所见,编译器已将其优化为对 puts() 的调用)使用 malloc 分配了一些内存()(因为 stdout 被缓冲),调用 mmap()。然后,程序调用 mmap(NULL) 并获取 紧接 printf 分配的内存之前的页面。第二次调用 mmap() 会在已经分配的页面之上分配一个新页面,将其清零并破坏 malloc 的内部数据结构。随后对 printf()(实际上是 puts())的调用在访问那些损坏的数据结构时崩溃,因为它试图追加到它认为已分配的内存缓冲区。

关于c - mmap 导致堆栈损坏,涉及内核?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24470834/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com