【问题标题】:strdup() memory leak even after free()即使在 free() 之后 strdup() 内存泄漏
【发布时间】:2014-01-08 15:46:20
【问题描述】:

直到最近我才需要将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 指针如何在第一个代码中被覆盖?是吗?

【问题讨论】:

  • 评论:不要做printf(line);如果line 包含看起来像printf() 的格式字符串转换规范,它将最终读取或写入错误的内存。使用fputs(line, stdout)printf("%s", line) — 既安全又等效。
  • message_copy 被 strsep 覆盖。读懂这个人。
  • 谢谢,@JonathanLeffler。 printf(line) 用于快速而肮脏的调试。

标签: c gcc memory-leaks posix


【解决方案1】:

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

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

【讨论】:

  • 我完全错过了它修改了 strsep 手册页中的指针。
【解决方案2】:

因为strsep() 修改了message_copy 参数,您试图释放malloc() 等人未返回的指针。这会引起一些malloc() 库和valgrind 的投诉。这也是未定义的行为,通常会导致短时间内崩溃(但代码崩溃的位置与造成损害的代码无关)。

事实上,您的循环会一直迭代,直到 message_copy 设置为 NULL,因此您正在释放 NULL,这是已定义且安全的行为,但它也是空操作。它没有释放通过strdup()分配的指针。

总结:

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

【讨论】:

    【解决方案3】:

    阅读strsep 手册页here

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

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

    【讨论】:

      【解决方案4】:

      从手册页,

      ...这个标记通过用空字节('\0')和*stringp is updated to point past the token....覆盖分隔符来终止。

      【讨论】:

        猜你喜欢
        • 2016-01-18
        • 1970-01-01
        • 2016-06-04
        • 2012-08-14
        • 2012-02-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-19
        相关资源
        最近更新 更多