Debugging Malloc Lab: Detecting Memory-Related Errors解答


实验三说明文档

题目:

Take Assessment: Exercise 3: Debugging Malloc Lab
Debugging Malloc Lab: Detecting Memory-Related Errors
Introduction
The usual implementation of malloc and free are unforgiving to errors in their callers' code, including cases where the programmer overflows an array, forgets to free memory, or frees a memory block twice. This often does not affect the program immediately, waiting until the corrupted memory is used later (in the case of overwrites) or gradually accumulating allocated but unused blocks. Thus, debugging can be extremely difficult.
In this assignment, you will write a wrapper for the malloc package that will catch errors in the code that calls malloc and free. The skills you will have learned upon the completion of this exercise are pointer arithmetic and a greater understanding of the consequences of subtle memory mistakes.

原文:http://blog.csdn.net/qq_34861102/article/details/78575533


  • 实验目的:

    • 本次实验的目的在于通过自己编写自定义的mallocfree函数以达到可以定位问题所在的行号,方便调试的目的
  • 实验思路

    • 首先是题目中提示要通过自定义headerfooter结构来记录在内存分配和释放中的相关信息以实现可以在问题出现的时候定位到问题的具体信息。示意图如下:

      这里写图片描述

    • 其次,实验要求中要求实现 PrintAllocatedBlocksHeapCheck 这两个函数,对于这两个函数的功能的实现则需要自己定义相关的数据结构来实现。

    • PrintAllocatedBlocks 函数要实现的是打印当前由 malloc 函数所分配的块的文件名和行号HeapCheck函数实现对当前已分配块的错误信息检查以及相关的输出。可以看到,对于这两个函数的实现都需要遍历每一个块中含有的headerfooter结构来实现,基于此,这里我想到的一个解决的方案是使用链表的结构来进行函数功能的实现。
  • 实验实现

    • header结构和footer结构的实现

      按照题目中的信息

      Information that you might want to store in this extra (header, footer) area include:
      • a "fence" immediately around the requested payload with a known value like 0xCCDEADCC, so that you can check if it has been changed when the block is freed.
      • the size of the block
      • a checksum for the header to ensure that it has not been corrupted (A checksum of a sequence of bits is calculated by counting the number of "1" bits in the stream. For example, the checksum for "1000100010001000" is 4. It is a simple error detection mechanism.)
      • the filename and line number of the MALLOC() call

      可以写出来header结构和footer结构应该含有的参数

      // the definition of header
      typedef struct {
          int checksum;
          char * filename;
          int linenumber;
          int size; // the size of payload
          int fence; // fence indicating whether writing past header
       } header;  
      
      // the definition of footer
      
      typedef struct {
          int fence; // fence indicating whether writing past footer
      } footer;
      
    • 链表结构的实现

      • 使用链表结构的同时要考虑到关联到header结构和footer结构,因此这里新定义一个结构体为链表的元素,同时初始化一个节点为链表的初始节点:

        //to record the information for the extra function
        typedef struct node {
             header *h;
             struct node *next;
        } footer_node;
        
        
        static footer_node header_node = { NULL, NULL };
    • MyMalloc函数的实现

      • 初始化headerfooter

      • 计算 headerchecksum 值,这里通过上一次实验中涉及到的相关位运算可以较为简便的计算checksum 。值得注意的是这里的tempheader的地址,要以char *的格式声明。(对于其他格式如 int *会导致进行++操作的时候导致实际地址变化大于 1),sizeheader的长度。

        while(size--) {
            // for the char the num of bits is 8
            for(int i = 0; i < 8; i++) {
                  checksum += (*temp >> i) & 0x1;
            }   
            temp ++;
        }
      • 分配地址,这里我分配地址的代码为:

        void *temp = malloc(sizeof(header) + sizeof(footer_node) + size + sizeof(footer) + BUFFER + BUFFER);

        在题目原有的基础上增加了BUFFER结构和元素FOOTER_NODE结构,原因在于:

        实际中,如果直接将链表的元素放在块之后,对于部分测试会因为相关的地址操作会修改链表的元素而导致程序的出现读写错误。(这里可以从http://danluu.com/malloc-tutorial/中看到对于malloc操作地址分配的实现,可以判断得出上述结论)因此这里元素前后增加一个BUFFER使得测试代码中的操作不会对记录链表产生影响。

        示意图如下:

        这里写图片描述

      • 向链表中添加元素

        通过向之前提到的初始链表中添加链表元素完成信息的连续记录,这里是将上面地址示意图FOOTER_NODE 加入到链表之中。 FOOTER_NODE结构中的h元素为当前块中header

        fn->h = h;
        fn->next = NULL;
        footer_node *ptmp = &header_node;
        while (ptmp->next){
            ptmp = ptmp->next;
        }
        ptmp->next = fn;
      • 依照地址示意图寻找到PAYLOAD的最低地址返回即可。

        return (void *)((char *)temp + sizeof(header));
    • MyFree函数的实现

      • 对链表中的元素进行判断,如果链表中不含当前FOOTER_NODE,则表明当前块已经被释放过了,则应该出现错误 4

        if (-1 == deleteNode(h)){
               error(4, filename, linenumber);
               return;
        }
      • 通过当前块PAYLOAD的值寻找到header

        header *h = (header *)((char *)ptr - sizeof(header));
      • 根据header包含的内容进行其余错误的判断:

        //get the footer information
        if (msize < 0)
            errorfl(3, mfilename, mlinenumber, filename, linenumber);
        else
            ffence = ((footer *)((char *)ptr + msize))->fence;
        
         //check whether writing past header
        
         if (mfence != FENCENUM) {
             errorfl(1, mfilename, mlinenumber, filename, linenumber);
          }
        
         // check whether writing past footer
         if (ffence != FENCENUM) {
             errorfl(2, mfilename, mlinenumber, filename, linenumber);
         }
        
        
         //check whether header information corrupts
         h->checksum = 0;
        
         if (CalcheckSum((char *)h, sizeof(header)) != mchecksum) {
             errorfl(3, mfilename, mlinenumber, filename, linenumber);
         }
    • PrintAllocatedBlocksHeapCheck 函数的实现

      对于PrintAllocatedBlocksHeapCheck 函数,直接对链表进行遍历,其中PrintAllocatedBlocks调用PRINTBLOCK即可

      HeapCheck 函数仿照MyFree函数进行错误的判断,其中将打印函数errorfl替换成PRINTERROR即可。


  • 实验结果

    这里写图片描述

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
调试是在编程过程中解决错误和问题的重要步骤。GNU调试器(GDB)是一种功能强大的调试工具,它允许我们在源代码级别上进行调试。 首先,为了使用GDB进行源代码级别调试,我们需要安装GDB。我们可以通过访问GNU调试器项目的官方网站,从那里下载并安装GDB软件包。 一旦安装完成,我们可以在终端中使用“gdb”命令来启动GDB调试器。然后,通过在命令行中指定可执行文件的路径,我们可以将程序加载到GDB中。 在源代码级别调试中,我们可以使用GDB的一些命令来执行不同的操作。例如,我们可以使用“break”命令设置断点,以便在程序执行时停止。我们还可以使用“run”命令开始执行程序,直到遇到断点为止。 一旦程序停止在断点处,我们可以使用GDB的其他命令来查看和修改程序状态。例如,我们可以使用“print”命令显示变量的值,以帮助我们理解程序的行为。我们还可以使用“step”命令逐行执行程序,并在每一步检查变量和代码的状态。 除了这些基本命令外,GDB还提供了许多其他功能,如条件断点、查看内存内容、查看函数调用栈等等。这些功能可以帮助我们更全面地理解程序的执行过程和错误的来源。 总之,GDB是一个强大的源代码级别调试工具,可以帮助我们解决编程过程中的错误和问题。通过使用GDB,我们可以在程序执行过程中查看和修改变量和代码的状态,以便更好地理解程序的行为和调试错误。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值