代码之家  ›  专栏  ›  技术社区  ›  Alex

为什么C有时可以覆盖内存?致命的glibc错误:sysmalloc中的malloc断言失败

  •  0
  • Alex  · 技术社区  · 2 年前

    为什么代码A运行良好,但代码B出现错误? 唯一的区别是printf。还要注意,我正在访问超出范围的内存。 GCC对此并无异议。在示例A中,我甚至很容易覆盖RAM内存。

    编译器错误:

    Fatal glibc error: malloc assertion failure in sysmalloc: (old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)
    

    我的代码和平:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
    #if 1
        // A
        int *items = malloc(10 * sizeof(int));
        printf("allocated: %lu bytes\n", 10 * sizeof(int));
        items = items;
        items[0] = 5;
        items[9] = 5;
        items[10] = 5;
        printf("[");
        for (size_t i = 0; i <= 10; i++)
        {
            printf(" %d", items[i]);
        }
        printf(" ]\n");
    #else
        // B
        int *items = malloc(10 * sizeof(int));
        items = items;
        items[0] = 5;
        items[9] = 5;
        items[10] = 5;
        printf("[");
        for (size_t i = 0; i <= 10; i++)
        {
            printf(" %d", items[i]);
        }
        printf(" ]\n");
    #endif
        return 0;
    }
    
    

    我试着问chatgpt为什么有效,它说是因为我的RAM不够,这太离谱了。 我预计这两个例子中都有segfaults。

    1 回复  |  直到 2 年前
        1
  •  1
  •   Eric Postpischil    2 年前

    我预计这两个例子中都有segfaults。

    C标准中没有任何规定,当你超出分配的内存时,C实现应该给你内存访问违规。也没有合适的教程或教科书。一些学习材料可能提到了分段错误 五月 发生了,但这不是肯定的。

    通常,不可能保证内存访问违规,因为硬件通常以称为页面的块(通常为4096或8192字节)处理内存,但 malloc 以较小的单位(通常是16字节的块)分配内存。(即使您请求的金额较小或不是16字节的倍数, 马洛克 仍然可以以16字节块为单位完成其工作。)所以,如果你为10分配40个字节 int ,无法在这40个字节之后立即将存储器标记为不可访问。硬件提供了一个4096字节的页面,它不能说其中40个字节可以访问,其余的不能访问。

    没有指定标准的C内存管理例程来防止不正确的访问。C通常不是为了防止你的程序做不正当的事情而设计的。它是为了帮助你编写低开销的程序。作为其中的一部分,它避免了检查程序所做一切的开销。作为一名程序员,你的工作就是确保你的程序是正确的。

    至于你的两个代码序列之间的区别,其中一个在超越数组时,碰巧改变了内存管理例程用于记录保存的数据。当他们检测到这一点时,他们报告了一个错误。区别可能是两个代码序列在内存中的排列方式不同。