Valgrind 无效写入大小 8
Valgrind invalid write size of 8
我有一些代码可以分解如下例所示的字符串并将其存储到数据结构中。
ORGANIZER;CN=John Doe;ON=Another Person;SN=Maybe another
我的函数如下所示:
CalError parseOptionalParam(char * paramString, CalParam * param) {
char * parseString = malloc(strlen(paramString) + sizeof(char*));
strcpy(parseString, paramString);
char * tokenSemi;
tokenSemi = strtok(parseString, ";");
if(tokenSemi == NULL) return SYNTAX;
int i = 0;
while(tokenSemi != NULL) {
tokenSemi = strtok(NULL, ";");
if(tokenSemi == NULL) return SYNTAX;
char * tokenEqual = strtok(tokenSemi, "=");
param->name = malloc(strlen(tokenEqual) + sizeof(char*));
strcpy(param->name, tokenEqual);
param = realloc(param, sizeof(param) + sizeof(char*));
tokenEqual = strtok(tokenSemi, "=");
param->value[i] = malloc(sizeof(char*) + strlen(tokenEqual));
strcpy(param->value[i], tokenEqual);
i++;
}
free(parseString);
return OK;
}
这是 valgrind 告诉我的:
==7925== Invalid write of size 8
==7925== at 0x400E56: parseOptionalParam (calutil.c:79)
==7925== by 0x400CED: parseCalProp (calutil.c:50)
==7925== by 0x400B0B: main (testfile.c:8)
==7925== Address 0x5202508 is 8 bytes after a block of size 16 alloc'd
==7925== at 0x4C2DD9F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7925== by 0x400E13: parseOptionalParam (calutil.c:77)
==7925== by 0x400CED: parseCalProp (calutil.c:50)
==7925== by 0x400B0B: main (testfile.c:8)
第 79 行是以 param->value[i] =
开头的行,然后 valgrind 指的是上面 2 行的 realloc
。我很困惑这里出了什么问题?在 param
结构中,结构末尾有一个灵活的数组成员 value
。我只是想在结构中分配另一个数组位置,然后将该位置用于字符串。
在这两行中的某个时刻,我猜我在内存方面做了一些不正确的事情,但我不确定它是什么。
Within the param structure there is a flexible array member at the end of the structure which is value
. I am simply trying to allocate another array position in the structure and then use that position for a string.
让我们计算一下:为了使用具有 i
个元素的灵活数组成员为 CalParam
分配足够的 space,您需要
sizeof(CalParam)
- 这是您的 struct
的基本尺寸
(i+1)*sizeof(char*)
- 这是一个 char*
大小的数组 i+1
因此,您的 realloc
调用应如下所示:
param = realloc(param, sizeof(*param) + (i+1)*sizeof(char*));
注意 param
前面的星号。这很重要,因为 param
是一个指针。
然而,这还没有结束,因为 param
是按值传递的,而您正在通过 realloc
-ing 来更改它的值。这将导致调用者中出现悬空引用。为了解决这个问题,你需要一个接一个地接收 param
指针(即一个 double-asterisk 指针),并在你对 realloc
的调用中分配它,像这样:
CalError parseOptionalParam(char * paramString, CalParam **param) {
...
*param = realloc(*param, sizeof(**param) + (i+1)*sizeof(char*));
...
}
请注意此处的更多星号。为了使您的代码更易于阅读,请考虑将第一个 sizeof
替换为 sizeof(CalParam)
,如下所示:
*param = realloc(*param, sizeof(CalParam) + (i+1)*sizeof(char*));
最后,你还应该用 realloc
修复潜在的内存泄漏:而不是直接分配给 *param
,你应该分配给一个临时的,检查 NULL
,然后分配回 *param
,或 free
旧值并报告错误。
我假设 CalParam
.
的定义如下
typedef struct {
char* name;
char* value[];
} CalParam;
sizeof(param)
与sizeof(typeof(param))
相同,与sizeof(CalParam*)
相同,都是指针的大小。你可能是说 sizeof(*param)
sizeof(*param)
与sizeof(typeof(*param))
相同,与sizeof(CalParam)
相同。类型是常量,因此 sizeof
在 compile-time 处已知,因此必须在计数中忽略灵活数组。
因此,
param = realloc(param, sizeof(param) + sizeof(char*));
应该是
param = realloc(param, sizeof(CalParam) + sizeof(char*)*(i+1));
您的其他内存分配也很不稳定。在三个地方,你有类似
的东西
char * dst = malloc(strlen(src) + sizeof(char*));
strcpy(dst, src);
应该是
char * dst = malloc((strlen(src) + 1) * sizeof(char));
strcpy(dst, src);
当然,sizeof(char)
就是1
,所以我们可以直接使用
char * dst = malloc(strlen(src) + 1);
strcpy(dst, src);
但是strdup
做同样的事情。
char * dst = strdup(src);
我有一些代码可以分解如下例所示的字符串并将其存储到数据结构中。
ORGANIZER;CN=John Doe;ON=Another Person;SN=Maybe another
我的函数如下所示:
CalError parseOptionalParam(char * paramString, CalParam * param) {
char * parseString = malloc(strlen(paramString) + sizeof(char*));
strcpy(parseString, paramString);
char * tokenSemi;
tokenSemi = strtok(parseString, ";");
if(tokenSemi == NULL) return SYNTAX;
int i = 0;
while(tokenSemi != NULL) {
tokenSemi = strtok(NULL, ";");
if(tokenSemi == NULL) return SYNTAX;
char * tokenEqual = strtok(tokenSemi, "=");
param->name = malloc(strlen(tokenEqual) + sizeof(char*));
strcpy(param->name, tokenEqual);
param = realloc(param, sizeof(param) + sizeof(char*));
tokenEqual = strtok(tokenSemi, "=");
param->value[i] = malloc(sizeof(char*) + strlen(tokenEqual));
strcpy(param->value[i], tokenEqual);
i++;
}
free(parseString);
return OK;
}
这是 valgrind 告诉我的:
==7925== Invalid write of size 8
==7925== at 0x400E56: parseOptionalParam (calutil.c:79)
==7925== by 0x400CED: parseCalProp (calutil.c:50)
==7925== by 0x400B0B: main (testfile.c:8)
==7925== Address 0x5202508 is 8 bytes after a block of size 16 alloc'd
==7925== at 0x4C2DD9F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7925== by 0x400E13: parseOptionalParam (calutil.c:77)
==7925== by 0x400CED: parseCalProp (calutil.c:50)
==7925== by 0x400B0B: main (testfile.c:8)
第 79 行是以 param->value[i] =
开头的行,然后 valgrind 指的是上面 2 行的 realloc
。我很困惑这里出了什么问题?在 param
结构中,结构末尾有一个灵活的数组成员 value
。我只是想在结构中分配另一个数组位置,然后将该位置用于字符串。
在这两行中的某个时刻,我猜我在内存方面做了一些不正确的事情,但我不确定它是什么。
Within the param structure there is a flexible array member at the end of the structure which is
value
. I am simply trying to allocate another array position in the structure and then use that position for a string.
让我们计算一下:为了使用具有 i
个元素的灵活数组成员为 CalParam
分配足够的 space,您需要
sizeof(CalParam)
- 这是您的struct
的基本尺寸
(i+1)*sizeof(char*)
- 这是一个char*
大小的数组i+1
因此,您的 realloc
调用应如下所示:
param = realloc(param, sizeof(*param) + (i+1)*sizeof(char*));
注意 param
前面的星号。这很重要,因为 param
是一个指针。
然而,这还没有结束,因为 param
是按值传递的,而您正在通过 realloc
-ing 来更改它的值。这将导致调用者中出现悬空引用。为了解决这个问题,你需要一个接一个地接收 param
指针(即一个 double-asterisk 指针),并在你对 realloc
的调用中分配它,像这样:
CalError parseOptionalParam(char * paramString, CalParam **param) {
...
*param = realloc(*param, sizeof(**param) + (i+1)*sizeof(char*));
...
}
请注意此处的更多星号。为了使您的代码更易于阅读,请考虑将第一个 sizeof
替换为 sizeof(CalParam)
,如下所示:
*param = realloc(*param, sizeof(CalParam) + (i+1)*sizeof(char*));
最后,你还应该用 realloc
修复潜在的内存泄漏:而不是直接分配给 *param
,你应该分配给一个临时的,检查 NULL
,然后分配回 *param
,或 free
旧值并报告错误。
我假设 CalParam
.
typedef struct {
char* name;
char* value[];
} CalParam;
sizeof(param)
与sizeof(typeof(param))
相同,与sizeof(CalParam*)
相同,都是指针的大小。你可能是说 sizeof(*param)
sizeof(*param)
与sizeof(typeof(*param))
相同,与sizeof(CalParam)
相同。类型是常量,因此 sizeof
在 compile-time 处已知,因此必须在计数中忽略灵活数组。
因此,
param = realloc(param, sizeof(param) + sizeof(char*));
应该是
param = realloc(param, sizeof(CalParam) + sizeof(char*)*(i+1));
您的其他内存分配也很不稳定。在三个地方,你有类似
的东西char * dst = malloc(strlen(src) + sizeof(char*));
strcpy(dst, src);
应该是
char * dst = malloc((strlen(src) + 1) * sizeof(char));
strcpy(dst, src);
当然,sizeof(char)
就是1
,所以我们可以直接使用
char * dst = malloc(strlen(src) + 1);
strcpy(dst, src);
但是strdup
做同样的事情。
char * dst = strdup(src);