【问题标题】:Why does printing to stdout cause `malloc(): corrupted top size`, but printing to stderr works just fine?为什么打印到标准输出会导致“malloc():损坏的顶部大小”,但打印到标准错误工作得很好?
【发布时间】:2020-08-29 05:17:20
【问题描述】:

我有以下函数来设置结构并从结构中转储一些数据:

#include <stdio.h>
#include <stdlib.h>

#include "image.h"

// typedef from image.h included above, copied here for SO
typedef struct image {
    int width;
    int height;
    char *data;
} image;

image *image_new(int width, int height) {
    image *i = malloc(sizeof(image));
    i->width = width;
    i->height = height;
    // allocate space for each row
    i->data = malloc(sizeof(unsigned char) * height * width * 3);
    return i;
}

void image_dump_data(image *i) {
    for (int x = 0; x < i->width; x++) {
        for (int y = 0; y < i->height; y++) {
            // write pixel color to file
            unsigned char r = i->data[(y * i->width) + (x * 3) + 0];
            unsigned char g = i->data[(y * i->width) + (x * 3) + 1];
            unsigned char b = i->data[(y * i->width) + (x * 3) + 2];
            printf("%d %d %d ", (int)r, (int)g, (int)b);
        }
        printf("\n");
    }
}

一旦第一次调用printf(),我的代码就会失败并显示消息malloc(): corrupted top size。当我将 printf() 更改为 fprintf(stderr, ...) 时,我得到了预期的输出。当我使用fprintf(stdout, ...) 时,错误仍然存​​在,因此特别是关于使用stdout 的东西似乎导致我的代码失败。

我希望在这里包含所有相关信息,但如有必要,here is a link to the GitHub repo 包含我在此项目中使用的所有文件。

【问题讨论】:

  • 你如何“连接”你展示的这两个函数?你怎么称呼他们?请尝试创建一个minimal reproducible example 向我们展示in问题本身(使其独立,无需外部链接可以更改、消失或更改其内容)。
  • stdoutstderr 在这方面的唯一区别是第一个通常被缓冲,第二个不是。因此stdout 版本可能会出现您在其他地方遇到的错误,因为实际上必须在某个地方使用malloc。所以不要打信使,stdoutstderr 不是你的问题,它只会让你的问题变得明显。
  • 函数是如何调用的,传入的是什么,后者是如何定义和设置/初始化的?必须知道,我们不知道什么,所以我们需要猜测,我们不会做什么。因此,就目前而言,这个问题有些不完整,因此无法回答。除了最有可能再次猜测,臭名昭著的未定义行为被调用的一般性陈述。
  • 这里为什么是幻数3 (x * 3)
  • 尝试通过 valgrind 运行您的代码。如果你的内存管理不善,它会告诉你在哪里。

标签: c memory-management malloc stdout stderr


【解决方案1】:

我不小心利用了在打印到 stderr 而不是 stdout 时发生的未定义行为(可能是因为缓冲输出与非缓冲输出)。在一个单独的文件中,我对结构指针的大小有一个错误的 malloc,而不是结构本身,导致分配的内存太小。直到后来,这才立即表现为问题。使用valgrind 进行调试时,以下几行直接指出了问题所在:

==1417933== Invalid write of size 8
==1417933==    at 0x10A864: scene_new (scene.c:24)
==1417933==    by 0x109267: main (raytracer.c:27)
==1417933==  Address 0x4b8b160 is 0 bytes after a block of size 32 alloc'd
==1417933==    at 0x483977F: malloc (vg_replace_malloc.c:309)
==1417933==    by 0x10A823: scene_new (scene.c:23)
==1417933==    by 0x109267: main (raytracer.c:27)

【讨论】:

    【解决方案2】:

    您是否尝试过更改格式以避免强制转换?不确定它是否有帮助,但您可以尝试printf doc

    printf("%hhu %hhu %hhu ", r, g, b);
    

    【讨论】:

    • 强制转换没问题,最坏的情况是它们只会导致打印错误的值(因为字节值被符号扩展为int)。它不应该导致被问及的问题,这是因为一些未定义的行为,可能在未显示的代码中。
    猜你喜欢
    • 1970-01-01
    • 2013-05-01
    • 1970-01-01
    • 2012-04-26
    • 1970-01-01
    • 1970-01-01
    • 2018-12-25
    • 2018-08-10
    • 1970-01-01
    相关资源
    最近更新 更多