图2. Heap的包装数据组织以检测是否heap被破坏 图2中的size域值是用于free()函数来找到该魔幻数字的,如下面的实例代码所示。包装函数用8个字节的额外开销来记载heap的结构。下例重新实现了C++中的new和delete函数。 #include <stdint.h> #include <stdlib.h> #define MAGIC_NUMBER 0xefdcba98 uint32_t myMallocMaxMem; void* MyMalloc(size_t bytes) { uint8_t *p, *p_end; static uint8_t* mLow = (uint8_t*)0xffffffff; /* lowest address returned by malloc() */ static uint8_t* mHigh; /* highest address + data returned by malloc() */ bytes = (bytes + 3) & ~3; /* ensure alignment for magic number */ p = (uint8_t*)malloc(bytes + 8); /* add 2x32-bit for size and magic number */ if (p == NULL) { abort(); /* out of memory */ } *((uint32_t*)p) = bytes; /* remember size */ *((uint32_t*)(p + 4 + bytes)) = MAGIC_NUMBER; /* write magic number after user allocation */ /* crude method of estimating maximum used size since application start */ if (p < mLow) mLow = p; p_end = p + bytes + 8; if (p_end > mHigh) mHigh = p_end; myMallocMaxMem = mHigh - mLow; return p + 4; /* allocated area starts after size */ } void MyFree(void* vp) { uint8_t* p = (uint8_t*)vp - 4; int bytes = *((uint32_t*)p); /* check that magic number is not corrupted */ if (*((uint32_t*)(p + 4 + bytes)) != MAGIC_NUMBER) { abort(); /* error: data overflow or freeing already freed memory */ } *((uint32_t*)(p + 4 + bytes)) = 0; /* remove magic number to be able to detect freeing already freed memory */ free(p); } #ifdef __cplusplus // global override of operator new, delete, new[] and delete[] void* operator new (size_t bytes) { return MyMalloc(bytes); } void operator delete (void *p) { MyFree(p); } #endif 需要说明的是,上面的实例能避免之前提到的错误是在分配的内存也被释放的前提下。但有些应用并不如此,这就需要添加另外的域来维护当前系统中分配的内存区域,然后周期性的验证分配内存记录的合理性。这个附加的列示当前动态内存分配的表不会太长因为对于嵌入式系统而言,只需要使用次数相对较少的动态内存。 |
|