【问题标题】:Can't get segmentation fault exit code from boost child process无法从提升子进程中获取分段错误退出代码
【发布时间】:2024-04-12 22:50:01
【问题描述】:

当子进程由于分段违规或除为零或任何其他终止信号而被终止时,我正在尝试获取子进程的退出代码(使用 boost::process 和 boost::asio)。退出代码和错误代码始终返回 0 并成功。

我在 CentOS 7 上使用 g++ 4.8.5 和 boost 1.66 运行它

如果我使用仅返回非零退出代码的子进程运行相同的代码,它会成功返回该退出代码。

#include <iostream>
#include <boost/process.hpp>
#include <boost/asio/io_service.hpp>

namespace bp = boost::process;
using namespace std;

int main (int argc, char** argv)
{
   string exe = "./crashes";

   vector<string> data;
   boost::asio::io_service ios;

   int exit_code;
   error_code ec;
   future<string> ostr;

   bp::child c(exe,
               (bp::std_out & bp::std_err) > ostr,
               ios,
               bp::on_exit=[&exit_code, &ec](int exit, const error_code& ecin)
                                             {exit_code = exit; ec = ecin;});

   ios.run();

   cout << "Exit Code = " << exit_code << endl;
   cout << "Error Code = " << ec.message() << endl;
   cout << "child stdin & stderr:\n";
   cout << ostr.get() << endl;
   return exit_code;
}

和崩溃代码

int main (int argc, char** argv)
{
   int* y = 0;
   int c = *y;
}

结果显示 0 退出代码和 Success error_code

Exit Code = 0
Error Code = Success
child stdin & stderr:

单独运行 crash 可执行文件会返回退出代码 139

bash-4.2$ ./crashes 
Segmentation fault (core dumped)
bash-4.2$ echo $?
139

【问题讨论】:

    标签: c++11 boost-asio boost-process


    【解决方案1】:

    进程终止和退出代码的详细信息取决于平台。

    Boost 过程文件关于默认界面的差异:您的on_exit 处理程序被调用,结果为退出状态的boost::process::detail::posix::eval_exit_status(),这意味着:

    inline int eval_exit_status(int code)
    {
        if (WIFEXITED(code))
        {
            return WEXITSTATUS(code);
        }
        else if (WIFSIGNALED(code))
        {
            return WTERMSIG(code);
        }
        else
        {
            return code;
        }
    }
    

    所以,你得到“exit-code 11”,意思是段错误......如果你想真正知道,你可以看看native_exit_code()

    bp::on_exit = [&result, &c](int /*ignored*/, const std::error_code &ec) {
        auto exit_status = c.native_exit_code();
        result.exit_code = boost::make_optional(WIFEXITED(exit_status), WEXITSTATUS(exit_status));
        result.signal    = boost::make_optional(WIFSIGNALED(exit_status), WTERMSIG(exit_status));
        result.ec = ec;
    }
    

    现在假设结果变量有一些变化。完整列表:

    上市

    #include <boost/asio/io_service.hpp>
    #include <boost/process.hpp>
    #include <iostream>
    
    namespace bp = boost::process;
    
    int main(int argc, char**) {
        std::string exe = argc>1? "./ltua" : "./crashes";
    
        boost::asio::io_service ios;
    
        struct {
            boost::optional<int> exit_code;
            boost::optional<int> signal;
            std::error_code ec{};
        } result;
    
        std::future<std::string> ostr;
    
        bp::group g;
        bp::child c(exe, g, (bp::std_out & bp::std_err) > ostr, ios,
            bp::on_exit = [&result, &c](int /*ignored*/, const std::error_code &ec) {
                auto exit_status = c.native_exit_code();
                result.exit_code = boost::make_optional(WIFEXITED(exit_status), WEXITSTATUS(exit_status));
                result.signal    = boost::make_optional(WIFSIGNALED(exit_status), WTERMSIG(exit_status));
                result.ec = ec;
            });
    
        //g.wait();
        ios.run();
    
        if (result.exit_code) {
            std::cout << "Exited with " << *result.exit_code << std::endl;
        }
        if (result.signal) {
            std::cout << "Signaled with sginal #" << *result.signal << ", aka " << ::strsignal(*result.signal) <<  std::endl;
        }
    
        std::cout << "Error Code = " << result.ec.message() << std::endl;
        std::cout << "child stdin & stderr:\n";
        std::cout << ostr.get() << std::endl;
        return result.exit_code? *result.exit_code : 255;
    }
    

    输出

    使用ltua.cpp 运行时:

    #include <iostream>
    int main() {
        std::cout << "so  long"   << std::end;
        std::cerr << "and thanks" << std::end;
        std::cout << "for all"    << std::end;
        std::cerr << "the fish"   << std::end;
        return 42;
    }
    

    打印

    Exited with 42
    Error Code = Success
    child stdin & stderr:
    so  long
    and thanks
    for all
    the fish
    

    还有crashes.cpp:

    int main() {
        int *y = 0;
        int c = *y;
    }
    

    打印

    Signaled with sginal #11, aka Segmentation fault
    Error Code = Success
    child stdin & stderr:
    

    【讨论】:

    • 重新阅读您的问题,似乎在最近的增强版本 (>1.66) 中行为可能已经改变。出于这个原因,您可能想要升级。
    • 是的,不幸的是 boost 1.66 没有有增强的eval_exit_status,它是在 1.67 中添加的。可悲的是,我坚持使用 1.66
    • 只要native_exit_code 可用,您就可能有解决方案。但是我还没有检查哪个版本引入了那个