在栈内存上使用free()函数

12

我正在支持一些在Solaris系统上的C代码,并且我看到了一些奇怪的东西,至少我认为是这样:

char new_login[64];
...
strcpy(new_login, (char *)login);
...
free(new_login);

我的理解是,由于变量是一个本地数组,内存来自堆栈,不需要释放,而且由于没有使用malloc/calloc/realloc,行为是未定义的。

这是一个实时系统,所以我认为这是浪费时间。我是否错过了什么明显的东西?


21
这篇文章是谁写的?那个人应该被 free() 了。 - kennytm
1
这是一个bug,但是有可能free知道堆的边界并能够发现它。这个项目也有可能有一个堆分配库,它可以进行垃圾回收,而free要么什么都不做,要么就像#define free(x) (x=NULL)一样成为一个宏。 - nategoose
1
@nategoose:如果是这样,那么它就不是那个宏,因为 new_login = 0 不应该编译。 - Steve Jessop
可能是https://dev59.com/8nE85IYBdhLWcg3wnU6p的重复问题,为什么我不能在未通过malloc分配的变量上调用free? - N 1.1
5个回答

23

只有从malloc()、calloc()或realloc()函数获取的内存才能使用free()函数释放。在堆栈上释放内存会导致未定义的行为,你很幸运这没有导致程序崩溃或更糟糕的后果。

把这种操作视为严重的错误,并尽快删除该行代码。


6
请考虑这是一个严重的错误,并尽快删除那行代码。如果当前代码能正常运行,我会尝试弄清楚为什么才会进行更改。可能是我严重误解了某些东西(比如说也许其中一个标记实际上是“new_login”或其他内容)。我可能会浪费时间,但我就是那么多疑。;-) - Steve Jessop
1
也许,free 检查指针的范围,并且当它来自堆之外的区域时不执行任何操作。在我看来这不是一个好主意,但谁知道实现者的想法(在我以前的嵌入式程序员生涯中,我甚至在我们的某个采集控制器上实现了这种行为)。 - Patrick Schlüter
1
同意,但在特定实现上,“也许”变成了“要么是,要么不是”。我总是想知道实践中可以检测到哪些类型的错误,以及哪些类型不能被检测到,因为这样可以更容易地智能调试未来的问题。 - Steve Jessop
如果您要将该测试放入您的free()实现中,那么您可能需要采取更多措施来处理它,而不是“默默忽略”。 - caf
1
有可能这不是一个错误。Malloc钩子可以本质上定义与标准中定义的free行为不同的行为。 - Yktula

9

不,这是一个bug。

根据free(3)的说明...

free()函数释放ptr指向的内存空间,该指针必须是之前通过malloc()、calloc()或realloc()返回的。否则,如果之前已经调用了free(ptr),或者ptr为NULL,则会出现未定义的行为。

因此,你的程序中出现了未定义的行为。


4
在大多数情况下,你只能释放在堆上分配的东西。请参见http://www.opengroup.org/onlinepubs/009695399/functions/free.html
然而:一种实现你想要做的事情的方法是对在栈上分配的临时变量进行作用域限定。如下所示:
{
char new_login[64];
... /* No later-used variables should be allocated on the stack here */
strcpy(new_login, (char *)login);
}
...

4

The free() is definitely a bug.
However, it's possible there's another bug here:


   strcpy(new_login, (char *)login);

If the function isn't pedantically confirming that login is 63 or fewer characters with the appropriate null termination, then this code has a classic buffer overflow bug. If a malicious party can fill login with the right bytes, they can overwrite the return pointer on the stack and execute arbitrary code. One solution is:


   new_login[sizeof(new_login)-1]='\0';
   strncpy(new_login, (char *)login, sizeof(new_login)-1 );

3

这绝对是一个bug。除非free()重新定义以执行完全不同的操作(我怀疑这种情况),否则它必须仅用于堆分配的内存。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接