Valgrind:大小为 8 的无效读取,已分配大小为 8 的块之后的字节

Valgrind: Invalid read of size 8, bytes after a block of size 8 alloc'd

一直在寻找一个简单的案例,就像我在 Stack overflow 和其他网站上找到的一样,但仍然没有找到任何东西,错误发生在第 57 行,然后也是第 47 行,valgrind 说我写了一个指向一个指针array of structures pixel,我试了一下,是不是分配内存有问题,不过好像是赋值有问题bmp_file->data = file_data

==1811== error calling PR_SET_PTRACER, vgdb might block
==1811== Invalid write of size 8
==1811==    at 0x10BC02: read_bmp (bmp.c:65)
==1811==    by 0x1092D7: main (main.c:12)
==1811==  Address 0x4b97268 is 0 bytes after a block of size 8 alloc'd
==1811==    at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1811==    by 0x10BB88: read_bmp (bmp.c:52)
==1811==    by 0x1092D7: main (main.c:12)
==1811== 
==1811== Invalid read of size 8
==1811==    at 0x10BC16: read_bmp (bmp.c:67)
==1811==    by 0x1092D7: main (main.c:12)
==1811==  Address 0x4b97268 is 0 bytes after a block of size 8 alloc'd
==1811==    at 0x483DD99: calloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==1811==    by 0x10BB88: read_bmp (bmp.c:52)
==1811==    by 0x1092D7: main (main.c:12)
struct bmp_image* read_bmp(FILE* stream) {
  struct bmp_image* bmp_file = (struct bmp_image*)calloc(1, sizeof(struct bmp_image*));
  struct bmp_header* header = read_bmp_header(stream);

  if (header->type != 0x4d42) {
    printf("Error: This is not a BMP file.\n");
    free(bmp_file);
    free(header);
    return NULL;
  }

  struct pixel* file_data = read_data(stream, header);

  bmp_file->header = header;
  bmp_file->data = file_data;

  if (bmp_file->header == NULL || bmp_file->data == NULL) {
    printf("Error: Corrupted BMP file.\n");

    if (bmp_file->header == NULL) {
      free(bmp_file->header);
    }

    if (bmp_file->data == NULL) {
      free(bmp_file->data);
    }

    free(bmp_file);
    return NULL;
  }

  return bmp_file;
}
struct pixel* read_data(FILE* stream, const struct bmp_header* header) {
  struct pixel* data = (struct pixel*)calloc(header->height * header->width, sizeof(struct pixel));

  if (!data) {
    free(data);
    return NULL;
  }

  fseek(stream, header->offset, SEEK_SET);
  unsigned short padding = header->width % 4;

  for (int pixelIdx = 0; pixelIdx < header->height * header->width; pixelIdx++) {
    data[pixelIdx].blue = (uint8_t)fgetc(stream);
    data[pixelIdx].green = (uint8_t)fgetc(stream);
    data[pixelIdx].red = (uint8_t)fgetc(stream);

    if ((pixelIdx + 1) % (int)header->width != 0 || padding == 0) continue;

    for (int i = 0; i < padding; i++) {
      fgetc(stream);
    }
  }

  return data;
}
void free_bmp_image(struct bmp_image* image) {
  if (image == NULL) return;

  free(image->header);
  free(image->data);
  free(image);
}

至少这个内存分配

struct bmp_image* bmp_file = (struct bmp_image *)calloc(1, sizeof(struct bmp_image *));

不正确。看来你的意思是

struct bmp_image* bmp_file = (struct bmp_image *)calloc(1, sizeof(struct bmp_image));

struct bmp_image* bmp_file = (struct bmp_image *)calloc(1, sizeof( *bmp_file));

避免分配大小错误:

  1. 分配给引用对象的大小,而不是类型。它使代码更清晰正确,更易于审查和维护。

  2. 不需要转换。

  3. 检查分配是否成功。

示例:

 // struct bmp_image* bmp_file = (struct bmp_image*)calloc(1, sizeof(struct bmp_image*));
 // wrong size >----------------------------------------------^-----------------------^

 struct bmp_image* bmp_file = calloc(1, sizeof bmp_file[0]);
 if (bmp_file == NULL) {
   fprintf(stderr, "Out-of-memory\n");
   return NULL; 
 }

...以及代码中的其他分配。