c - 内存分配违规后 free() 的奇怪行为

标签 c memory-management segmentation-fault

不久前,我在我编写的某个大型数字库中寻找错误,这让我花了很多时间。问题是我违反了某些结构成员的内存边界,但不是 段错误 或只是普通的崩溃,它做了一些意想不到的事情(至少我没想到)。让我举个例子:

segmentation_fault.c

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>

#define N 100 /* arbitrary large number */

typedef unsigned char byte;

void exitError(char *);
void segmentationFaultSignalHandler(int);

sig_atomic_t segmentationFaultFlag = 0;


int main(void)
{
    int i, memorySize = 0;
    byte *memory;
    if (setvbuf(stdout, NULL, _IONBF, 0))
        exitError("setvbuf() failed");
    if (signal(SIGSEGV, segmentationFaultSignalHandler) == SIG_ERR)
        exitError("signal() failed");
    for (i = 0; i < N; ++i)
    {
        printf("Before malloc()\n");
        if ((memory = malloc(++memorySize * sizeof(byte))) == NULL)
            exitError("allocation failed");
        printf("After malloc()\n");
        printf("Before segmentation fault\n");
        memory[memorySize] = 0x0D; /* segmentation fault */
        if (segmentationFaultFlag)
            exitError("detected segmentation fault");
        printf("After segmentation fault\n");
        printf("Before free()\n");
        free(memory);
        printf("After free()\n");
    }
    return 0;
}


void segmentationFaultSignalHandler(int signal)
{
    segmentationFaultFlag = 1;
}


void exitError(char *errorMessage)
{
    printf("ERROR: %s, errno=%d.\n", errorMessage, errno);
    exit(1);
}

正如我们所见,memory[memorySize] = 0x0D; 行显然违反了 malloc() 给定的内存边界,但它不会崩溃或引发信号(我知道根据 ISO C99/ISO C11,信号处理是实现定义的,并且在违反内存边界时根本不必提高)。它继续打印 After segmentation faultBefore free()After free() 行,但经过几次迭代后它崩溃了, 始终在 free() (打印 After segmentation faultBefore free(),但不打印 After free()).我想知道是什么导致了这种行为,以及检测内存访问违规的最佳方法是什么(我很惭愧,但我总是有点用 printf 来确定程序崩溃的位置,但肯定有更好的工具来做到这一点)因为它很难检测(通常它不会在违规代码处崩溃,但是,如示例所示,在代码的后面,当再次尝试使用此内存执行某些操作时)。当然,我应该能够释放这 block 内存,因为我正确地分配了它并且没有修改指针。

最佳答案

您只能在伪造的环境中检测违规行为。 在这种情况下,您违反了从系统中获得的内存,您将无法再相信任何事情。因为现在发生的所有事情都是未定义的行为,你不能期望会发生什么,因为没有任何规则。

因此,如果您想检查程序是否存在内存泄漏或某些读/写违规。您必须编写一个程序来获取属于它的内存区域,并将该区域的一部分提供给“待检查”程序。您必须检查进程并跟踪它写入和读入我们内存的位置,并且您必须使用内存的另一部分来检查是否允许在那里读写(即在您的伪造环境中通过设置一些 FLAGS 并检查它们是否已更改)。

因为如果程序离开你拥有的区域。你不能确定你是否会检测到这种行为。 所以你必须自己做内存管理来检查这种行为。

关于c - 内存分配违规后 free() 的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21330233/

相关文章:

C编程将链表分成两半

c - 删除二叉搜索树的叶节点 - segmentation fault

c++ - 使用 NULL 值初始化内存块是否等同于 free?

C 列表插入程序 - 运行时出现段错误

c - 为取消引用的双指针赋值时出现段错误

c++ - 确定导致段错误的代码行?

c - 使用 longjmp 在 Lua 中处理错误

c++ - 如何将字符串(字符数组)中的 UUID 转换为静态 uint8_t adv_data[31]

c# - Hashtable 的内存是如何分配的?

memory-management - gfortran傻瓜版:mcmodel = medium到底能做什么?