Редкая ошибка сегментации при доступе к boost :: unordered_multimap или struct - PullRequest
1 голос
/ 19 мая 2010

У меня проблемы с отладкой ошибки сегментации. Буду признателен за советы о том, как сузить проблему.

Ошибка появляется, когда итератор пытается получить доступ к элементу структуры Infection, определенной как:

struct Infection {
public:
  explicit Infection( double it, double rt ) : infT( it ), recT( rt ) {}
  double infT; // infection start time
  double recT; // scheduled recovery time
};

Эти структуры хранятся в специальной структуре, InfectionMap:

typedef boost::unordered_multimap< int, Infection > InfectionMap;

Каждый член класса Host имеет InfectionMap carriage. Время восстановления и соответствующие идентификаторы хоста хранятся в очереди с приоритетами. Когда в симуляции возникает запланированное событие восстановления для определенного штамма s на конкретном хосте, программа просматривает carriage этого хоста, чтобы найти Infection, recT которого соответствует времени восстановления (double recoverTime) , (По причинам, в которые не стоит вдаваться, для меня не столь целесообразно использовать recT как ключ к InfectionMap; штамм s более полезен, и возможны коинфекции с таким же штаммом.)

assert( carriage.size() > 0 );
pair<InfectionMap::iterator,InfectionMap::iterator> ret = carriage.equal_range( s );
InfectionMap::iterator it;
for ( it = ret.first; it != ret.second; it++ ) {
  if ( ((*it).second).recT == recoverTime ) { // produces seg fault
    carriage.erase( it );
  }
}

Я получаю «Программа получила сигнал EXC_BAD_ACCESS, Не удалось получить доступ к памяти. Причина: KERN_INVALID_ADDRESS at address ...» в строке, указанной выше. RecoveryTime в порядке, и assert(...) в коде не отключается.

Как я уже сказал, эта ошибка сегмента появляется «случайно» после тысяч успешных событий восстановления.

Как бы вы поняли, что происходит? Мне бы хотелось получить представление о том, что может быть не так, и о том, как я могу продолжить изучение проблемы.


Обновление

Я добавил новый assert и проверку прямо внутри цикла for:

assert( carriage.size() > 0 );
assert( carriage.count( s ) > 0 );
pair<InfectionMap::iterator,InfectionMap::iterator> ret = carriage.equal_range( s );
InfectionMap::iterator it;
cout << "carriage.count(" << s << ")=" << carriage.count(s) << endl;
for ( it = ret.first; it != ret.second; it++ ) {
  cout << "(*it).first=" << (*it).first << endl; // error here
  if ( ((*it).second).recT == recoverTime ) {
    carriage.erase( it );
  }
}

Ошибка EXC_BAD_ACCESS теперь появляется при вызове (*it).first, снова после многих тысяч успешных восстановлений. Кто-нибудь может дать мне советы, как выяснить, как возникает эта проблема? Я пытаюсь использовать GDB. Кадр 0 из следа читает

"# 0 0x0000000100001d50 в Host :: restore (this = 0x100530d80, s = 0, recoverTime = 635.91148029170529) в Host.cpp: 317"

Я не уверен, какую полезную информацию я могу извлечь здесь.


Обновление 2

Я добавил break; после carriage.erase(it). Это работает.

Ответы [ 2 ]

7 голосов
/ 19 мая 2010

Поправьте меня, если я ошибаюсь, но я бы поспорил, что удаление элемента в неупорядоченном мультикарте делает недействительными все итераторы, указывающие на него. Попробуйте "it = carriage.erase (it)". Тебе тоже придется что-то делать с ret.

Обновление в ответ на ваше последнее обновление:

Причина выхода из цикла после вызова «carriage.erase (it)» исправила ошибку в том, что вы перестали пытаться получить доступ к стертому итератору.

0 голосов
/ 19 мая 2010

Скомпилируйте программу с помощью gcc -g и запустите ее под gdb. Когда вы получите сбой EXC_BAD_ACCESS, вы попадете в командную строку GDB. В этот момент вы можете набрать bt, чтобы получить обратную трассировку, которая покажет вам, как вы попали в точку, где произошел сбой.

...