本研究在Malloc调试实验室环境中,专注于检测与内存相关的错误,旨在提高程序稳定性和安全性。通过分析和实验,提出有效的解决方案来识别并修正内存使用问题。
介绍
在标准C库中的`malloc()` 和 `free()`函数的常规实现对调用它们的代码中的错误非常严格,包括程序员溢出数组、忘记释放内存或两次释放同一块内存等情况。这些情况往往不会立即影响程序运行,而是等到被篡改过的内存再次使用时才会出现问题(在覆盖的情况下)或者逐渐累积分配但未使用的区块。因此,在调试过程中会变得极其困难。
在这次作业中,你需要为`malloc()` 包装器编写一个错误检测层,该包装器可以捕捉调用 `malloc() 和 free()` 函数的代码中的错误。完成此练习后你将掌握指针运算和对细微内存问题后果的理解技能。
物流
下载并解压debugging_malloc.zip文件到空目录中。其中包含以下文件:
- debugmalloc.c:包含了你需要实现的三个函数。
- debugmalloc.h:定义了这些函数以及调用它们的宏。
- driver.c:包含主程序和将调用 `malloc()` 包中的功能代码
- dmhelper.c 和 dmhelper.h: 这些是辅助函数,你将在自己的代码中使用到
- grader.pl : 一个Perl脚本,用于运行你的代码并基于当前的实现给出反馈。
- debugmalloc.dsp, debug_malloc.dsw:这是练习3项目文件和工作区文件。
说明
程序将通过调用 `MALLOC` 和 `FREE` 宏来使用这个包。这两个宏就像标准C库中的 `malloc()` 和 `free()` 函数一样被使用,例如:
```c
void *ptr = MALLOC(n);
```
会分配至少n字节的内存,并且 ptr 指向这块内存的前端。
调用
```c
FREE(ptr);
```
会使指针指向的那块内存释放并可供后续使用。宏定义如下:
```c
#define MALLOC(s) MyMalloc(s, __FILE__, __LINE__)
#define FREE(p) MyFree(p, __FILE__, __LINE__)
```
`__FILE__` 宏解析为当前文件名,而 `__LINE__` 解析为当前行号。
debugmalloc.c 文件包含以下三个需要实现的函数:
```c
void *MyMalloc(size_t size, char *filename, int linenumber);
void MyFree(void *ptr, char *filename, int linenumber);
int AllocatedSize();
```
默认情况下, `MyMalloc()` 和`MyFree()` 分别调用标准库中的`malloc()`和`free()`, 并立即返回。函数 `AllocatedSize()` 应该返回当前用户分配的字节数:通过MALLOC请求的总字节减去FREE释放的字节数。
默认情况下,它只返回0并且未实现。
你的任务是修改这些功能,以便捕获以下将描述的一系列错误。
此外,在 debugmalloc.c 文件中还有两个可选函数可以实现:
- `void PrintAllocatedBlocks();`
- `int HeapCheck();`
`PrintAllocatedBlocks()` 应该打印出所有已分配块的信息。
`HeapCheck()`应该检查所有区块,以查找可能的内存覆盖。
实施细节
为了捕捉错误,你需要稍微多一点的空间,并且在“请求负载”周围插入一个头和尾。 `MyMalloc() `将在这些区域中存储信息,而 `MyFree() `将查看该信息是否未更改。
错误包括:
1. 在用户区块的开头写入(通过围栏)
2. 写入到用户块结尾外
3. 头部数据被破坏
4. 尝试释放未分配或已释放的区块
5. 内存泄漏检测
为了报告前四个错误,调用以下函数之一:
```c
void error(int errorcode, char *filename, int linenumber);
```
`errorfl()` 与 `error() 类似,但它有两个文件名和行号集,一个用于分配语句所在的文件名/行号(malloc),另一个用于释放语句所在的文件名/行号(错误发生处)。
当你的程序能够捕捉所有这些错误后,你可以进一步创建全局区块列表。这将允许你对内存泄漏进行分析,并检查当前已分配的内存。
评估
总共有7个测试用例可以使用,还有一个额外用于测试全局列表。通过输入 `debugmalloc -t n` 来运行第n个测试。
一旦你能捕捉所有这些错误并实现可选功能,你的代码将能够提供更详细的错误报告和更好的调试支持。