【问题标题】:Freeing memory after allocation error (realloc)分配错误后释放内存 (realloc)
【发布时间】:2021-11-25 14:18:06
【问题描述】:

下面的第一个 if 语句检查在向数组添加元素时是否已达到缓冲区大小的末尾。如果我们有,它会复制原始大小。

while (token != NULL) {
    tokens[position] = token;
    position++;

    if (position >= bufsize) {
      bufsize += LSH_TOK_BUFSIZE;
      tokens_backup = tokens;
      tokens = realloc(tokens, bufsize * sizeof(char*));
      if (!tokens) {
        free(tokens_backup);
        fprintf(stderr, "lsh: allocation error\n");
        exit(EXIT_FAILURE);
      }
    }

    token = strtok(NULL, LSH_TOK_DELIM);
}

最后一个 if 语句检查分配错误,如果发生这种情况,它会释放 tokens_backup,它指向原始的 tokens

为什么这里需要 tokens_backup?

如果确实存在分配错误,他们不能简单地释放原来的tokens吗?

两者的声明是:

char **tokens = malloc(bufsize * sizeof(char*));
char *token, **tokens_backup;

【问题讨论】:

  • 一般来说,在返回错误代码之前释放一个特定的内存分配是无稽之谈。我知道您对这段代码有些困惑,我认为该代码不应该存在。
  • @Cheatah 人们可以选择保持分配/空闲的完美同步,而不必为valgrind 和 LeakSanitizer 创建抑制规则(如果 LeakSanitizer 甚至支持抑制规则)。保持它的清洁通常比过滤掉“没有问题的泄漏”更容易。
  • 在这些情况下,调用完整的清理和退出例程会更有意义,而不是只关注最近的realloc 并不干净地退出。但我想这主要是基于意见的。但我明白你的意思。

标签: c malloc free realloc


【解决方案1】:

“如果确实存在分配错误,他们不能简单地释放原始令牌吗?”

不,我们不能,因为我们丢失了原来的tokens

如果tokens = realloc(tokens, bufsize * sizeof(char*)) 中的分配失败,tokens 将是NULL 并且我们要释放的指针丢失,因此无法再释放内存。因此我们需要将原始的tokens指针存储在tokens_backup中,这样我们就可以释放tokens_backup

【讨论】:

  • 感谢您的解释。如果tokens_backup指向了tokens,分配失败了,是不是也丢失了tokens_backup?
  • @hendrix 不,tokens_backup 不会神奇地改变,除非你给它分配别的东西。如果realloc 失败,则返回NULL,仅此而已。 tokens_backup 仍将指向 tokensrealloc 之前指向的相同位置
  • realloc 函数承诺“如果 realloc() 失败,原始块保持不变;它不会被释放或移动。”所以内存区域仍然可以安全使用,但为了这样做,您需要对其进行引用。否则你只会有内存泄漏。 @TedLyngmo 在问题的 cmets 中很好地说明了这一点。但在这种情况下,我不会担心它,因为无论如何编程都会退出。这只会满足内存调试器。
【解决方案2】:

C 标准中关于函数realloc 的一些引用(7.22.3.5 realloc 函数)

  1. ...如果无法为新对象分配内存,则旧对象不会 已解除分配,其值不变

4 realloc 函数返回一个指向新对象的指针(可能 具有与指向旧对象的指针相同的值)、或 null 无法分配新对象时的指针。

在您的代码 sn-p 中,指针 tokens 指向分配的内存。在此声明中

tokens = realloc(tokens, bufsize * sizeof(char*));

如果无法重新分配内存,则函数realloc 返回一个分配给指针tokens 的空指针,覆盖存储在指针中的先前值。也就是说,在这种情况下,指针标记将为空指针,并且先前分配的内存的地址将丢失。因此,您将无法释放先前分配的内存。结果会出现内存泄漏,因为它写在第一个提供的引号中,之前分配的内存不会被函数 realloc 本身释放。

在调用函数 realloc 之前有一个重复的指针,您可以在这种情况下使用这个重复的指针释放先前分配的内存。

【讨论】:

    猜你喜欢
    • 2014-03-07
    • 2017-03-22
    • 2018-03-26
    • 2016-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-09
    相关资源
    最近更新 更多