с плавающей точкой — c ++ плавает и странное поведение valgrind

У меня есть 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)

3

Решение

Хорошо, после нескольких часов чтения и исследования я нашел проблему, я собираюсь ответить на свой собственный вопрос, потому что никто не делает, только комментарий @Kerrek SB [ https://stackoverflow.com/users/596781/kerrek-sb ] но я не могу принять комментарий. (Спасибо)

Это так же просто, как внутри обработчика сигнала, вы можете безопасно вызывать только несколько функций: http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html

Если вы вызываете некоторые неасинхронные функции, они могут работать, но не всегда.

Если вы хотите вызывать неасинхронно-безопасные функции внутри обработчика сигнала, вы можете сделать это:

  • Создать 2 трубы. 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.

1

Другие решения

Отладчики и прочее иногда бросают сигналы процессу, который вы обычно не получаете. Мне пришлось изменить функцию, которая использовала recv для работы под GDB, например. Проверьте, какой у вас сигнал, и убедитесь, что mc не равен null, прежде чем пытаться его использовать. Посмотрите, начнет ли это приближать вас к ответу.

Я думаю, что, возможно, ваше использование new (или что-то еще, возможно) может привести к тому, что valgrind отправит сигнал, который перехватывается вашим обработчиком до инициализации mc.

Также очевидно, что вы не вставляли реальный код, потому что использование класса без публичной функции end () означает, что это не должно компилироваться.

0

По вопросам рекламы [email protected]