程序运行,但 Valgrind 在尝试写入 malloc 内存时检测到问题

问题描述 投票:0回答:2

为了了解更多 C 语言,我正在尝试重新创建基本数据结构。这是我尝试数组的一个最小示例,该数组可以编译并运行,但 valgrind 检测到问题:

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

typedef void * vp_t;

typedef struct {
  int len;
  vp_t *start;
} arr_t;

arr_t * array_new(int len) {
  arr_t *arr = malloc(sizeof(arr_t));
  arr->start = malloc(len * sizeof(vp_t));
  arr->len = len;
  return arr;
}

void array_set(arr_t *arr, int i, vp_t vp) {
  vp_t *dest = arr->start + i * sizeof(vp_t);  
  *dest = vp;
}

int array_get(arr_t *arr, int i) {
  int *p = *(arr->start + i * sizeof(vp_t));
  return *p;
}

void array_delete(arr_t *arr) {
  free(arr->start);
  free(arr);
}

int main() {
  int x=0, y=1, z=2;
  arr_t *arr = array_new(3);
  array_set(arr, 0, &x);
  array_set(arr, 1, &y);
  array_set(arr, 2, &z);

  for (int i = 0; i < 3; ++i) printf("%i ", array_get(arr, i));
  putchar('\n');

  array_delete(arr);
  
  return 0;
}

程序按预期输出

1 2 3
。然而,当我第二次和第三次调用 array_set 函数时,valgrind 检测到了一个问题。针对此处的示例代码运行 valgrind,我得到:

==91933== Invalid write of size 8
==91933==    at 0x109244: array_set (min.c:22)
==91933==    by 0x109312: main (min.c:39)
==91933==  Address 0x4a990d0 is 32 bytes before an unallocated block of size 4,194,032 in arena "client"
==91933== 
==91933== 
==91933== Process terminating with default action of signal 11 (SIGSEGV)
==91933==  Access not within mapped region at address 0x2003A98F4C
==91933==    at 0x109244: array_set (min.c:22)
==91933==    by 0x109327: main (min.c:40)

min.c:22
指的是array_set函数中的
*dest = vp
min.c:39
指的是
array_set(arr, 1, &y)
。 Valgrind 抱怨第 38 行,
array_set(arr, 0, &x)

我一直在研究gdb,但我还没弄清楚。感谢您的浏览。

c pointers segmentation-fault malloc valgrind
2个回答
0
投票

当您需要寻址数组时,只需将多少个单元格(除了单元格大小)添加到指针即可。

void array_set(arr_t *arr, int i, vp_t vp) {
  vp_t *dest = arr->start + i;  
  *dest = vp;
}

int array_get(arr_t *arr, int i) {
  int *p = *(arr->start + i);
  return *p;
}

arr->start 的类型为 vp_t,因此当您向指针添加 1 时,编译器将增加所需的数量 (sizeof(vp_t)) 以转到下一个单元格。


0
投票

这就是解决方案,但首先为什么,你需要一个 void ** 数组,如果你想创建一个整数数组,请使用 int** 创建,只有当你需要任何类型的数组时才推荐使用 void 数组。 不管怎样,错误在于你创建了一个 void* (一维),而实际上,应该是一个二维数组 void **

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


typedef struct {
  int len;
  void  **start;
} arr_t;

arr_t * array_new(int len) {
  arr_t *arr = malloc(sizeof(arr_t));
  arr->start = malloc(len * sizeof(void*));
  arr->len = len;
  return arr;
}

void array_set(arr_t *arr, int i, void  *vp) {
    arr->start[i] = vp;
}

int array_get(arr_t *arr, int i) {
    return *(int*)arr->start[i];
}

void array_delete(arr_t *arr) {
  free(arr->start);
  free(arr);
}

int main() {
  int x=0, y=1, z=2;
  arr_t *arr = array_new(3);
  array_set(arr, 0, &x);
  array_set(arr, 1, &y);
  array_set(arr, 2, &z);
  for (int i = 0; i < 3; ++i) printf("%i ", array_get(arr, i));
  putchar('\n');

  array_delete(arr);
  
  return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.