C:分段错误:GDB:

我有一个函数shortestPath(),它是Dijkstra算法的修改实现,用于我正在为我的comp2类工作的棋盘游戏AI。 我已经浏览了网站并使用gdb和valgrind我确切知道了段错误发生的位置(几小时前就知道了),但无法弄清楚导致问题的是什么未定义的行为或逻辑错误。

发生问题的函数被调用大约10倍并按预期工作,直到它与GDB发生段错误:“错误读取变量:无法访问内存”和valgrind:“读取大小为8的无效”

通常情况下这就足够了,但我无法解决这个问题。 也欢迎任何一般建议和提示…谢谢!

GDB: https : //gist.github.com/mckayryan/b8d1e9cdcc58dd1627ea
Valgrind: https : //gist.github.com/mckayryan/8495963f6e62a51a734f

以下是发生段错误的function:

static void processBuffer (GameView currentView, Link pQ, int *pQLen, LocationID *buffer, int bufferLen, Link prev, LocationID cur) { //printLinkIndex("prev", prev, NUM_MAP_LOCATIONS); // adds newly retrieved buffer Locations to queue adding link types appendLocationsToQueue(currentView, pQ, pQLen, buffer, bufferLen, cur); // calculates distance of new locations and updates prev when needed updatePrev(currentView, pQ, pQLen, prev, cur); <--- this line here qsort((void *) pQ, *pQLen, sizeof(link), (compfn)cmpDist); // qsort sanity check int i, qsortErr = 0; for (i = 0; i  pQ[i+1].dist) qsortErr = 1; if (qsortErr) { fprintf(stderr, "loadToPQ: qsort did not sort succesfully"); abort(); } } 

以及在它被称之后一切都崩溃的function:

 static void appendLocationsToQueue (GameView currentView, Link pQ, int *pQLen, LocationID *buffer, int bufferLen, LocationID cur) { int i, c, conns; TransportID type[MAX_TRANSPORT] = { NONE }; for (i = 0; i gameMap, cur, buffer[i], type); for (c = 0; c < conns; c++) { pQ[*pQLen].loc = buffer[i]; pQ[(*pQLen)++].type = type[c]; } } } 

所以我认为指针已被覆盖到错误的地址,但在GDB中进行了大量打印后似乎并非如此。 我还通过对有问题的变量进行读/写操作来查看哪个触发了错误,并且它们都是在appendLocationsToQueue()之后,但不是之前(或者在该函数结束时)。

以下是相关代码的其余部分:shortestPath():

 Link shortestPath (GameView currentView, LocationID from, LocationID to, PlayerID player, int road, int rail, int boat) { if (!RAIL_MOVE) rail = 0; // index of locations that have been visited int visited[NUM_MAP_LOCATIONS] = { 0 }; // current shortest distance from the source // the previous node for current known shortest path Link prev; if(!(prev = malloc(NUM_MAP_LOCATIONS*sizeof(link)))) fprintf(stderr, "GameView.c: shortestPath: malloc failure (prev)"); int i; // intialise link data structure for (i = 0; i roundNum, road, rail, boat); // mark current node as visited visited[cur] = VISITED; // locations from buffer are used to update priority queue (pQ) // and distance information in prev processBuffer(currentView, pQ, &pQLen, buffer, bufferLen, prev, cur); } free(buffer); free(pQ); return prev; } 

在此行之前所有参数看起来都很好的事实:

 appendLocationsToQueue(currentView, pQ, pQLen, buffer, bufferLen, cur); 

在它告诉我你已经0x7fff00000000 (写入0x7fff00000000到) $rbp寄存器之后变得不可用(所有局部变量和参数在没有优化的情况下构建时相对于$rbp )。

您可以在调用appendLocationsToQueue之前和之后使用print $rbp在GDB中确认这appendLocationsToQueue$rbp应该在给定函数内始终具有相同的值,但会更改)。

假设这是真的,只有几种方法可以发生,最可能的方式是appendLocationsToQueue (或它调用的东西)中的堆栈缓冲区溢出。

您应该能够使用Address Sanitizer( g++ -fsanitize=address ... )轻松找到此错误。

在GDB中找到溢出也相当容易:进入appendLocationsToQueue ,并watch -l *(char**)$rbpcontinue 。 当您的代码覆盖$rbp保存位置时,应该触发观察点。