代码之家  ›  专栏  ›  技术社区  ›  Petr Skocik

Linux堆栈的动态扩展

  •  3
  • Petr Skocik  · 技术社区  · 5 年前

    我注意到Linux堆栈开始时很小,并随着递归/推送/VLA导致的页面错误而扩展到最大值。 getrlimit(RLIMIT_STACK,...) ,给予或接受(在我的系统上默认为8mib)。

    不过,奇怪的是,如果我通过直接寻址字节而导致页面错误,那么在限制范围内,Linux只会定期执行segfault,而不会扩展页面映射(但是,如果我在执行完例如alloca之后执行该操作,则不会导致堆栈扩展)。

    示例程序:

    #include <stdio.h>
    #include <unistd.h>
    #include <stdint.h>
    #include <stdlib.h>
    #define CMD "grep stack /proc/XXXXXXXXXXXXXXXX/maps"
    #define CMDP "grep stack /proc/%ld/maps"
    void vla(size_t Sz)
    {
        char b[Sz];
        b[0]='y';
        b[1]='\0';
        puts(b);
    }
    #define OFFSET (sizeof(char)<<12)
    int main(int C, char **V)
    {
        char cmd[sizeof CMD]; sprintf(cmd,CMDP,(long)getpid());
        if(system(cmd)) return 1;
        for(int i=0; ; i++){
            printf("%d\n", i);
            char *ptr = (char*)(((uintptr_t)&ptr)-i*OFFSET);
            if(C>1) vla(i*OFFSET); //pass an argument to the executable to turn this on
            ptr[0] = 'x';
            ptr[1] = '\0';
            if(system(cmd)) return 1;
            puts(ptr);
        }
    }
    

    这是什么内核代码?它如何区分自然的堆栈增长和我在地址空间中四处摸索?

    1 回复  |  直到 5 年前
        1
  •  3
  •   Ctx    5 年前

    Linux内核将堆栈指针的内容作为限制(在合理的边界内)。访问堆栈 在下面 堆栈指针减去65536和32个无符号长整型的大小会导致分段冲突。因此,如果您通过堆栈访问内存,必须确保堆栈指针在某种程度上随Linux内核的访问而减小,从而扩大段。查看以下代码段 /arch/x86/mm/fault.c :

    if (sw_error_code & X86_PF_USER) {
        /*
         * Accessing the stack below %sp is always a bug.
         * The large cushion allows instructions like enter
         * and pusha to work. ("enter $65535, $31" pushes
         * 32 pointers and then decrements %sp by 65535.)
         */
        if (unlikely(address + 65536 + 32 * sizeof(unsigned long) < regs->sp)) {
            bad_area(regs, sw_error_code, address);
            return;
        }
    }
    

    堆栈指针寄存器的值在这里是键!