簡體   English   中英

使用Valgrind在C中無效讀取大小8的分段錯誤

[英]Segmentation Fault with invalid read of size 8 in C with 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;
}

根據問題的症狀,您的程序遇到某種無效的堆內存讀取。 這通常只要我們的程序試圖讀取之后,我們有發生free內存或free內存的兩倍。 如果看到Valgrind報告摘要,則將獲得以下信息:

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

您的程序分配了128個分配,並嘗試釋放134個時間。 這表示您的程序中出現雙重免費的情況。 由於在釋放內存后為指針分配了NULL,因此稍后某處的程序遇到分段錯誤,而程序嘗試訪問NULL指針。

查看堆棧跟蹤,幾乎不可能找出造成此問題的根本原因,因為這些分段錯誤將是由程序中完成的某些實際不良事件(釋放內存后將指針設置為NULL)造成的。早期執行。

識別這些內存損壞的最佳方法是一起使用GDBValgrind 為此,您可能需要將程序(a.out)附加到Valgrind / GDB中。

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

這樣,當檢測到您的第一個內存錯誤時,Valgrind會將程序附加到調試器中,以便您可以進行實時調試(GDB)。 這應該是理解和解決問題的最佳方法。 一旦能夠找出您的第一個錯誤,就將其修復並重新運行,然后查看您還遇到了其他錯誤。應該執行此步驟,直到Valgrind報告沒有錯誤為止。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM