简体   繁体   English

Valgrind的无效写入大小为8

[英]Valgrind invalid write size of 8

I have some code that is suppose to break apart a string that looks like the example below and store it into a data structure. 我有一些代码想将一个字符串分解为下面的示例,并将其存储到数据结构中。

ORGANIZER;CN=John Doe;ON=Another Person;SN=Maybe another

Here is what my function looks like: 这是我的函数:

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;
}

And here is what valgrind is telling me: 这是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)

The line 79 is the line that starts with param->value[i] = and then valgrind is referring to the realloc that is 2 lines above. 第79行是以param->value[i] =开头的行,然后valgrind引用的是上面两行的realloc I am confused what is wrong here? 我很困惑这里出了什么问题? Within the param structure there is a flexible array member at the end of the structure which is value . param结构内,在结构的末尾有一个柔性数组成员,它是value I am simply trying to allocate another array position in the structure and then use that position for a string. 我只是试图在结构中分配另一个数组位置,然后将该位置用于字符串。

At some point in those two lines I am guessing I am doing something incorrect regarding the memory, but I am unsure what it is yet. 在这两行的某个时刻,我猜想我在内存方面做错了什么,但是我不确定它到底是什么。

Within the param structure there is a flexible array member at the end of the structure which is value . 在param结构内,在结构的末尾有一个柔性数组成员,它是value I am simply trying to allocate another array position in the structure and then use that position for a string. 我只是试图在结构中分配另一个数组位置,然后将该位置用于字符串。

Let's do the math: in order to allocate enough space for CalParam with its flexible array member that has i elements you need 让我们做个数学:为了给CalParam分配足够的空间,它具有需要i元素的灵活数组成员

  • sizeof(CalParam) - that's the base size of your struct sizeof(CalParam) -这是您的struct的基本大小
  • (i+1)*sizeof(char*) - that's an array of char* of size i+1 (i+1)*sizeof(char*) -这是大小为i+1char*数组

Therefore, your realloc call should look like this: 因此,您的realloc调用应如下所示:

param = realloc(param, sizeof(*param) + (i+1)*sizeof(char*));

Note the asterisk in front of param . 注意param前面的星号。 This is important, because param is a pointer. 这很重要,因为param是指针。

This is not the end of the story, however, because param is passed by value, and you are changing its value by realloc -ing it. 这不是故事的结束,但是,因为param是按值传递,并且系统会通过改变其值realloc -ing它。 This will result in dangling reference in the caller. 这将导致在调用方中悬挂引用。 In order to fix this problem, you need to receive param pointer by pointer (ie a double-asterisk pointer), and assign it in your call of realloc , like this: 为了解决此问题,您需要按指针接收param指针(即双星号指针),并在realloc调用中将其分配,如下所示:

CalError parseOptionalParam(char * paramString, CalParam **param) {
    ...
    *param = realloc(*param, sizeof(**param) + (i+1)*sizeof(char*));
    ...
}

Note some more asterisks there. 注意那里还有一些星号。 To make your code slightly easier to read, consider replacing the first sizeof with sizeof(CalParam) , like this: 为了使您的代码更易于阅读,请考虑将第一个sizeof替换为sizeof(CalParam) ,如下所示:

*param = realloc(*param, sizeof(CalParam) + (i+1)*sizeof(char*));

Finally, you should also fix the potential memory leak with realloc : instead of assigning to *param directly, you should assign to a temporary, check for NULL , and then either assign back to *param , or free the old value and report an error. 最后,您还应该使用realloc修复潜在的内存泄漏:而不是直接分配给*param ,您应该分配给一个临时变量,检查NULL ,然后分配回*param ,或者free旧值并报告错误。

I'm assuming the following definition of CalParam . 我假设以下CalParam定义。

typedef struct {
    char* name;
    char* value[];
} CalParam;

sizeof(param) is the same as sizeof(typeof(param)) , which is the same as sizeof(CalParam*) , which is the size of a pointer. sizeof(param)sizeof(typeof(param))相同,与sizeof(CalParam*) ,后者是指针的大小。 You probably meant sizeof(*param) 你可能是说sizeof(*param)

sizeof(*param) is the same as sizeof(typeof(*param)) , which is the same as sizeof(CalParam) . sizeof(*param)sizeof(typeof(*param))相同,与sizeof(CalParam)相同。 Types are constant, so sizeof is known at compile-time, so flexible arrays must be ignored in the count. 类型是常量,因此sizeof在编译时是已知的,因此必须在计数中忽略灵活的数组。

As such, 因此,

param = realloc(param, sizeof(param) + sizeof(char*));

should be 应该

param = realloc(param, sizeof(CalParam) + sizeof(char*)*(i+1));

Your other memory allocations are wonky too. 您的其他内存分配也很奇怪。 In three places, you have something like 在三个地方,你有类似

char * dst = malloc(strlen(src) + sizeof(char*));
strcpy(dst, src);

That should be 那应该是

char * dst = malloc((strlen(src) + 1) * sizeof(char));
strcpy(dst, src);

But of course, sizeof(char) is 1 , so we can just use 但是当然, sizeof(char)1 ,所以我们可以使用

char * dst = malloc(strlen(src) + 1);
strcpy(dst, src);

But strdup does the same thing. 但是strdup做同样的事情。

char * dst = strdup(src);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM