我有一些代码可能会破坏看起来像下面示例的字符串并将其存储到数据结构中。
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
。我只是试图在结构中分配另一个数组位置,然后将该位置用于字符串。
在这两行中的某些时候,我猜我在做一些关于记忆的错误,但我不确定它到底是什么。
答案 0 :(得分:4)
在param结构中,在结构的末尾有一个灵活的数组成员
value
。我只是试图在结构中分配另一个数组位置,然后将该位置用于字符串。
让我们进行数学运算:为CalParam
分配足够的空间,使其灵活的数组成员具有您需要的i
个元素
sizeof(CalParam)
- 这是struct
(i+1)*sizeof(char*)
- 这是char*
大小为i+1
因此,您的realloc
电话应如下所示:
param = realloc(param, sizeof(*param) + (i+1)*sizeof(char*));
请注意param
前面的星号。这很重要,因为param
是指针。
然而,这不是故事的结尾,因为param
是按值传递的,而您正在通过realloc
更改其值。这将导致调用者中的悬空引用。为了解决这个问题,你需要通过指针接收param
指针(即双星号指针),并在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
旧值并报告错误。
答案 1 :(得分:2)
我假设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
在编译时是已知的,因此必须在计数中忽略灵活的数组。
因此,
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);