【问题标题】:when _malloca can not allocate memory on heap当 _malloca 无法在堆上分配内存时
【发布时间】:2014-09-02 06:59:36
【问题描述】:

当 alloca 无法在堆上分配内存时,它会创建结构化异常 stackoverflow 并使用 Stackoverflow 停止程序。好的。但是当 _malloca 不能在堆上分配内存时,它什么也没说。我分配了大量内存,然后使用它,但得到访问冲突异常。 示例

#include <stdio.h>
#include <malloc.h>
#include <conio.h>

void foo(size_t n) {
    int *arr = (int*) _malloca(n*sizeof(int));
    size_t i;

    for (i = 0; i < n; i++) {
        arr[i] = rand();
    }
    for (i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    _freea(arr);
}

void main() {
    foo(900000000000);
    _getch();
}

但是当我只使用部分分配的内存时,我根本没有例外。示例

#include <stdio.h>
#include <malloc.h>
#include <conio.h>

void foo(size_t n) {
    int *arr = (int*) _malloca(n*sizeof(int));
    size_t i;

    for (i = 0; i < 100; i++) {
        arr[i] = rand();
    }
    for (i = 0; i < 100; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    _freea(arr);
}

void main() {
    foo(900000000000);
    _getch();
}

VSE2013 WinDesktop。 Oki,你可能会说,试着捕捉异常

#include <stdio.h>
#include <malloc.h>
#include <conio.h>
#include <windows.h>

void foo(size_t n) {
    int *arr = NULL; 
    size_t i;

    __try {
        arr = (int*)_malloca(n*sizeof(int));
    } __except (GetExceptionCode() == STATUS_STACK_OVERFLOW) {
        int errcode;
        printf("_malloca failed!\n");
        _getch();
        errcode = _resetstkoflw();
        if (errcode) {
            printf("Could not reset the stack!");
            _getch();
            _exit(1);
        }
    }
    for (i = 0; i < 100; i++) {
        arr[i] = rand();
    }
    for (i = 0; i < 100; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    _freea(arr);
}

void main() {
    foo(900000000000);
    _getch();
}

但它继续工作。如果使用数组的所有元素,则再次获得访问冲突。
问题:这是错误还是功能?

【问题讨论】:

  • @JoachimPileborg 来自同一手册页:“如果请求超过一定的字节大小,_malloca 会从程序堆栈或堆分配大小字节”(我只是强调擦它;-))
  • @PeterSchneider Ah 错过了这一点。考虑我适当地擦。 :)
  • @JoachimPileborg 奇怪的功能。需要用 _freea() 括起来(有点合乎逻辑)。因此,对于大小分配和本地范围不可预测的情况,这只是性能问题。
  • 好的,我知道这很奇怪。我什至明白 MS 很奇怪,但是......如果不能在堆上分配内存,为什么它不返回 NULL?为什么它不触发异常呢?不是php,是c。也许还有其他地方我可以检查是否发生了错误?
  • 根据the reference page,它应该在空间不足时抛出结构化异常,而不是返回NULL。但是,为什么它不这样做我不知道。除非您使用的是某种具有超过 3 TB 内存的超级计算机? :)

标签: c stack-overflow alloca


【解决方案1】:

是的!我是对的,当无法在堆上使用 malloc 分配内存时,_malloca 返回 NULL。问题出在电话上,那是愚蠢的(((

foo(900000000000);

无效,因为它大于我计算机上的 size_t 大小。 malloc.h 用这个函数检查大小是否正常

__inline int _MallocaIsSizeInRange(size_t size)
{
    return size + _ALLOCA_S_MARKER_SIZE > size;
}

当我打电话时

foo(INT_MAX);

它返回 NULL,因为无法分配内存。

【讨论】:

  • 不错的一个。抓住了我。应该总是 -Wall 虽然会发出警告。
  • 还有疑问。 VS 写警告:将 __int64 减少到 size_t。所以,它是 size_t;好吧,如果没有,它就不会编译。但是,如果 size + 8 变得小于 size,它为什么要分配内存。不明白。
  • 编译器将文字 900000000000 设为 64 位整数,因为这是唯一适合该数字的类型。现在 size_t 可能是 32 位(或者我们不会有这个麻烦)。请注意, size_t 甚至可能取决于编译器选项。然后将该 64 位数字复制到 32 位 size_t 参数中,可能只是将高 32 位切掉。剩余的低 32 位将只是余数模 2^32,这是一种任意的。 ...
  • ... 例如,如果 size_t 有 4 位,则最多可以分配 15 个字节(所有 4 位设置,1 + 2 + 4 + 8)。如果您传递 int 18 (0 + 2 + 0 + 0 + 1),则只考虑低 4 位:0 + 2 + 0 + 0,其值为 2。该函数将尽职尽责地分配 2 个字节,并且签入 _MallocaIsSizeInRange 不会吠叫,因为它只看到 2。在您的情况下,它会尝试分配 4*900000000000 字节。以 32 为模的数字是 817405952,这取决于限制和内容,您可能仍然可以从系统中获得。
  • 这里的字节切割我很清楚了。我不明白为什么它仍然有效。我的世界有两种可能的变体——计算机可以分配内存并返回有效指针,计算机无法分配足够的内存并返回 NULL。 MS 给了我第三种变体——返回指向小于所需内存块的有效指针。我只能使用这个空间的一部分,如果试图走得更远(多长时间 - 谁知道!)然后遇到意外。最糟糕的是 *arr 现在不是一个指针,它是不寻常的,所以我无法 _msize 并确定它的实际大小。
猜你喜欢
  • 2013-08-10
  • 2011-06-03
  • 2020-05-05
  • 2013-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-17
  • 1970-01-01
相关资源
最近更新 更多