运行-Time Check Failure #4 - 此函数保留的 _alloca 内存周围的堆栈区域已损坏?

Run-Time Check Failure #4 - Stack area around _alloca memory reserved by this function is corrupted?

#include <iostream>
#include <malloc.h>

void print_vals(int n)
{
    int *arr = (int *)alloca(n);

    for (int i = 0; i < n; i++)
        arr[i] = i;

    for (int i = 0; i < n; i++)
        std::cout << arr[i] << ' ';

    std::cout << '\n';
}

int main()
{
    print_vals(5);
    print_vals(10);
}

当我 运行 这段代码时,我每次调用都会得到这个错误:

Run-Time Check Failure #4 - Stack area around _alloca memory reserved by this function is corrupted

我正在使用 Visual C++ 2019,stdc++14 和 stdc++17 都会产生相同的错误。

这段代码有什么问题?

我假设这只是示例代码,因为如果您的目的只是 打印 数字 0..n,那么绝对 没有 为什么要为此使用数组的原因:-)


关于您的实际问题,alloca 函数,如 malloc,分配了一些 字节。 如果您将其视为您有许多 int 值(几乎肯定大于一个字节),结果不会很好。这实际上在您看到的对话框中得到确认,其中大小为 10,但每个数组元素占用 4 个:

Size: 10
Data: <> 00 00 00 00 01 00 00 00 02 00
         \_________/ \_________/ \____
            arr[0]      arr[1]      ar

您需要做的是:

int *arr = (int*) alloca(n * sizeof(*arr)); // n ints, not bytes.

无论如何,我会避免 alloca因为:

  1. 确实不标准;和
  2. 如果它不能分配 space,它有行为不端的恼人习惯,而不是像 new 那样引发异常。

关于最后一点,Linux doco for alloca 指出(我强调):

The alloca() function returns a pointer to the beginning of the allocated space. If the allocation causes stack overflow, program behavior is undefined.

如果你想要一些不需要自己担心的东西 de-allocating,现代 C++ 有智能指针,所以你可以使用类似的东西:

std::unique_ptr<int[]> arr(new int[n]);

arr 变量超出范围时,为其分配的内存将自动释放。您可以在原始代码的完整变体中尝试:

#include <iostream>
#include <memory>

void print_vals(size_t n) {
    std::unique_ptr<int[]> arr(new int[n]);

    for (size_t i = 0; i < n; i++)
        arr[i] = static_cast<int>(i);
    for (size_t i = 0; i < n; i++)
        std::cout << arr[i] << ' ';
    std::cout << '\n';
}

int main() {
    print_vals(5);
    print_vals(10);
}

顺便说一句,您会注意到我还使用 size_t 而不是 int 作为大小和索引 - 我认为这样更合适。现在,当然,这使用 heap 而不是堆栈,但根据之前关于 alloca.

的评论,这是更安全的方法

可以使alloca更容易成功,如果你保证对大小有一些限制,例如:

void print_vals(size_t n) {
    if (n >= 100) {
        doSomethingIntelligent();
        return;
    }
    int *arr = (int *)alloca(n * sizeof(*arr));

    ...
}

但这实际上并不能保证它的安全,如果你打算这样做,你也可以使用固定缓冲区,因为你会知道最大尺寸:

void print_vals(size_t n) {
    int arr[100];
    if (n >= sizeof(arr) / sizeof(*arr)) {
        doSomethingIntelligent();
        return;
    }

    ...
}

我想提出另一个解决方案:如果您的意图是尽可能高效,则可以使用混合方法。就此而言,我的意思是使用本地缓冲区 below 一定大小并仅在需要时分配内存:

void print_vals(size_t n) {
    // Default to using local buffer.

    int localBuff[100];
    int *arr = localBuff;

    // If more space needed, allocate  an auto-freeing smart pointer.

    std::unique_ptr<int[]> allocBuff;
    if (n >= sizeof(localBuff) / sizeof(*localBuff)) {
        allocBuff.reset(new int[n]);
        arr = allocBuff.get();
    }

    // Here, arr points to to a big-enough buffer.

    ...

函数alloca()的参数是字节分配,所以元素的大小必须乘以元素的数量。

可以这样做:

int *arr = (int *)alloca(sizeof(*arr) * n);