简体   繁体   English

C alloca函数-尝试分配过多内存时会发生什么

[英]C alloca function - what happens when too much memory is tried to be allocated

In C the alloca() function allocates memory on the stackframe of the caller of alloca(). 在C语言中,alloca()函数在alloca()调用者的堆栈帧上分配内存。

What happens when you try to allocate a huge number of bytes that it cannot possibly allocate? 当您尝试分配无法分配的大量字节时会发生什么?

  • Does it allocate as many bytes as it can until the stack meets the heap segment? 它是否分配尽可能多的字节,直到堆栈遇到堆段为止?
  • Or does it allocate nothing at all? 还是根本不分配任何东西?

    alloca( 100000000000000000000 ); alloca(100000000000000000000);

The manual mentions: 手册中提到:

The alloca() function returns a pointer to the beginning of the allocated space. alloca()函数返回一个指向分配空间开头的指针。 If the allocation causes stack overflow, program behavior is undefined. 如果分配导致堆栈溢出,则程序行为未定义。

I understand the behaviour is undefined. 我了解行为是不确定的。 But there must be more to say than that: 但是必须要说的比这还多:

  • What does it return, a pointer to the first byte after the top of the stack before main was called? 它返回什么,即指向main调用之前堆栈顶部之后的第一个字节的指针?
  • After alloca() returned is the stack pointer different then what it was before alloca() was called? 返回alloca()之后,堆栈指针是否不同于调用alloca()之前的指针?

Does anyone have some more info about this? 有人对此有更多信息吗?

What happens depends on your compiler and the hardening options in use; 会发生什么情况取决于您的编译器和使用的强化选项。 typically, you have no indication that it failed and you either clobber random unrelated memory, or crash, shortly after calling alloca . 通常,您没有迹象表明它失败了,或者在调用alloca之后不久就破坏了随机无关的内存,或者崩溃了。 With some hardening options you may be able to make the crash reliable, but you're never able to detect and recover from the failure. 使用某些强化选项,您也许可以使崩溃更可靠,但您永远无法检测到故障并从故障中恢复。 alloca simply should not be used. 根本不应该使用alloca It was a bad mistake that looked too good to be true, because it is. 看起来好得令人难以置信,这是一个严重的错误,因为事实确实如此。

The GNU libc implementation of alloca() reads: alloca()GNU libc实现如下:

# define alloca(size)   __builtin_alloca (size)

It uses a compiler built-in , thus it depends entirely on how it's been implemented by the compiler. 它使用内置编译器 ,因此完全取决于编译器的实现方式。 More specifically, it depends on how the stack is handled, which happens to be aa machine and ABI-dependent data structure. 更具体地说,这取决于堆栈的处理方式,而堆栈恰好是一台机器和与ABI相关的数据结构。


Let's examine a concrete case. 让我们研究一个具体案例。 On my machine, this is the assembly for alloca(100000000000L) : 在我的机器上,这是alloca(100000000000L)的程序集:

0e9b:  movabsq $-100000000016, %rax ; * Loads (size + 16) into rax.
0ea5:  addq   %rax, %rsp            ; * Adds it to the top of the stack.
0ea8:  movq   %rsp, -48(%rbp)       ; * Temporarily stores it.
0eac:  movq   -48(%rbp), %rax       ; * These five instructions round the
0eb0:  addq   $15, %rax             ;   value stored to the next multiple
0eb4:  shrq   $4, %rax              ;   of 0x10 by doing:
0eb8:  shlq   $4, %rax              ;   rax = ((rax+15) >> 4) << 4
0ebc:  movq   %rax, -48(%rbp)       ;   and storing it again in the stack.
0ec0:  movq   -48(%rbp), %rax       ; * Reads the rounded value and copies
0ec4:  movq   %rax, -24(%rbp)       ;   it on the previous stack position.

Compiled using gcc-4.2 -g test.c -o test from the following program: 使用gcc-4.2 -g test.c -o test从以下程序编译:

With something to refer to, your questions can now be answered: 通过参考,您的问题现在可以得到回答:

Does it allocate as many bytes as it can until the stack meets the heap segment? 它是否分配尽可能多的字节,直到堆栈遇到堆段为止?

It just blindly grows the stack by the requested number of bytes. 它只是盲目地使堆栈增加所请求的字节数。 No bounds checking is performed at all , so both the stack pointer and the returned value will probably now be in a illegal location. 无边界检查全部执行,所以无论是堆栈指针和返回值将可能现在处于非法位置。 Attempting to read/write from the returned value (or push onto the stack) will result on a SIGSEGV . 尝试从返回的值进行读取/写入(或压入堆栈)将导致SIGSEGV

What does it return, a pointer to the first byte after the top of the stack before main was called? 它返回什么,即指向main调用之前堆栈顶部之后的第一个字节的指针?

It returns a pointer to the first byte of allocated memory. 它返回一个指向已分配内存的第一个字节的指针。

After alloca() returned is the stack pointer different then what it was before alloca() was called? 返回alloca()之后,堆栈指针是否不同于调用alloca()之前的指针?

Yes, see explanation above. 是的,请参阅上面的说明。 Also, when the function that called alloca returns, the stack will be restored to previous frame and it will be usable again. 同样,当调用alloca的函数返回时,堆栈将恢复到前一帧,并且将再次可用。

Strictly speaking, nobody knows, because "undefined behavior" isn't itself defined. 严格来说,没有人知道,因为“未定义的行为”本身不是定义的。 (alloca isn't defined by the C or POSIX standards, for example). (例如,alloca不是由C或POSIX标准定义的)。

For illustration only, C's definition of "undefined behavior" is (ISO 9899:1999, section 3.4.3): 仅出于说明目的,C对“未定义行为”的定义是(ISO 9899:1999,第3.4.3节):

"behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements “在使用非便携式或错误程序构造或错误数据时,本国际标准对此不施加任何要求的行为

"NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message)." “要点可能的不确定行为范围从完全忽略具有不可预测结果的情况到在以环境特征的文档化方式进行翻译或程序执行期间的行为(有或没有发出诊断消息),到终止翻译或执行(有发出诊断消息)。”

So: absolutely anything can happen. 所以:绝对会发生任何事情。 Your hard disk might get reformatted. 您的硬盘可能会重新格式化。 The sky might fall in. (OK, probably not, but it would be perfectly acceptable given your input.) You can't make any assumption or statement whatsoever. 天空可能会掉下来。(好的,可能不会,但是考虑到您的输入,这是完全可以接受的。)您无法做出任何假设或声明。

If your program makes any such assumptions about (or reliance on) program behaviour after an alloca-induced stack overflow then your program is broken. 如果您的程序在分配内存引起的堆栈溢出后对程序行为做出任何此类假设(或依赖),则您的程序将被破坏。 It's best not to surmise what a particular compiler might do in that situation. 最好不要推测在这种情况下特定的编译器可能会做什么。 Your program's broken, end of story. 您的程序坏了,故事结束了。

On windows you can recover from it. 在Windows上,您可以从中恢复。 Tested using gcc: 使用gcc测试:

/*
 * Show how get memory from stack without crash
 * Currently, compiles ok with mingw, and the latest version of tiny c (from git)
 * Last Version: 29/june/2014
 * Programmed by Carlos Montiers
 */

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <malloc.h>
#include <setjmp.h>

int _resetstkoflw(void);

static jmp_buf alloca_jmp_buf;

LONG WINAPI AllocaExceptionFilter(EXCEPTION_POINTERS * ExceptionInfo)
{

    switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
    case STATUS_STACK_OVERFLOW:

    // reset the stack
    if (0 == _resetstkoflw()) {
        printf("Could not reset the stack!\n");
        _exit(1);
    }

    longjmp(alloca_jmp_buf, 1);

    break;
    }

    return EXCEPTION_EXECUTE_HANDLER;
}

int main()
{
    void *m;
    int alloca_jmp_res;
    LPTOP_LEVEL_EXCEPTION_FILTER prev;

    //replace the exception filter function saving the previous
    prev = SetUnhandledExceptionFilter(AllocaExceptionFilter);

    alloca_jmp_res = setjmp(alloca_jmp_buf);
    if ((0 == alloca_jmp_res)) {
    m = alloca(INT_MAX);

    } else if ((1 == alloca_jmp_res)) {
    m = NULL;

    }
    //restore exception filter function
    SetUnhandledExceptionFilter(prev);

    if (!m) {
    printf("alloca Failed\n");
    }

    printf("Bye\n");
    return 1;

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C-用malloc分配的内存过多 - C - Too much memory allocated with malloc 当试图释放由堆管理器分配的内存时会发生什么,它分配的内容超过了要求? - what happens when tried to free memory allocated by heap manager, which allocates more than asked for? 分配了alloca的内存在函数结束时或范围结束时被释放? - Memory allocated with alloca gets freed at end of function or at end of scope? 像这样在函数调用中分配的内存会发生什么? - What happens to the memory allocated in a function call like so? 如果您不释放函数中动态分配的内存会怎样? - What happens if you don't free dynamically allocated memory in a function? 如果在C中将分配的内存设置为NULL,会发生什么 - What Happens If You Set Allocated Memory To NULL in C Android NDK:应用程序完成后,使用malloc分配的内存将如何处理? - Android NDK: what happens to memory allocated with malloc when app finishes? 调用execv()时动态分配的内存会发生什么? - What happens to dynamic allocated memory when calling execv()? 当我引用一个不是我分配的地址 memory 时会发生什么? - What happens when I reference a memory address not allocated by me? 分配的内存中空白空间会发生什么? - What happens to empty space in allocated memory?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM