即使在free()之后strdup()内存泄漏

时间:2014-01-08 15:46:21

标签: c gcc memory-leaks posix

直到最近,我一直都不需要将strdup(stringp)strsep(&stringp_copy, token)一起使用,我认为这会导致内存泄漏。

strdup()总是free'就好了。)

我修复了漏洞,我想我明白了,但我无法弄明白为什么需要。

原始代码(摘要):

const char *message = "From: username\nMessage: basic message\n";
char *message_copy, *line, *field_name;
int colon_position;
message_copy = strdup(message);

while(line = strsep(&message_copy, "\n")) {
  printf(line);
  char *colon = strchr(line, ':');
  if (colon != NULL) {
    colon_position = colon - line;
    strncpy(field_name, line, colon_position);
    printf("%s\n", field_name);
  }
}

free(message_copy);

不泄漏的新代码:

const char *message = "From: username\nMessage: basic message\n";
char *message_copy, *freeable_message_copy, *line, *field_name;
int colon_position;
freeable_message_copy = message_copy = strdup(message);

while(line = strsep(&message_copy, "\n")) {
  printf(line);
  char *colon = strchr(line, ':');
  if (colon != NULL) {
    colon_position = colon - line;
    strncpy(field_name, line, colon_position);
    printf("%s\n", field_name);
  }
}

free(freeable_message_copy);

如何在第一个代码中覆盖message_copy指针?或者是吗?

4 个答案:

答案 0 :(得分:10)

函数strsep()接受一个指向原始字符串(message_copy)的指针并修改它以返回一个指向'next'标记的新指针

const char *message = "From: username\nMessage: basic message\n";
char *message_copy, *original_copy;
//here you have allocated new memory, a duplicate of message
message_copy = original_copy = strdup(message);

在这里打印指针,

printf("copy %p, original %p\n", message_copy, original_copy);

请注意,当您使用strsep()时,您正在修改message_copy,

char* token;
//here you modify message_copy
while(token = strsep(&message_copy, "\n")) {
    printf("%s\n", token);
}

这说明了更改后的message_copy,而original_copy未更改,

printf("copy %p, original %p\n", message_copy, original_copy);

由于message_copy没有指向原始的strdup()结果,这是错误的,

free(message_copy);

但保持原始的strdup()结果,这个免费的作品

//original_copy points to the results of strdup
free(original_copy);

答案 1 :(得分:5)

因为strsep()修改了message_copy参数,所以你试图释放malloc()等未返回的指针。这会产生来自某些malloc()图书馆和valgrind的投诉。它也是未定义的行为,通常会在短时间内导致崩溃(但代码崩溃的位置与执行损坏的代码无关的不方便)。

实际上,你的循环迭代直到message_copy设置为NULL,因此你释放NULL,这是定义的安全行为,但它也是一个无操作。它没有释放通过strdup()分配的指针。

要点:

  • 只有内存分配器返回的自由指针。
  • 不要将指针释放到内存分配器返回的块的中间或末尾。

答案 2 :(得分:1)

阅读strsep手册页here

简而言之,strsep函数将修改传递给函数的原始字符指针,用\0覆盖分隔符的每个出现位置,然后更新原始字符指针以指向经过\0

你的第二个版本没有泄漏,因为你创建了一个临时指针指向从strdup()返回的原始字符指针的开头,所以内存被正确释放,就像你调用free()一样使用原始的char指针而不是strsep()已修改的更新的指针。

答案 3 :(得分:0)

从手册页

...通过使用空字节('\ 0')和*stringp is updated to point past the token覆盖分隔符来终止此令牌....