一尘不染

为什么MAP_GROWSDOWN映射不增长?

linux

我尝试创建MAP_GROWSDOWN映射,期望它会自动增长。如手册页中所指定:

MAP_GROWSDOWN

该标志用于堆栈。它向内核虚拟内存系统指示该映射应在内存中向下扩展。返回地址比在进程的虚拟地址空间中实际创建的内存区域低一页。
触摸映射下方的“防护”页面中的地址,将导致 映射增加一页
。可以重复这种增长,直到该映射增长到下一个较低映射的高端的页面内为止,此时触摸“防护”页面将产生 SIGSEGV信号。

因此,我编写了以下示例来测试映射的增长:

#ifndef _GNU_SOURCE
    #define _GNU_SOURCE
#endif
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <errno.h>
#include <sys/mman.h>
#include <stdio.h>

int main(void){
    char *mapped_ptr = mmap(NULL, 4096,
                            PROT_READ | PROT_WRITE,
                            MAP_ANONYMOUS | MAP_PRIVATE | MAP_STACK | MAP_GROWSDOWN,
                            -1, 0);
    if(mapped_ptr == MAP_FAILED){
        int error_code = errno;
        fprintf(stderr, "Cannot do MAP_FIXED mapping."
                        "Error code = %d, details = %s\n", error_code, strerror(error_code));
                        exit(EXIT_FAILURE);
    }
    volatile char *c_ptr_1 = mapped_ptr; //address returned by mmap
    *c_ptr_1 = 'a'; //fine

    volatile char *c_ptr_2 = mapped_ptr - 4095; //1 page below the guard
    *c_ptr_2 = 'b'; //crashes with SEGV
}

所以我得到的SEGV不是增加映射。在这里生长意味着什么?


阅读 372

收藏
2020-06-07

共1个答案

一尘不染

更换:

volatile char *c_ptr_1 = mapped_ptr - 4096; //1 page below

volatile char *c_ptr_1 = mapped_ptr;

因为:

返回地址比在进程的虚拟地址空间中实际创建的内存区域低一页。 触摸映射下方的“防护”页面中的地址将导致映射按页面增长。

请注意,我测试了该解决方案,并且可以在内核4.15.0-45-generic上按预期工作。

2020-06-07