使用Valgrind在C中无效读取大小为8的分段错误

时间:2014-10-25 19:07:28

标签: c segmentation-fault gdb valgrind

我正在为一个学校项目编写一个程序,该程序使用A *搜索遍历可能状态列表并选择下一个最佳状态以继续解决。

我想明确表示我不是在寻找我的作业解决方案,而是帮助解决这些错误。我在网上看了很多其他问题,发现在某些时候地址0x0意味着我试图访问NULL因为内存不再存在。我不明白我的计划在哪里或如何发生。

我遇到了一些我无法在我的程序中使用gdb和valgrind追踪或理解的错误。

有人可以看看这些错误和我的代码,并可能说明程序段错误的原因吗?我已经坚持了很长一段时间了。

运行Valgrind的结果:

==80117== Invalid read of size 8
==80117==    at 0x4011AB: freeList (AST.c:403)

==80117==    by 0x401E24: main (main.c:129)
==80117==  Address 0x51a8dd8 is 24 bytes inside a block of size 32 free'd
==80117==    at 0x4C2701C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==80117==    by 0x400E58: removeFringe (AST.c:267)
==80117==    by 0x401DB4: main (main.c:104)
==80117==
==80117== Invalid read of size 8
==80117==    at 0x4011B7: freeList (AST.c:404)
==80117==    by 0x401E24: main (main.c:129)
==80117==  Address 0x51a8dc0 is 0 bytes inside a block of size 32 free'd
==80117==    at 0x4C2701C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==80117==    by 0x400E58: removeFringe (AST.c:267)
==80117==    by 0x401DB4: main (main.c:104)
==80117==
==80117== Invalid read of size 8
==80117==    at 0x401511: freeDiscs (discs.c:140)
==80117==    by 0x4011C1: freeList (AST.c:404)
==80117==    by 0x401E24: main (main.c:129)
==80117==  Address 0x51a8e30 is 16 bytes inside a block of size 24 free'd
==80117==    at 0x4C2701C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==80117==    by 0x401521: freeDiscs (discs.c:141)
==80117==    by 0x400E4F: removeFringe (AST.c:266)
==80117==    by 0x401DB4: main (main.c:104)
==80117==
==80117== Invalid free() / delete / delete[] / realloc()
==80117==    at 0x4C2701C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==80117==    by 0x401521: freeDiscs (discs.c:141)
==80117==    by 0x4011C1: freeList (AST.c:404)
==80117==    by 0x401E24: main (main.c:129)
==80117==  Address 0x51a8e20 is 0 bytes inside a block of size 24 free'd
==80117==    at 0x4C2701C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==80117==    by 0x401521: freeDiscs (discs.c:141)
==80117==    by 0x400E4F: removeFringe (AST.c:266)
==80117==    by 0x401DB4: main (main.c:104)
==80117==
==80117== Invalid free() / delete / delete[] / realloc()
==80117==    at 0x4C2701C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==80117==    by 0x4011CA: freeList (AST.c:405)
==80117==    by 0x401E24: main (main.c:129)
==80117==  Address 0x51a8dc0 is 0 bytes inside a block of size 32 free'd
==80117==    at 0x4C2701C: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==80117==    by 0x400E58: removeFringe (AST.c:267)
==80117==    by 0x401DB4: main (main.c:104)
==80117==
==80117==
==80117== HEAP SUMMARY:
==80117==     in use at exit: 0 bytes in 0 blocks
==80117==   total heap usage: 128 allocs, 134 frees, 3,112 bytes allocated
==80117==
==80117== All heap blocks were freed -- no leaks are possible
==80117==
==80117== For counts of detected and suppressed errors, rerun with: -v
==80117== ERROR SUMMARY: 13 errors from 5 contexts (suppressed: 4 from 4)

运行GDB的结果:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000401511 in freeDiscs (discs=0x0, MAX_SLOTS=5) at discs.c:140
140         discs = discs->next;
(gdb) backtrace
#0  0x0000000000401511 in freeDiscs (discs=0x0, MAX_SLOTS=5) at discs.c:140
#1  0x00000000004011c2 in freeList (list=0x604220, MAX_SLOTS=5) at AST.c:404
#2  0x0000000000401e25 in main (argc=2, argv=0x7fffffffe048) at main.c:129
(gdb)

从边缘删除多个具有相同状态的节点的函数:

/* removes nodes from the fringe and then returns the fringe */
struct AST_Node * removeFringe(struct AST_Node * fringe, struct AST_Node * remove, int MAX_SLOTS) {
  struct AST_Node * head, * current, * prev, * delete;
  int remove_switch = 0;
  head = fringe;
  current = fringe;
  prev = fringe;

  /* traverse the fringe until the end */
  while (current != NULL) {
    /* when the current node has the same state as the one for removal */
    if (isSame(current->state, remove->state, MAX_SLOTS)) {
      /* when removing from the head */
      if (current == head) {
        head = current->parent;
        delete = current;
        current = head;
        freeDiscs(delete->state, MAX_SLOTS);
        free(delete);
        delete = NULL;
        remove_switch = 1;
      }
      /* when the node to be removed is at the end of the list */
      else if (current->parent == NULL && current != NULL) {
        delete = current;
        current = NULL;
        freeDiscs(delete->state, MAX_SLOTS);
        free(delete);
        delete = NULL;
        remove_switch = 1;
      }
      /* when the node to be removed is in the middle of the list */
      else {
        delete = current;
        current = current->parent;
        prev->parent = current;
        /* ---- line 266 and 267 below ---- */
        freeDiscs(delete->state, MAX_SLOTS);
        free(delete);
        delete = NULL;
        remove_switch = 1;
      }
    }
    if (remove_switch == 0) {
      prev = current;
      current = current->parent;
    }
    remove_switch = 0;
  }
  return head;
}

免费列表功能:

/* free's an AST_Node list */
void freeList(struct AST_Node * list, int MAX_SLOTS) {
  struct AST_Node * current, * prev;
  current = list;
  /* when a list must be free'd, free it */
  if (current != NULL) {
    /* traverse and free until the last node */
    while (current != NULL) {
      prev = current;
      current = current->parent;
      /* ---- line 404 below ---- */
      freeDiscs(prev->state, MAX_SLOTS);
      free(prev);
      prev = NULL;
    }    
  }
}

免费光盘功能:

/* frees's a discs_slot list */
void freeDiscs(struct discs_slot * discs, int MAX_SLOTS) {
  int i = 0;
  struct discs_slot * temp;

  while (i < MAX_SLOTS) {
    temp = discs;
    discs = discs->next;
    /* ---- line 141 below ---- */
    free(temp);
    i++;
  }

}

主要相关守则:

  /* until reaching a solution or the maximum traversals allowed */
  while (!isGoal(best_current->state) && Towards_Solution < Solution_Count) {
    /* when the best current node has not already been expanded */
    if (!inClosed(closed_list, best_current, Max_Slots)) {
      /* expand it and add the nodes to the fringe */
      fringe_list = addFringe(fringe_list, best_current, goal_state, Max_Slots);
      /* add the expanded node to the closed list */
      closed_list = addClosed(closed_list, best_current);
    }
    /* when the best node is in the closed list */
    else {
      /* do nothing */
    }

    printSmallDiscs(best_current->state, Max_Slots);

    /* get a new best node to evaluate and remove it from the fringe */
    best_current = fringeTraverse(fringe_list, best_current, goal_state, Max_Slots);
    /* ---- line 104 below ---- */
    fringe_list = removeFringe(fringe_list, best_current, Max_Slots);

    Towards_Solution++;

    /* when all possible nodes have been expanded and no solution exists */
    if (fringe_list == NULL) {
      printf("No solution\n");
      break;
    }
  }



  /* return memory */
  freeDiscs(discs_list, Max_Slots);
  freeDiscs(goal_state, Max_Slots);

  freeList(best_current, Max_Slots);
  /* ---- line 129 below ---- */
  freeList(fringe_list, Max_Slots);
  freeList(closed_list, Max_Slots);

  return 0;

}

这是添加条纹函数:

/* creates new nodes from the best current state and adds those nodes to the fringe */
struct AST_Node * addFringe(struct AST_Node * list, struct AST_Node * best, struct discs_slot * goal, int MAX_SLOTS) {
  struct AST_Node * move_LCW, * move_LCCW, * move_ACW, * move_ACCW;
  struct AST_Node * current, * head, * prev;
  current = list;
  head = list;

  /* break apart the current best state for a possible solution */
    move_LCW = largeCW(best, goal, MAX_SLOTS);
    move_LCCW = largeCCW(best, goal, MAX_SLOTS);
    move_ACW = adjacentCW(best, goal, MAX_SLOTS);
    move_ACCW = adjacentCCW(best, goal, MAX_SLOTS);


  /* store these new nodes in the fringe */
  /* when storing in the fringe for the first time */
  if (current == NULL) {
    //printf("Empty Fringe:\n\n");
    current = move_LCW;
    current->parent = move_LCCW;
    current->parent->parent = move_ACW;
    current->parent->parent->parent = move_ACCW;
    current->parent->parent->parent->parent = NULL;
    //printf("List Start --------------------\n");
    //printList(current, MAX_SLOTS);
    //printf("List End --------------------\n");

  }
  /* when storing in a partially filled fringe */
  else {
    /* traverse to the end and start adding nodes from there */
    while (current != NULL) {
      prev = current;
      current = current->parent;
      //printf("*\n");
    }
    //printf("Fringe not empty new nodes added:\n\n");
    current = move_LCW;
    current->parent = move_LCCW;
    current->parent->parent = move_ACW;
    current->parent->parent->parent = move_ACCW;
    current->parent->parent->parent->parent = NULL;
    //printf("List Start --------------------\n");
    //printList(current, MAX_SLOTS);
    //printf("List End  --------------------\n");
    prev->parent = current;
    current = head;
  }

  //printf("Entire Fringe: \n\n");
  //printList(head, MAX_SLOTS);
  //printf("____________________\n");
  return current;
}

这是复制大小为MAX_SLOTS的光盘列表的函数(它最终读为NULL)

/* creates a copy of a disc slot list */
struct discs_slot * copy_dlist(struct discs_slot * discs, int MAX_SLOTS) {

  struct discs_slot * head, * current;

  current = malloc(sizeof(struct discs_slot));
  if (current == NULL) {
    printf("\nAn error ocurred when trying to allocate memory.\n");
    exit(0);
  }

  head = current;

  /* traverse for as many disc slots that exist and copy the data from
     the disc slot list passed in to the new one */
  for (int i = 0; i < MAX_SLOTS; i++) {
    current->large = discs->large;
    current->small = discs->small;
    current->position = discs->position;

    if (i < (MAX_SLOTS - 1)) {
      struct discs_slot * new_dslot;
      new_dslot = malloc(sizeof(struct discs_slot));
      if (new_dslot == NULL) {
    printf("\nAn error ocurred when trying to allocate memory.\n");
    exit(0);
      }

      current->next = new_dslot;
      current = new_dslot;
    }
    discs = discs->next;
  }

  current->next = head;
  current = head;

  return current;
}

1 个答案:

答案 0 :(得分:1)

根据问题的症状,您的程序会遇到某种无效的堆内存读取。这通常发生在我们的程序尝试读取内存free或内存free两次之后。如果我们看到Valgrind报告摘要,我们会收到以下信息:

total heap usage: 128 allocs, 134 frees, 3,112 bytes allocated

您的计划已分配 128 分配并尝试释放 134 时间。这表示程序中的双重自由场景。由于在释放内存后已将指针指定为NULL,因此稍后程序会在程序尝试访问NULL指针时遇到分段错误。

查看堆栈跟踪,几乎不可能找出导致此问题的根本原因,因为这些分段错误会在真正坏的情况发生后(在释放内存后将指针设置为NULL)完成通过早期执行中的程序。

识别这些内存损坏的最佳方法是同时使用GDBValgrind。为此,您可能希望在Valgrind / GDB中附加您的程序(a.out)。

$ valgrind --tool=memcheck --db-attach=yes ./a.out

这样,当您检测到第一个内存错误时,Valgrind会将您的程序附加到调试器中,以便您可以进行实时调试(GDB)。这应该是理解和解决问题的最佳方式。一旦你能够弄清楚你的第一个错误,修复它并重新运行它,看看你得到的其他错误。这个步骤应该完成,直到Valgrind没有报告错误。