C++ c++;飘浮和英勇的奇怪行为

C++ c++;飘浮和英勇的奇怪行为,c++,floating-point,segmentation-fault,valgrind,stringstream,C++,Floating Point,Segmentation Fault,Valgrind,Stringstream,我有valgrind 3.6.0,我到处找都没找到 问题是,当我在使用valgrind时试图访问一个浮点数时,我得到了一个segfault,但是当我按原样运行程序时,没有valgrind,一切都按预期进行 这是一段代码: class MyClass { public: void end() { float f; f = 1.23; std::stringstream ss; ss << f;

我有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
    }
}
这是默认的stringstream转换:

./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()时当程序运行正常(接收到任何信号,Object刚刚完成工作)时,我不会以任何方式得到segfault(就像valgrind一样)

请不要告诉我‘不要用Control+C关闭你的程序等等……’这段代码用于记录程序可能存在的任何错误,而不会在发生segfault时丢失数据,因为死锁或其他原因而终止程序

编辑:可能是一个valgrind bug(我不知道,在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)

调试器和其他东西有时会向进程抛出通常无法得到的信号。例如,我必须修改一个使用recv在gdb下工作的函数。检查您的信号是什么,并在尝试使用它之前验证mc是否为空。看看这是否会让你更接近答案

我在想,您使用new(或者其他可能的东西)可能会导致valgrind发送一个信号,该信号在mc初始化之前被处理程序捕获


很明显,你没有粘贴实际的代码,因为你在没有公开end()函数的情况下使用'class',这意味着它不应该编译。

好的,经过几个小时的阅读和研究,我发现了问题,我将回答我自己的问题,因为没有人会,只有@Kerrek SB[]的评论,但我不能接受评论。(谢谢)

这就像在信号处理器中一样简单,您只能安全地调用一组函数:

如果调用一些非异步安全函数,它们可以工作,但并不总是如此

如果要在信号处理程序中调用非异步安全函数,可以执行以下操作:

  • 创建两个管道<代码>int pip1[2];int-pip2[2];管道(pip1);管道(pip2)
  • 创建一个新线程并使线程等待从1rst管道
    读取(pip1[0],msg,1)接收一些数据
  • 调用信号处理程序时,使用
    write
    async safe函数写入第一个管道
    write(pip1[1],“0”,1)
  • 然后使信号等待第二个管道读取
    (pip2[0],msg,1)
  • 线程将唤醒并完成所有他必须完成的工作(在本例中,将数据保存到数据库),然后,使线程将数据写入第二个管道
    write(pip2[1],“0”,1)
  • 现在,主线程将唤醒并以退出(1)
或其他方式结束 信息:

我使用2个管道,因为如果我写入管道,然后读取它,第2个线程可能永远不会唤醒,因为主线程已经读取了刚刚写入的数据。我使用一个辅助管道来阻止主线程,因为我不希望它在第二个线程保存数据时退出

请记住,在修改共享资源时可能调用了信号处理程序,如果您的第二个线程访问该资源,则可能会遇到第二个segfault,因此在使用第二个线程(全局变量或其他内容)访问共享资源时要小心

如果您正在使用valgrind进行测试,并且在接收信号时不希望接收到“假”内存泄漏,则可以在退出
pthread\u join(2ndthread,NULL)
exit(1)
而不是
\u exit(1)
之前执行此操作。这些都是非异步安全函数,但至少你可以测试内存泄漏,并在不接收“错误”内存泄漏的情况下用信号关闭你的应用程序


希望这对别人有帮助。再次感谢@Kerrek SB.

我认为您的信号处理程序不是异步安全的。不允许在信号处理程序中执行复杂的操作在你的信号处理程序中。Kerrek SB,我知道,但是没有valgrind,一切都很好,所以我认为我没有做复杂的事情,因为它是有效的。我需要将浮点放在一个字符串中,并尝试这样做:
sprintf(fl,%.1g),f
)是的,我已经检查过了,mc不是空的。是的,这不是完整的代码,因为代码现在有几千行,所以不可能放入真正的代码,只是忘记添加
public:
,去编辑它。当一些代码试图访问浮点时,信号被发送,因此
new
没有抛出任何信号,它按预期工作。
./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(_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)