C:分段故障:GDB:<读取变量的错误> [英] C: Segmentation fault: GDB: <error reading variable>

查看:244
本文介绍了C:分段故障:GDB:<读取变量的错误>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个函数shortPath(),它是Dijkstra算法的修改实现,用于与我在comp2类中工作的棋盘游戏AI一起使用。我已经浏览了网站,并使用gdb和valgrind我确切知道segfault发生的地方(实际上知道几个小时前),但是无法确定导致该问题的未定义的行为或逻辑错误。



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



通常这样就够了,但是我不能这样做。还有任何一般的建议和提示都赞赏...谢谢!



GDB: https://gist.github.com/mckayryan/b8d1e9cdcc58dd1627ea

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



这是发生segfault的功能: p>

  static void processBuffer(GameView currentView,Link pQ,int * pQLen,
LocationID * buffer,int bufferLen,Link prev,
LocationID cur)
{
// printLinkIndex(prev,prev,NUM_MAP_LOCATIONS);
//添加新检索的缓冲区添加链接类型的位置
appendLocationsToQueue(currentView,pQ,pQLen,buffer,bufferLen,cur);
//计算新位置的距离和需要时的更新prev
updatePrev(currentView,pQ,pQLen,prev,cur); < ---这行这里

qsort((void *)pQ,* pQLen,sizeof(link),(compfn)cmpDist);
// qsort sanity check
int i,qsortErr = 0; (i = 0; i< * pQLen-1; i ++)
if(pQ [i] .dist> pQ [i + 1] .dist)qsortErr = 1;
if(qsortErr){
fprintf(stderr,loadToPQ:qsort does not sort succesfully);
abort();
}
}

  static void appendLocationsToQueue(GameView currentView,Link pQ,
int * pQLen,LocationID * buffer,
int bufferLen,LocationID cur)
{
int i,c,conns;
TransportID类型[MAX_TRANSPORT] = {NONE};

for(i = 0; i< bufferLen; i ++){
//获取连接信息(最多3个可能)
conns = connections(currentView-> gameMap ,cur,buffer [i],type); (c = 0; c< conns; c ++)
{
pQ [* pQLen] .loc = buffer [i];
pQ [(* pQLen)++]。type = type [c];
}
}
}

所以我以为一个指针已被覆盖到错误的地址,但经过GDB的大量打印,似乎并非如此。我还通过对所涉及的变量进行读/写操作来查看哪个触发器的错误,并且它们都在appendLocationsToQueue()之后执行,但不是之前(或在该函数的结尾处)。



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

  link shortPath(GameView currentView,LocationID from,LocationID to,PlayerID player,int road,int rail,int boat)
{
if(!RAIL_MOVE)rail = 0;

//已访问的位置的索引
int visited [NUM_MAP_LOCATIONS] = {0};

//当前距离源的最短距离
//当前已知最短路径的前一个节点
链接prev;
if(!(prev = malloc(NUM_MAP_LOCATIONS * sizeof(link))))
fprintf(stderr,GameView.c:shortPath:malloc failure(prev));

int i;
// intialise链接数据结构
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;
//一个优先级队列,用于指定LocationID的顺序。
Link pQ;
int bufferLen,pQLen = 0;
if(!(pQ = malloc(MAX_QUEUE * sizeof(link))))
fprintf(stderr,GameView.c:minimumPath:malloc failure(pQ));
//将初始位置加载到队列
pQ [pQLen ++]。loc = from;

while(!visited [to]){
//将第一个项从队列中删除到cur
shift(pQ,& pQLen,& cur);
if(visited [cur])继续;
//释放来自connectedLocations()的malloc
if(cur!= from)free(buffer);
//找到连接到
的所有位置buffer = connectedLocations(currentView,& bufferLen,cur,
player,currentView-> roundNum,road,
rail,boat);
//将当前节点标记为已访问
visited [cur] = VISITED;
//来自缓冲区的位置用于更新优先级队列(pQ)
//和距离信息在prev
processBuffer(currentView,pQ,& pQLen,buffer,bufferLen,prev,
cur);
}
free(buffer);
免费(pQ);
返回prev;
}


解决方案

在这行之前看起来不错:

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

,当它告诉我你已经踩了(写了 0x7fff00000000 to) $ rbp 注册表(所有局部变量和参数都相对于 $ rbp />

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

假设这是真的,只有几种方法可能会发生,最可能的方法是在 appendLocationsToQueue (或者它所调用的东西)。



你应该可以使用地址清理器( g ++ -fsanitize = address ... )相当容易找到这个错误。



在GDB中找到溢出也很容易:进入 appendLocationsToQueue ,然后执行 watch -l *(char **)$ rbp continue 。当您的代码覆盖 $ rbp 保存位置时,观察点将触发。


I have a function shortestPath() that is a modified implementation of Dijkstra's algorithm for use with a board game AI I am working on for my comp2 class. I have trawled through the website and using gdb and valgrind I know exactly where the segfault happens (actually knew that a few hours ago), but can't figure out what undefined behaviour or logic error is causing the problem.

The function in which the problem occurs is called around 10x and works as expected until it segfaults with GDB: "error reading variable: cannot access memory" and valgrind: "Invalid read of size 8"

Normally that would be enough, but I can't work this one out. Also any general advise and tips are appreciated... thanks!

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

Here is the function in which the segfault occurs:

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();
    }  
}

and the function whereby after it is called everything falls apart:

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];            
        }            
    }
}

So I thought that a pointer had been overridden to the wrong address, but after a lot of printing in GDB that doesn't seem to be the case. I also rotated through making reads/writes to the variables in question to see which trigger the fault and they all do after appendLocationsToQueue(), but not before (or at the end of that function for that matter).

Here is the rest of the relevant code: 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 < 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;
}

解决方案

The fact that all your parameters look good before this line:

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

and become unavailable after it tells me that you've stepped on (wrote 0x7fff00000000 to) the $rbp register (all local variables and parameters are relative to $rbp when building without optimization).

You can confirm this in GDB with print $rbp before and after call to appendLocationsToQueue ($rbp is supposed to always have the same value inside a given function, but will have changed).

Assuming this is true, there are only a few ways this could happen, and the most likely way is a stack buffer overflow in appendLocationsToQueue (or something it calls).

You should be able to use Address Sanitizer (g++ -fsanitize=address ...) to find this bug fairly easily.

It's also fairly easy to find the overflow in GDB: step into appendLocationsToQueue, and do watch -l *(char**)$rbp, continue. The watchpoint should fire when your code overwrites the $rbp save location.

这篇关于C:分段故障:GDB:&lt;读取变量的错误&gt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆