2015-10-14 65 views
2

我有一個函數shortestPath(),這是Dijkstra算法的修改實現,用於棋盤遊戲AI我正在爲我的comp2類工作。我瀏覽了網站,並使用gdb和valgrind,我確切地知道段錯誤發生的位置(實際上幾個小時前就知道這一點),但無法弄清楚未定義的行爲或邏輯錯誤是如何導致問題的。C:分段錯誤:GDB:<錯誤讀取變量>

中發生的問題是圍繞10倍打來電話,工作正常,直到它與GDB出現segfaults功能: 「錯誤讀取變量:無法訪問存儲」 和Valgrind的:

「大小8的無效讀」

通常情況下就夠了,但我無法完成這一項。還有任何一般的意見和建議表示讚賞......謝謝!

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

這裏是在其中發生的段錯誤的功能:

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 < *pQLen-1; i++) 
     if (pQ[i].dist > pQ[i+1].dist) qsortErr = 1; 
    if (qsortErr) { 
     fprintf(stderr, "loadToPQ: qsort did not sort succesfully"); 
     abort(); 
    } 
} 

和功能,由此之後它被稱爲一切散開:

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 < bufferLen; i++) { 
     // get connection information (up to 3 possible) 
     conns = connections(currentView->gameMap, cur, buffer[i], type); 
     for (c = 0; c < conns; c++) { 
      pQ[*pQLen].loc = buffer[i]; 
      pQ[(*pQLen)++].type = type[c];    
     }    
    } 
} 

所以我認爲一個指針已被覆蓋到錯誤的地址,但之後GDB中的大量印刷似乎並非如此。我還通過對所討論的變量進行讀/寫操作來查看哪些觸發了錯誤,並且它們都在appendLocationsToQueue()之後執行,而不是在此之前(或者在該函數結束時)執行。

下面是相關代碼的其餘部分:) 最短路徑(:

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

,並變得不可用它告訴後:

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 < NUM_MAP_LOCATIONS; i++) { 
     prev[i].loc = NOWHERE; 
     prev[i].type = NONE; 
     if (i != from) prev[i].dist = INF; 
     else prev[i].dist = LAST; 
    } 
    LocationID *buffer, cur; 
    // a priority queue that dictates the order LocationID's are checked 
    Link pQ; 
    int bufferLen, pQLen = 0; 
    if (!(pQ = malloc(MAX_QUEUE*sizeof(link)))) 
     fprintf(stderr, "GameView.c: shortestPath: malloc failure (pQ)"); 
    // load initial location into queue 
    pQ[pQLen++].loc = from; 

    while (!visited[to]) { 
     // remove first item from queue into cur 
     shift(pQ, &pQLen, &cur); 
     if (visited[cur]) continue; 
     // freeing malloc from connectedLocations() 
     if (cur != from) free(buffer); 
     // find all locations connected to 
     buffer = connectedLocations(currentView, &bufferLen, cur, 
            player, currentView->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; 
} 
+0

你是否將內存分配給'buffer'? – ameyCU

+1

不應該'sizeof(link)'是'sizeof(Link)'? (無論如何,「link」是什麼?)。 –

+0

typedef struct _link { LocationID loc; TransportID類型; float dist; }鏈接; typedef struct _link * Link;它是圖中兩個節點之間的鏈接ADT –

回答

3

你的所有參數好看這條線之前,這一事實我已經加入了(寫入0x7fff00000000$rbp寄存器(所有本地變量和參數在沒有優化的情況下相對於$rbp)。

您可以在撥打appendLocationsToQueue$rbp應該始終在給定功能內具有相同的值,但已經改變)之前和之後在GDB中用print $rbp進行確認。

假設這是真的,這可能發生的方法只有幾種,最可能的方式是在appendLocationsToQueue(或它調用的東西)中的堆棧緩衝區溢出。

你應該可以使用Address Sanitizer(g++ -fsanitize=address ...)很容易地找到這個bug。

在GDB中找到溢出也很容易:步入appendLocationsToQueue,並且執行watch -l *(char**)$rbp,continue。當您的代碼覆蓋$rbp保存位置時,應該觸發觀察點。

+0

這工作的一種享受。我是在假定valgrind會提醒我導致問題的溢出類型並因此將其歸因於某種看不見的情況下運行的。 –

+0

@RyanMckay Valgrind對堆棧和全局進行很少的檢查。地址Sanitizer是*更好*。 –