C: Ошибка сегментации: GDB:

У меня есть функция shortestPath (), которая является модифицированной реализацией алгоритма Дейкстры для использования с карточной игрой AI, над которой я работаю для моего classа comp2. Я прошел через веб-сайт и использовал gdb и valgrind. Я точно знаю, где происходит segfault (фактически знал, что несколько часов назад), но не может понять, что вызывает неопределенное поведение или логическая ошибка.

Функция, в которой возникает проблема, называется около 10x и работает так, как ожидалось, пока она не столкнется с GDB: «переменная чтения ошибки: невозможно получить доступ к памяти» и valgrind: «Неверное чтение размера 8»

Обычно этого было бы достаточно, но я не могу работать с этим. Также приветствуются любые общие советы и советы … спасибо!

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

Вот функция, в которой происходит segfault:

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

и функция, благодаря которой после того, как она называется, все разваливается:

 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 в) регистр $rbp (все локальные переменные и параметры относятся к $rbp при построении без оптимизации).

Вы можете подтвердить это в GDB с помощью print $rbp до и после вызова appendLocationsToQueue ( $rbp должен всегда иметь одно и то же значение внутри данной функции, но изменится).

Предполагая, что это правда, есть всего несколько способов, чтобы это могло произойти, и наиболее вероятным способом является переполнение буфера стека в appendLocationsToQueue (или что-то, что он вызывает).

Вы должны иметь возможность использовать Address Sanitizer ( g++ -fsanitize=address ... ), чтобы найти эту ошибку довольно легко.

Также довольно легко найти переполнение в GDB: appendLocationsToQueue в appendLocationsToQueue и watch -l *(char**)$rbp , continue . Контрольная точка должна срабатывать, когда ваш код перезаписывает место сохранения $rbp .