【问题标题】:`boost::process::child` will hang if the result of the command is long如果命令的结果很长,`boost::process::child` 将挂起
【发布时间】:2021-11-13 16:01:28
【问题描述】:

我有一个简单的 C++ 程序,它使用boost::process:child 接收终端命令并执行它,然后打印出结果。但是如果我执行像ps aux 这样的命令,整个程序将没有响应。我不确定如何解决。我试过调试它,调试器只会停在cp.wait()

try{
        child cp(cmd+" "+param, (std_out & std_err) > pipe);
        cp.wait();
        return_code = cp.exit_code();
}catch (process_error e){
        return_code = -1;
}

【问题讨论】:

    标签: c++ boost


    【解决方案1】:

    您需要消耗管道。管道连接到什么(换句话说,谁在使用它?)。

    如果看起来确实如此,您对输出根本不感兴趣,只需重定向到 null 设备:

    作为旁注,我会强烈劝阻using namespace boost::process,因为它看起来像你正在做的。该命名空间中有许多名称很容易与 C/标准库名称发生冲突。例如,pipe 是局部变量吗?是boost::process::pipe这个类型吗?是POSIX系统库调用::pipe吗?

    修复

    Live On Coliru

    #include <boost/process.hpp>
    #include <iostream>
    
    int main()
    {
        namespace bp    = boost::process;
        std::string cmd = "cat", param = "/etc/dictionaries-common/words";
        //bp::pipe pipe;
    
        int return_code = -1;
        try {
            bp::child cp(cmd + " " + param, (bp::std_out & bp::std_err) > bp::null);
            cp.wait();
            return_code = cp.exit_code();
        } catch (bp::process_error const& e) {
            return_code = -1;
        }
    
        std::cout << "return_code: " << return_code << "\n";
        return return_code;
    }
    

    请注意,它在 Coliru 上返回 1,因为该字典不存在。在我的系统上它正确返回0(没有阻塞。

    安全

    请注意,将命令拼凑成字符串可能非常容易出错并引发安全漏洞(如果传入的文件名是“foot.txt; rm -rf *”怎么办?)。

    我建议使用参数向量样式:

        std::string              cmd = "cat";
        std::vector<std::string> params{"-n", "--",
                                        "/etc/dictionaries-common/words"};
    
        bp::child cp(bp::search_path(cmd), params,
                     (bp::std_out & bp::std_err) > bp::null);
    

    不使用search_path 更安全,但它要求exe 是完全指定的路径(如/bin/cat./bin/myexe)。

    请注意,现在接受来自外部输入的文件名已经足够安全了:

        std::vector<std::string> params{"-n", "--"};
        params.insert(end(params), argv + 1, argv + argc);
    

    作为画龙点睛的一笔,让我们关闭子进程的标准输入(这样我们就不会在那里泄露隐私,如果命令行上没有列出文件也不会挂起......):

    Live On Coliru

    #include <boost/process.hpp>
    #include <iostream>
    
    int main(int argc, char** argv)
    {
        namespace bp    = boost::process;
        int return_code = -1;
    
        try {
            std::string              cmd = "/bin/cat";
            std::vector<std::string> params{"-n", "--"};
            params.insert(end(params), argv + 1, argv + argc);
    
            bp::child cp(cmd, params,        //
                         bp::std_in.close(), //
                         (bp::std_out & bp::std_err) > bp::null);
    
            cp.wait();
            return_code = cp.exit_code();
        } catch (bp::process_error const& e) {
            return_code = -1;
        }
    
        std::cout << "return_code: " << return_code << "\n";
        return return_code;
    }
    

    现在它打印return_code: 0,因为文件实际上存在于 Coliru 上。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-30
      相关资源
      最近更新 更多