У меня есть valgrind 3.6.0, я искал везде и ничего не нашел.
Проблема в том, что, когда я пытаюсь получить доступ к числу с плавающей запятой при использовании valgrind, я получаю segfault, но когда я запускаю программу как есть, без valgrind, все идет так, как ожидалось.
Это кусок кода:
class MyClass {
public:
void end() {
float f;
f = 1.23;
std::stringstream ss;
ss << f;
std::cout << ss.str();
}
};
extern "C" void clean_exit_on_sig(int sig) {
//Code logging the error
mc->end();
exit(1);
}
MyClass *mc;
int main(int argc, char *argv[]) {
signal(SIGINT , clean_exit_on_sig);
signal(SIGABRT , clean_exit_on_sig);
signal(SIGILL , clean_exit_on_sig);
signal(SIGFPE , clean_exit_on_sig);
signal(SIGSEGV, clean_exit_on_sig);
signal(SIGTERM , clean_exit_on_sig);
mc = new MyClass();
while(true) {
// Main program loop
}
}
Когда я нажимаю Control + C, программа правильно улавливает сигнал, и все идет хорошо, но когда я запускаю программу, используя valgrind, когда пытается выполнить эту команду ss << f; // (Inside MyClass)
бросается segfault: — /
Я тоже попробовал это:
std::string stm = boost::lexical_cast<std::string>(f);
Но я продолжаю получать сигнал segfault, когда boost принимает и число с плавающей точкой.
Это обратная трассировка, когда я получаю segfault с boost:
./a.out(_Z17clean_exit_on_sigi+0x1c)[0x420e72]
/lib64/libc.so.6(+0x32920)[0x593a920]
/usr/lib64/libstdc++.so.6(+0x7eb29)[0x51e6b29]
/usr/lib64/libstdc++.so.6(_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE15_M_insert_floatIdEES3_S3_RSt8ios_baseccT_+0xd3)[0x51e8f43]
/usr/lib64/libstdc++.so.6(_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecd+0x19)[0x51e9269]
/usr/lib64/libstdc++.so.6(_ZNSo9_M_insertIdEERSoT_+0x9f)[0x51fc87f]
./a.out(_ZN5boost6detail26lexical_stream_limited_srcIcSt15basic_streambufIcSt11char_traitsIcEES4_E9lcast_putIfEEbRKT_+0x8f)[0x42c251]
./a.out(_ZN5boost6detail26lexical_stream_limited_srcIcSt15basic_streambufIcSt11char_traitsIcEES4_ElsEf+0x24)[0x42a150]
./a.out(_ZN5boost6detail12lexical_castISsfLb0EcEET_NS_11call_traitsIT0_E10param_typeEPT2_m+0x75)[0x428349]
./a.out(_ZN5boost12lexical_castISsfEET_RKT0_+0x3c)[0x426fbb]
./a.out(This line of code corresponds to the line where boost tries to do the conversion)
и это с преобразованием потока строк по умолчанию:
./a.out(_Z17clean_exit_on_sigi+0x1c)[0x41deaa]
/lib64/libc.so.6(+0x32920)[0x593a920]
/usr/lib64/libstdc++.so.6(+0x7eb29)[0x51e6b29]
/usr/lib64/libstdc++.so.6(_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE15_M_insert_floatIdEES3_S3_RSt8ios_baseccT_+0xd3)[0x51e8f43]
/usr/lib64/libstdc++.so.6(_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecd+0x19)[0x51e9269]
/usr/lib64/libstdc++.so.6(_ZNSo9_M_insertIdEERSoT_+0x9f)[0x51fc87f]
./a.out(This line of code corresponds to the line where I try to do the conversion)
a.out
моя программа, и я запускаю valgrind следующим образом: valgrind --tool=memcheck ./a.out
Еще одна странная вещь, что когда я звоню mc->end();
пока программа работает нормально (любой сигнал получен, объект только что завершил свою работу), я не получаю никакого segfault (как есть и с valgrind).
Пожалуйста, не говорите мне: «Не закрывайте свою программу с помощью Control + C, бла-бла…». Этот фрагмент кода предназначен для регистрации любой ошибки, которую может иметь программа, без потери данных в случае segfault, уничтожая ее из-за тупика. или что-то другое.
РЕДАКТИРОВАТЬ: Может быть, это ошибка valgrind (я не знаю, искал в Google, но ничего не нашел, не убивайте меня), любой обходной путь тоже будет принят.
EDIT2: Просто понял, что boost тоже вызывает ostream (здесь это понятнее, чем использование vim: — /), собираюсь попробовать преобразование с плавающей запятой sprintf.
EDIT3: Пробовал это sprintf(fl, "%.1g", f);
но все равно вылетает, трассировка:
./a.out(_Z17clean_exit_on_sigi+0x40)[0x41df24]
/lib64/libc.so.6(+0x32920)[0x593a920]
/lib64/libc.so.6(sprintf+0x56)[0x5956be6]
./a.out(Line where sprintf is)
Хорошо, после нескольких часов чтения и исследования я нашел проблему, я собираюсь ответить на свой собственный вопрос, потому что никто не делает, только комментарий @Kerrek SB [ https://stackoverflow.com/users/596781/kerrek-sb ] но я не могу принять комментарий. (Спасибо)
Это так же просто, как внутри обработчика сигнала, вы можете безопасно вызывать только несколько функций: http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
Если вы вызываете некоторые неасинхронные функции, они могут работать, но не всегда.
Если вы хотите вызывать неасинхронно-безопасные функции внутри обработчика сигнала, вы можете сделать это:
int pip1[2]; int pip2[2]; pipe(pip1); pipe(pip2);
read(pip1[0], msg, 1);
write
безопасная асинхронная функция для записи в 1-й канал write(pip1[1], "0", 1);
read(pip2[0], msg, 1);
write(pip2[1], "0", 1);
_Exit(1)
или что-то другое.Информация:
Я использую 2 канала, потому что если я пишу в канал и сразу после этого читаю его, возможно, что 2-й поток никогда не проснется, потому что основной поток прочитал только что записанные данные. И я использую вторичный канал для блокировки основного потока, потому что я не хочу, чтобы он выходил, пока второй поток сохраняет данные.
Имейте в виду, что обработчик сигнала, возможно, был вызван при изменении общего ресурса, если ваш 2-й поток признает, что ресурс возможен, если вы столкнетесь со вторым segfault, поэтому будьте осторожны при доступе к общим ресурсам с вашим 2-м потоком (глобальные переменные или что-то еще) ,
Если вы тестируете с помощью valgrind и не хотите получать «ложные» утечки памяти при получении сигнала, вы можете сделать это перед выходом pthread_join(2ndthread, NULL)
а также exit(1)
вместо _Exit(1)
, Это не асинхронно-безопасные функции, но, по крайней мере, вы можете проверить утечки памяти и закрыть приложение с помощью сигнала без получения «ложных» утечек памяти.
Надеюсь, это кому-нибудь поможет. Еще раз спасибо @Kerrek SB.
Отладчики и прочее иногда бросают сигналы процессу, который вы обычно не получаете. Мне пришлось изменить функцию, которая использовала recv для работы под GDB, например. Проверьте, какой у вас сигнал, и убедитесь, что mc не равен null, прежде чем пытаться его использовать. Посмотрите, начнет ли это приближать вас к ответу.
Я думаю, что, возможно, ваше использование new (или что-то еще, возможно) может привести к тому, что valgrind отправит сигнал, который перехватывается вашим обработчиком до инициализации mc.
Также очевидно, что вы не вставляли реальный код, потому что использование класса без публичной функции end () означает, что это не должно компилироваться.