加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-16 09:50:06 所属栏目:百科 来源:网络整理
导读:就在不久前,我正在寻找一些我正在编写的大型图书馆中的一个错误,它耗费了我很长一段时间.问题是我违反了某些结构成员的内存界限,但是它没有出现分段错误或只是一个简单的崩溃,而是出了意想不到的事情(至少我没想到).让我举一个例子: segmentation_fault.c #
就在不久前,我正在寻找一些我正在编写的大型图书馆中的一个错误,它耗费了我很长一段时间.问题是我违反了某些结构成员的内存界限,但是它没有出现分段错误或只是一个简单的崩溃,而是出了意想不到的事情(至少我没想到).让我举一个例子:

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 faultn");
        memory[memorySize] = 0x0D; /* segmentation fault */
        if (segmentationFaultFlag)
            exitError("detected segmentation fault");
        printf("After segmentation faultn");
        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);
}

我们可以看到行内存[memorySize] = 0x0D;显然违反了malloc()给出的内存界限,但它不会崩溃或引发信号(我知道根据ISO C99 / ISO C11,信号处理是实现定义的,并且在违反内存边界时根本不需要引发) .它在打印线条上移动后分段出现故障,在free()和After free()之前,但经过几次迭代之后它会崩溃,总是处于free()(打印后分段故障和之前free(),但不是免费之后) ()).我想知道导致这种行为的原因是什么,以及检测内存访问违规的最佳方法是什么(我很惭愧,但我总是使用printfs来确定程序崩溃的位置,但确定必须有更好的工具来执行此操作),因为它非常难以检测(通常它不会在违规代码中崩溃,但是,如在示例中,稍后在代码中,当尝试再次对此内存执行某些操作时).当然我应该能够释放这个内存,因为我正确分配它并且没有修改指针.

解决方法

在内存中读取或写入时,您不会拥有未定义的行为.

这并不总是导致分段错误.在实践中,代码更有可能破坏其他一些数据,并且您的程序将在某些其他地方崩溃,这使得难以调试.

在此示例中,您写入了无效的堆地址.您可能会损坏一些内部堆结构,这可能会导致程序在任何后续malloc或free调用时崩溃.

有一些工具可以检查您的堆使用情况,并且可以告诉您是否写出了边界.我喜欢并建议使用valgrind for linux和gflags for windows.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读