Skip to content

Reading from boost::asio::readable_pipe used by Boost Process V2 ends with wrong code 109 on Windows (as opposed to expected boost::asio::error::eof) #553

@aliquis162

Description

@aliquis162

When I launch process (V2) and connect boost::asio::readable_pipe to its stdout on Windows, reading the pipe in a loop finishes with boost::system::error_code with value 109 and message "The pipe has been ended". On Linux I get code 2 and message "End of file". I would expect the code on Windows to behave the same way as Linux, as there seems to be a predefined constant for that: boost::asio::error::eof. This issue seems to be present in all functions (sync read, async read, async read with co_await).

What is the suggested workaround around this bug for now? Do I have to compare error codes based on OS, or is there something better and less error-prone?

Complete example:

#include <iostream>
#include <string>
#include <thread>
#include <vector>

#include <boost/asio.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/process/v2/process.hpp>
#include <boost/process/v2/stdio.hpp>

int main()
{
    boost::asio::io_context ctx;
    boost::asio::readable_pipe stdOutPipe(ctx);

#ifdef unix
    std::string processName = "/usr/bin/bash";
    std::vector<std::string> processArgs = { "-c", "ls", "-al"};
#else
    std::string processName = std::format("{}\\system32\\cmd.exe", std::getenv("windir"));
    std::vector<std::string> processArgs = { "/c", "dir"};
#endif

    boost::process::v2::process process(ctx, processName, processArgs, boost::process::v2::process_stdio{ {}, stdOutPipe, {} });

    std::jthread printStdOutThread([&]
        {
            while (true)
            {
                std::string stdOut;
                boost::system::error_code ec;
                size_t stdOutLength = boost::asio::read(stdOutPipe, boost::asio::dynamic_buffer(stdOut), ec);

                if (stdOutLength > 0)
                {
                    if (stdOut.size() != stdOutLength)
                        stdOut.resize(stdOutLength);

                    std::cout << stdOut;
                    std::cout.flush();
                }

                if (ec.value() != boost::system::errc::success)
                {
                    std::cout
                        << "------------------------\n"
                        << "Pipe end.\n"
                        << "eof: " << (ec == boost::asio::error::eof) << "\n"      // Windows: 0, Linux: 1
                        << "error code: " << ec.value() << "\n"       // Windows: 109, Linux: 2
                        << "error message: " << ec.message() << "\n"     // Windows: "The pipe has been ended", Linux: "End of file"
                        << "pipe is still open: " << stdOutPipe.is_open() << "\n"     // Windows: 1, Linux: 1
                        << "process is still running: " << process.running() << "\n";    // Unreliable because the child process may crash or be terminated at any time, but got this: Windows: false, Linux: true
                    std::cout.flush();

                    break;
                }
            }
        });

    ctx.run();

    int resultCode = process.wait();

    return resultCode;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions