Что может изменить указатель кадра? - PullRequest
4 голосов
/ 31 октября 2008

У меня очень странная ошибка, возникающая сейчас в довольно крупном C ++ приложении на работе (огромная с точки зрения использования процессора и оперативной памяти, а также длины кода - свыше 100 000 строк). Это работает на двухъядерной машине Sun Solaris 10. Программа подписывается на каналы цен акций и отображает их на «страницах», настроенных пользователем (страница - это оконная конструкция, настроенная пользователем - программа позволяет пользователю настраивать такие страницы). Эта программа работала без проблем, пока одна из базовых библиотек не стала многопоточной. Части программы, затронутые этим, были изменены соответствующим образом. На мою проблему.

Примерно один раз в каждые три запуска программы происходит сбой при запуске. Это не обязательно жесткое правило - иногда оно будет три раза подряд, а затем будет работать пять раз подряд. Это segfault, что интересно (читай: больно). Это может проявляться несколькими способами, но чаще всего случается, что функция A вызывает функцию B, и при входе в функцию B указатель кадра внезапно устанавливается на 0x000002. Функция A:

   result_type emit(typename type_trait<T_arg1>::take _A_a1) const
     { return emitter_type::emit(impl_, _A_a1); }

Это простая реализация сигнала. impl_ и _A_a1 четко определены в их кадре при сбое. При фактическом выполнении этой инструкции мы оказываемся в программном счетчике 0x000002.

Это не всегда происходит с этой функцией. На самом деле это происходит в нескольких местах, но это один из более простых случаев, который не оставляет места для ошибок. Иногда случается, что переменная, размещенная в стеке, внезапно окажется в нежелательной памяти (всегда в 0x000002) безо всякой причины. В других случаях тот же код будет работать нормально. Итак, мой вопрос: что может так сильно испортить стек? Что на самом деле может изменить значение указателя кадра? Я конечно никогда не слышал о такой вещи. Единственное, о чем я могу думать, это записывать данные за пределы массива, но я построил его с помощью стекового протектора, который должен подходить для любых случаев этого. Я также хорошо в пределах моего стека здесь. Я также не вижу, как другой поток может перезаписать переменную в стеке первого потока, так как каждый поток имеет свой собственный стек (это все pthreads). Я пытался собрать это на Linux-машине, и, хотя у меня там нет segfaults, примерно один из трех раз он зависнет от меня.

Ответы [ 14 ]

0 голосов
/ 31 октября 2008

Я попробовал Valgrind, но, к сожалению, он не обнаруживает ошибки стека:

"В дополнение к снижению производительности важным ограничением Valgrind является его неспособность обнаруживать ошибки границ при использовании статических или стековых данных."

Я склонен согласиться с тем, что это проблема переполнения стека. Хитрая вещь выслеживает это. Как я уже сказал, в этой штуке более 100 000 строк кода (включая собственные библиотеки, разработанные внутри компании - некоторые из них относятся еще к 1992 году), поэтому, если у кого-то есть какие-то хорошие приемы для уловки такого рода вещей, я бы признательна. Повсюду работают массивы, и приложение использует OI для своего GUI (если вы не слышали об OI, будьте благодарны), так что просто поиск логической ошибки - гигантская задача, и у меня мало времени.

Также согласился, что 0x000002 является подозрительным. Это примерно единственная константа между авариями. Еще более странным является тот факт, что это произошло только с многопоточным коммутатором. Я думаю, что меньший стек в результате многопоточности - вот что делает этот рост сейчас, но это чистое предположение с моей стороны.

Никто не спрашивал об этом, но я собрал с помощью gcc-4.2. Кроме того, я могу гарантировать безопасность ABI здесь, так что это тоже не проблема. Что касается «мусора в конце стека» в обращении к ОЗУ, тот факт, что он универсально равен 2 (хотя в разных местах кода), заставляет меня усомниться в том, что мусор имеет тенденцию быть случайным.

0 голосов
/ 31 октября 2008

Я придерживаюсь мнения, что это, вероятно, повреждение стека. Я добавлю, что переход к многопоточной библиотеке вызывает у меня подозрение, что произошла скрытая ошибка. Возможно, секвенирование переполнения буфера происходило в неиспользуемой памяти. Теперь он попадает в стек другого потока. Есть много других возможных сценариев.

Извините, если это не дает намек на то, как его найти.

0 голосов
/ 31 октября 2008

Во-вторых, это определенно звучит как повреждение стека из-за записи в массив или буфера. Защитник стека был бы хорош, если запись последовательная, а не случайная.

0 голосов
/ 31 октября 2008

Что-то значит присваивать значение 2 переменной, но вместо этого присваивает ее адрес 2?

Остальные детали потеряны для меня, но "2" - это повторяющаяся тема в описании вашей проблемы. ;)

...