【问题标题】:realloc crashes when the input address is points to invalid address当输入地址指向无效地址时 realloc 崩溃
【发布时间】:2017-12-25 16:01:41
【问题描述】:

realloc 可以返回相同的输入地址或不同的地址。如果它返回一个不同的地址,那么它将在内部取消分配/释放输入内存并将该内容移动到另一个位置并返回该新地址。

请考虑以下情况。

new_ptr = realloc (2000, 10000)  // Lets assume the input address is 2000 

// Lets assume the new_ptr address is 3000

因此,realloc 内部应释放指针指向 2000 的内存并将这些数据移动到新位置 3000 并返回 3000 地址。

现在地址 2000 指向无效。因此,realloc API 不会将它分配给 NULL。

现在,将无效地址传递给 realloc 函数。实时可能会有变化,realloc 可能会得到无效的输入地址。

new_ptr = realloc(2000, 10000)

此 2000 地址无效,因为它已被先前的 realloc 释放。现在程序崩溃了。

我可以通过以下方式解决此问题吗?

      if (new_ptr != old_ptr ) {
        old_ptr = NULL;                      
      }

由于 old_ptr 无效。我将把它分配给NULL。 请确认我的更正。

【问题讨论】:

  • 我认为这是一个XY problem,因为 OP 似乎没有向我们展示真正的问题。
  • 总是使用返回值,不一样没关系。使用临时指针检查NULL,这是唯一需要旧指针的情况。
  • 问题是realloc成功后该区域被释放,并分配一个新的,旧指针会有不确定的值,所以你不能比较new_ptr != old_ptr
  • 使用已释放的指针值调用 realloc() 会导致未定义的行为。现在对 2000 指针的任何使用都无效。当您使用它时,任何事情都可能发生。该程序没有义务崩溃。它没有义务不崩溃。
  • 没有可移植的方法来知道块是否移动,并且测试旧指针是未定义的行为

标签: c memory-management realloc


【解决方案1】:

想想你的第一句话:

realloc 可以返回相同的输入地址或不同的地址。

这意味着你可以只使用返回值作为你的新指针,你不必知道它是否与你之前的不同。如果不同,realloc() 已经为您释放了前一个块。

但有一个例外:如果分配失败,realloc() 可能会返回 0 / NULL仅在这种情况下,旧指针仍然有效。因此,正确使用realloc() 的常用习语如下所示:

T *x = malloc(x_size);
// check x for NULL

// [...]

T *tmp = realloc(x, new_size);
if (!tmp)
{
    free(x);
    // handle error, in many cases just exit(1) or similar
}
x = tmp; // use the new pointer, don't care whether it's the same

请注意,在对realloc()成功 调用之后使用x(来自我上面的示例)是未定义的,根据C 标准,x 在调用之后是无效的。这并没有告诉您关于x 的实际值的任何信息。它只是告诉你“不要使用它,否则你的程序可能会做任何事情”。

这段自述可能会帮助您理解未定义行为的含义:

C 中的未定义行为

C 是一种非常低级的语言,其结果如下:

没有什么能阻止你做完全错误的事情

许多语言,尤其是那些用于某些托管环境的语言,例如JavaC# 当你做不允许的事情时,实际上会阻止你,比如, 访问不存在的数组元素。 C 没有。只要你的 程序语法正确,编译器不会抱怨。如果你这样做 你的程序中禁止的东西,C 只是调用你的行为 程序未定义。这正式允许在运行时发生任何事情 该程序。通常,结果将是崩溃或只是“垃圾”的输出 值,如上所示。但如果你真的不走运,你的程序看起来 工作得很好,直到它得到一些稍微不同的输入,然后 时间,你将很难确定你的程序到底在哪里 未定义。因此一定要避免未定义的行为!

附带说明,未定义的行为也可能导致安全漏洞。这 在实践中发生了很多

【讨论】:

  • 我接受 Felix。" 如果不同,realloc() 已经为你释放了前一个块。 .现在,input_pointer 是有效还是无效? realloc 释放前一个块是可以的。但是,它会将 old_ptr 分配为 NULL 吗?
  • 什么意思?如果你想接受这个答案,here's how。但是,您不需要这样做,如果仍有不清楚的地方,请随时询问。
  • @Arulprakasan 关于您的编辑:如果返回值不是NULL,则您传递给realloc() 的指针在调用后无效,这就是您必须知道的全部内容。它的值不会改变(特别是它没有设置为NULL),它只是一个你应该忘记的无效指针,如代码sn-p所示。
  • 为什么我要问这个问题,因为在某些情况下 old_ptr 可能会成为 realloc 的输入。 (old_ptr 现在无效)那是什么行为??
  • 没有人理解我的确切问题。我的问题很简单。如何避免将无效输入传递给 realloc 函数。这意味着,在之前的尝试中,realloc 已经解除分配/释放了该输入指针,它也是一个悬空指针。在相同的情况下,相同的指针作为输入传递给 realloc 那么行为是什么?我们怎样才能避免呢?
【解决方案2】:

如果成功,Realloc 将释放旧的内存块。 注意:如果它可以附加到同一个内存块中,它将自己附加到那里。如果无法追加,它将创建一个新的内存块并释放旧的。

如果你有任何循环逻辑,或者你在 realloc 完成后使用指向函数内部旧内存块的指针,那么肯定会发生崩溃。 如果旧指针只是为了重新分配而不需要。由于您已创建本地指针,并且其范围将仅限于该函数。每次调用该函数时,它将是新指针变量。

【讨论】:

  • 感谢您理解我的问题。我们如何避免将无效指针传递给 realloc 函数?这个修复应该有效吗?如果不是,还有其他解决方案吗? if (new_ptr != old_ptr ) { old_ptr = NULL; }
  • @Arulprakasan,不!这不是正确的方法。先前关于该问题的答案和 cmets 已经非常清楚地说明了原因。请退后一步,再次阅读您的问题和所有 cmets。
  • 如果 realloc 成功 old_ptr 应该重新初始化为 NULL。所以后期这个无效地址不应该被其他语句使用。例如:- void memory_allocater() { int *new_ptr = NULL;诠释 *old_ptr= NULL; old_ptr = malloc(sizeof(int) * 10); if(NULL != old_ptr) { new_ptr = (int *)realloc (old_ptr, sizeof(int)*3); if (NULL != new_ptr ) { old_ptr = NULL; } } }
  • @Rohit:感谢您的回答。似乎这也可以正常工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-19
  • 2016-05-26
  • 2014-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多