C - 在内存被释放()之后访问数据?

Pet*_*ete 6 c malloc free pointers

我在标准 C 中阅读了很多关于 malloc() 和 free() 的内容。据我所知,你只malloc()需要一次内存,然后你只free()需要一次相同的内存。这可能是不好的做法,但我知道在你malloc()记忆之后,你可以定义多个指向它的指针。一旦你找到free()任何这些指针,分配的内存就会被取消分配?

考虑这个玩具示例:

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

int main(){

    char* p = (char*)malloc(10 * sizeof(char));     // allocate memory
    int* q = (int*)p;                               // pointer to the same block of memory
    *p = 'A';                                       // Input some data
    printf("TEST::  %c %d\n", *p, *q);              // Everything's ok so far...
    free(p);                                        // free() my allocated memory?
    sleep(10);                                      // wait
    printf("%c\n", *q);                             // q now points to de-allocated memory
                                                    // shouldn't this segfault?

    free(q);                                        // *** SEGFAULTS HERE ***

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出是:

[Linux]$ ./a.out
TEST::  A 65

*** Error in `./a.out': double free or corruption (fasttop): 0x0000000001ac4010 ***
======= Backtrace: =========
...lots of backtrack info...
Run Code Online (Sandbox Code Playgroud)

所以我假设当我free()第一个指针时,内存被认为是free()ed,但是我在这个内存块中写入的数据值仍然“存在”,这就是为什么我可以通过第二个指针访问它们?

(我不是建议这是一个好主意,我试图理解系统的逻辑。)

Jay*_*mat 5

当你 malloc 内存时,你会得到一个指向某个空间的指针,当你释放它时,你将它归还给系统。通常,您仍然可以访问此内存,但是在释放内存后使用它是非常糟糕的。

确切的行为未定义,但在大多数系统上,您可以继续访问内存,或者出现段错误。

您可以尝试的一项有趣实验是在释放该指针后尝试分配更多内存。在我尝试过的大多数系统上,你会得到相同的块(这是一个问题,如果你依赖于释放块中的数据)。您的程序最终会使用这两个指针,但由于它们指向相同的物理数据,您将覆盖自己的数据!

这样做的原因是,当你 malloc 数据时(当然取决于 malloc 的实现),malloc 首先从操作系统请求一个数据块(通常比 malloc 请求大得多),malloc 会给你一部分记忆。不过,您将能够访问最初从操作系统获得的内存 malloc 的任何部分,因为对于操作系统而言,它是您的程序在内部使用的所有内存。当您释放时,您是在告诉 malloc 系统该内存是空闲的,并且可以稍后返回给程序。

在 malloc 区域外写是很危险的,因为

  1. 它可能会出现段错误,具体取决于您的 c 实现
  2. 您可以覆盖 malloc 所依赖的元数据结构,当您稍后释放/ malloc 更多数据时,这会导致非常糟糕的问题

如果您有兴趣了解更多信息,我建议您通过泄漏检测器 valgrind 运行您的程序,以更好地了解已释放/未释放的内容。

PS:在没有操作系统的系统上,您很可能根本不会遇到段错误,并且您将能够在任何地方随意使用。操作系统负责触发段错误(当您写入/读取您无权访问的内存时,例如内核或受保护的内存)

如果您有兴趣了解更多信息,您应该尝试编写自己的 malloc,和/或阅读/了解内存管理操作系统所做的工作。