【问题标题】:Is it valid to pass a pointer to a stack variable to realloc()?将指向堆栈变量的指针传递给 realloc() 是否有效?
【发布时间】:2010-10-13 15:16:59
【问题描述】:
int main()
{
   char myString = NULL;
   realloc(&myString, 5);
   strncpy((char *)&myString, "test", 5);
}

似乎工作正常,但我仍然对堆栈与堆有点困惑。这是允许的吗?如果允许,myString是需要手动释放还是超出范围时释放?


编辑:感谢您的回复,所以我认为这同样是非法的

//I want the code to change myString to "tests"
char myString[5] = "test";
realloc(&myString, strlen(myString)+2);
myString[4] = 's';
myString[5] = '\0';

【问题讨论】:

  • 是的,第二个变种也来自“从不这样做”部门。
  • 具体来说,你永远不应该 realloc() 一个不是 malloc()、calloc() 或 realloc() 给你的值。

标签: c++ c memory memory-management heap-corruption


【解决方案1】:

您的程序在语法上是有效的 C++,但它会产生未定义的行为,因为您将堆栈对象的地址传递给堆分配器。通常这意味着您的程序在执行时会崩溃。

堆栈和堆是分配给执行程序的进程的两个不同的内存区域。当你输入一个函数来保存它的参数和局部变量时,堆栈会增长,当你从函数返回时它会自动收缩。另一方面,堆是一个单独的地址区域,可以按需获取内存,并且必须在不再需要时显式释放。

如果将局部变量的地址传递给 realloc(),它可能会尝试释放其内存并将其分配到其他地方。由于地址不是来自堆,而 realloc() 在堆上操作,这将失败。 realloc() 很可能会检测到地址不是来自堆并中止程序。


除此之外,示例程序还包含一些逻辑错误。


char myString = NULL;

您声明一个变量来保存一个字符,而不是一个字符串。 C 风格字符串的类型为 char*,即指向 char 的指针。

此外,char 被分配NULL,通常分配给无效指针的地址零。这是因为预处理器将NULL 替换为文字0。实际上,您在 char 中存储了一个零字节,按照惯例,它也是 C 样式字符串的终止符。


realloc(&myString, 5);

如上所述,这是非法的,因为您将堆栈对象的地址传递给堆分配器。这个问题仍然存在于您的第二个代码示例中。

此外,您丢弃了返回值。 realloc() 返回分配新内存的地址。它可能与以前的地址不同。它甚至可能是 NULL,这是 realloc() 告诉您它内存不足的方式。


strncpy((char *)&myString, "test", 5);

这是正确的,但演员表是多余的。


这是您的程序的更正确版本:


#include <stdlib.h>
#include <string.h>

int main()
{
   /* allocate space for, say, one character + terminator */
   char* myString = (char*) malloc(2);

   /* some code using myString omitted */

   /* get more space */
   myString = (char*) realloc(myString, 5);

   /* write to the string */
   strncpy(myString, "test", 5);

   /* free the memory */
   free(myString);

   return 0;
}

在 C++ 中,最好完全避免 realloc()。例如,您可以使用如下内容:


#include <string>

int main()
{
   std::string myString;

   /* some code using myString */

   myString = "test";

   return 0;
}

【讨论】:

    【解决方案2】:

    这应该行不通。您正在重新分配一开始没有分配的东西。不,当它超出范围时它不会被释放 - 当你使用 malloc 或 realloc 时,这完全取决于你。

    更新:您的编辑不会改变任何东西 - 您仍在尝试重新分配一开始没有分配的东西。此外,您不能忽略 realloc 的返回值 - 如果 realloc 必须将内存移动到其他地方,您会在返回中找到它。换句话说:

    char* ptr = malloc(4);
    ptr = realloc(ptr, 5);
    

    在 realloc 之后,ptr 可能指向内存中完全不同的位置,继续使用 ptr 的原始值可能会让您使用已被释放且没有您想象的那么大的内存。

    【讨论】:

    • 这很好。 realloc() 是一个非常通用的函数(在我看来太通用了),并且会进行所有的内存管理。
    • @David,不是不行 - realloc 可以重新分配指针,你不能像那样重新分配堆栈上的变量。
    • 嗯,不好 - 我没有注意到 &myString。绝对不行。
    • @Paul,你不应该使用临时指针变量来存储 realloc 的返回值吗,如果它返回 NULL,你的原始内存仍然会被分配并且永远不会被释放。
    【解决方案3】:

    响应您的第二个代码示例:

    是的,这也是非法的。 myString 不是用 malloc(或 calloc)分配的,所以不能用 realloc 重新分配,也不能用 free 释放。

    另外,realloc 不会将指向指针的指针作为其第一个参数。它需要一个指向已分配内存的指针,并返回另一个(可能不同的)指针。改为这样编写调用:

    myString = realloc(myString, strlen(myString)+2);
    

    【讨论】:

      【解决方案4】:

      您发布的代码存在一些问题:

      • 是的,您需要释放使用 malloc、realloc 和其他相关的 C 风格内存分配函数分配的所有内容。
      • 我认为您的意思是使用 char *myString,而不是 char。传入堆栈上某些东西的地址(你的字符)是完全错误的。
      • 在 realloc 中使用之前,您需要将 myString char 指针初始化为 NULL。
      • 你应该将 4 传递给 strncpy 而不是 5,如果你有一个更大的字符串你会覆盖内存。
      • 您应该释放您在示例中创建的缓冲区
      • 您应该检查 realloc 调用的返回值。重新定位()

      [关于 realloc 的返回值:] 成功完成后用 size 不等于 0,realloc() 返回一个 指向(可能已移动)的指针 分配的空间。如果大小为 0,则 空指针或唯一指针 可以成功传递给 free() 被返回。如果没有 足够的可用内存,realloc() 返回一个空指针并设置 errno 到 [ENOMEM]。

      • 当你传入 NULL 时,re-alloc 将像 malloc 一样工作:

      如果 ptr 是空指针,realloc() 行为类似于 malloc() 的 指定大小。

      更多的 C++ 方式:

      尽管您将其标记为 C++,但使用 C++ 的 new 运算符更安全。尽管 new 运算符不允许重新分配,但它可以用于分配和重新使用现有缓冲区(放置新)。

      char *myString = new char[5];
      strncpy(myString, "test", 4); 
      //...
      delete[] myString;
      

      甚至:

      #include <string>
      
      //...
      
      std::string str = "test";
      

      Source of top 2 quotes

      【讨论】:

      • 定义为使用带 NULL 的 realloc()。您可以使用 realloc() 进行所有 C 内存管理。这是否是个好主意是另一个问题。
      • 到目前为止,您是唯一一个提到这甚至不是 C++ 管理内存的方式的人。你会得到我的 +1。
      【解决方案5】:

      您正在做的事情的问题是您正在处理不是变量的东西。您将 myString 定义为 char,因此试图更改其地址。这很糟糕。

      函数 realloc() 不应该改变传递给它的任何东西。它需要一个指向堆上某个内存的指针(或空指针,如果尚未分配任何内容)并返回一个指向堆上某个内存的指针。

      因此,您提供空指针或指向由 malloc() 或 realloc() 或 calloc() 分配的内容的指针,并存储返回的指针。

      有点像

      char * myString = NULL;
      myString = realloc(myString, 5);
      

      会起作用,但你会想要 free() myString。

      但是,在 C++ 中,使用 std::string。

      【讨论】:

        【解决方案6】:

        这是你永远不应该做的。尝试 free() 或 realloc() 堆栈变量可能导致未定义的行为,包括(但不限于)损坏的堆栈(导致不可预测的控制流)、损坏的堆服务结构、损坏的用户内存。如果程序只是与 AV 一起崩溃,那你就很幸运了。在某些情况下它可能会起作用,但您永远不应该尝试这样做。

        经验法则:仅将内存返回给分配它的内存管理器。在这种情况下,不要尝试将堆栈变量返回到运行时堆。

        【讨论】:

          【解决方案7】:

          您不必释放myString,因为它在堆栈上(离开作用域时会“释放”)。

          realloc 在这里是非法的,地址必须是 NULL 或之前调用 reallocmalloccalloc 返回的地址。

          你声明的每一个变量都在栈上,甚至是一个指针:

          int *x;

          变量x 在堆栈上!它是pointer 类型并拥有一个地址。

          x = (int *)malloc(sizeof(int));

          malloc返回的地址赋值给变量x! x的内容是一个内存地址!

          【讨论】:

            【解决方案8】:

            这很危险!这会破坏你的堆栈。如果您要在返回 main() 的函数的堆栈上重新分配某些内容,则实际上最终会覆盖堆栈帧并返回 main() 以外的其他位置。这是一个潜在的安全漏洞。

            尝试运行以下命令。如果它在 realloc 上崩溃,你很幸运。你可以用 memcpy(&myString) 之类的东西造成严重的损害。

            int dostuff();
            
            int main()
            {
                    dostuff();
                    return 0;
            }
            
            int dostuff()
            {
                    char myString = NULL;
                    realloc(&myString, 5);
                    strncpy((char *)&myString, "test", 5);
                    return 0;
            }
            

            【讨论】:

              【解决方案9】:

              不,这是完全错误的。 realloc 应该只用于重新分配 malloc 分配的内存,你所做的只是偶然的,最终会严重崩溃

              char *myString = malloc(x);
              myString = realloc(myString,y);
              free(myString)
              

              不过,最好使用 new 和 delete,甚至最好使用 std::string。

              【讨论】:

              • 你也可以使用 "char *myString = NULL;"并重新分配一个空指针。
              猜你喜欢
              • 2013-04-14
              • 1970-01-01
              • 2021-12-04
              • 2013-07-21
              • 2020-01-03
              • 1970-01-01
              • 2012-01-18
              • 2013-05-14
              • 1970-01-01
              相关资源
              最近更新 更多