[英]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)造成的。早期執行。
識別這些內存損壞的最佳方法是一起使用GDB
和Valgrind
。 為此,您可能需要將程序(a.out)附加到Valgrind / GDB中。
$ valgrind --tool=memcheck --db-attach=yes ./a.out
這樣,當檢測到您的第一個內存錯誤時,Valgrind會將程序附加到調試器中,以便您可以進行實時調試(GDB)。 這應該是理解和解決問題的最佳方法。 一旦能夠找出您的第一個錯誤,就將其修復並重新運行,然后查看您還遇到了其他錯誤。應該執行此步驟,直到Valgrind報告沒有錯誤為止。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.