内存分配违规后free()的奇怪行为
就在不久前,我正在寻找一些我正在编写的大型图书馆中的一个错误,它耗费了我很长一段时间.问题是我违反了某些结构成员的内存界限,但是它没有出现分段错误或只是一个简单的崩溃,而是出了意想不到的事情(至少我没想到).让我举一个例子:
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. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |