我怎样才能使用这个未分配的内存?

时间:2014-12-02 20:11:55

标签: c memory-management heap-memory

为什么我使用以下程序不会出现任何错误?

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

int main(int argc, char *argv[]){
  char *pStr = (char*) malloc(25); 
  free(pStr); 
  strcpy(pStr, "foo");
  printf("%s\n", pStr);
  return 0;
}

不应该free(pStr)阻止我写信到那个地址吗?在使用它之前,我不得不重新分配空间吗?

4 个答案:

答案 0 :(得分:9)

只要事情在语法上正确,

free就不会阻止你做任何事情。因此,如果您从未分配过内存,那么您仍然非常欢迎复制到char*。但这是未定义的行为,并且有责任(阅读:可能)导致程序崩溃或在没有警告的情况下做错事。

例如,如果您的编译器进行了一些优化,它可能会重新排序某些指令以节省时间。由于您释放了内存,编译器可能会认为在该位置为以后创建的其他数据分配内存是安全的。如果优化器移动了该分配并在此处strcpy之前写入,则可以覆盖存储在那里的对象。

考虑以下代码:

int main(int arc, char *argv[]){
    char* pStr = (char*) malloc(25);
    free(pStr);
    strcpy(pStr, "foo");
    printf("%s\n", pStr);
    int* a = (int*) malloc(sizeof(int));
    *a = 36;
    printf("%d\n", *a);
}

由于您写入了未分配的内存,因此您无法确定printf 将会显示。 36可能已经覆盖了一些&#34; foo&#34;串。 &#34; foo&#34;字符串可能已覆盖a指向的值36。或者也许它们都没有影响到另一个,你的程序运行似乎很好,直到你改变一些变量的名称并重新编译,并且由于某种原因,即使你没有改变任何东西,一切都搞砸了。

故事的道德:你不应该写入free记忆是正确的;但是,您无法写入free内存是不正确的。 C不会检查这种情况,并假设您正在尝试做一些奇特的事情。如果您确切地知道编译器在调用malloc时如何优化以及它在何处分配内存,您可能知道在特定情况下写入未分配的内存是安全的,并且C不会阻止您这样做。但是,对于99.999%的时间你不知道所有,只是不要这样做。

答案 1 :(得分:5)

这是undefined behavior。真正发生的是特定于实现的。

实际上,free经常将释放的内存块标记为可重用的malloc - s。

另见this ...

答案 2 :(得分:3)

正如其他答案所指出的那样未定义的行为,因此编译器没有义务进行任何诊断。但是,如果您使用gcc>= 4.8)或clang的现代版本,那么AddressSanitizer可能会对此有所帮助&#34;免费后使用&#34 ;错误:

$ gcc -ansi -pedantic -fsanitize=address check.c
$ ./a.out 
=================================================================
==2193== ERROR: AddressSanitizer: heap-use-after-free on address 0x60060000efe0 at pc 0x4009a8 bp 0x7fff62e22bc0 sp 0x7fff62e22bb8
...

常见的防御性编程&#34;技巧&#34;是在NULL电话后立即指定free()

free(pStr), pStr = NULL;

有了它可能会在GNU / Linux上"Segmentation fault" pStr取消引用,但不能保证这一点。

答案 3 :(得分:0)

了解您需要了解内存分配过程的问题的答案。在一般意义上,malloc / free是库函数。它们管理从操作系统服务分配的内存池。

[有过度简化的风险]

你的第一个malloc找到一个空池。然后,它调用操作系统系统服务将页面添加到要添加到池中的进程。然后,Malloc从该池中返回一块内存。

免费调用将块返回池中。它仍然是池中有效的内存块。

如果您访问免费地址,内存仍然存在。但是,你是$ $ @ $ up up malloc的内存池。这种访问最终会在#$#$。

中输入