gpt4 book ai didi

linux - mmap 成功但写入失败

转载 作者:太空宇宙 更新时间:2023-11-04 12:58:28 25 4
gpt4 key购买 nike

我有一个非常简单的代码来测试低内存地址上的 mmap。

  unsigned long *p = mmap ((void*)(4096*16), 4096, PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_GROWSDOWN, -1, 0);
fprintf (stderr, "p=0x%lx\n", (unsigned long)p);`
*p = 2554;
printf ("p=0x%lx; *p=%ld\n", (unsigned long)p, *p);

当我运行代码并得到以下输出时:

 p=0x10000
Segmentation fault (core dumped)

在 dmesg 日志中,我可以看到以下打印:

 segfault at 10000 ip 00000000004006cc sp 00007fff5845f4c0 error 6

总的来说,mmap似乎是成功的,但是写操作失败了。我无法解释这两个相互矛盾的观察结果。请帮我。谢谢。

最佳答案

如果您在 mmap 调用的 flags 参数中省略 MAP_GROWSDOWN,您可能会发现段错误不再发生。

如果在 mmap 调用之后检查 /proc/$PID/maps 文件,您可能会看到一个奇怪的地方(包括 MAP_GROWSDOWNflags 中)。该地址似乎比请求的地址高一页,并且该映射的大小似乎比您请求的小一页。简而言之,该映射的起始地址偏移了 4096 字节。我在 MAP_GROWSDOWN 的文档中没有发现这种奇怪的情况,对我来说它更像是一个错误而不是一个功能。您是否看到这种特殊情况可能取决于您使用的内核版本(我从标签中假设您使用的是 Linux 内核)。在任何情况下,在进程处于事件状态时检查该文件可能是有教育意义的,即使您的代码在没有 MAP_GROWSDOWN 的情况下按预期工作也是如此。

使进程保持事件状态足够长的时间以检查其 maps 文件的一种方法是在 gdb 中设置断点。调用 mmap 的函数中的任何地方都应该足够了,如果你走得足够远(刚刚通过 mmap 调用)。上述路径名中的$PID 旨在表示调用mmap 的进程的进程ID。您可以从合适的 ps 输出或 gdb 中的 info inferior 的输出中获取该进程 ID。

为了解决您的具体问题,mmap 调用的成功反射(reflect)了 maps 文件中列出的映射(即使该映射的大小在您的示例中为零),而失败反射(reflect)了 mmap 的返回值 (0x10000) 与映射开始 (0x11000) 之间的差异。以 4096 作为大小(如在您的示例中),没有地址将允许分配给 *p 但是使用更大的大小将 4096 添加到 mmap 的返回值会给您一个工作地址(假设你的内核和我的一样)。如果映射的开头等于 mmap 返回值(因为没有 MAP_GROWSDOWN),则不会有差异。

关于linux - mmap 成功但写入失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34932551/

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