Repository navigation
Problem with process creating (boost process v2) in limited linux systems #529
Description
Activity
Important note: on that system binary works with boost::process::v1, after upgrading appeared troubles
Testing on aarch64 show that result:
Creating process... Exception: default_launcher: No such file or directory [system:2 at /boost_1_87_0/include/boost/process/v2/posix/default_launcher.hpp:431 in function 'operator()']. Error code: system:2
I checked that file (/bin/echo) is exists and runs manually
But linux version is 5.10.61After testing locally with boost 1.89, I found, that if I add some printf calls in the child process (inside the
if (child_pid == 0) {...}block) - it started to work.IMO, it looks like as a data race.
@klemens-morgenstern , do we have some better way to mitigate that?P.S. File not found errno value, that was reported in the @Sene4kass 's logs looks like the pipe related, not the executable one.
P.P.S. My changeset:else if (pid == 0) { ::close(pg.p[0]); #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_child); #endif printf("1\n"); ec = detail::on_exec_setup(*this, executable, argv, inits...); printf("2: %d\n", ec); if (!ec) { printf("3\n"); close_all_fds(ec); } if (!ec) printf("4\n"); ::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env)); printf("5: %d\n", ec); ignore_unused(::write(pg.p[1], &errno, sizeof(int))); BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category()); detail::on_exec_error(*this, executable, argv, ec, inits...); ::exit(EXIT_FAILURE); return basic_process<Executor>{exec}; }
Looks like we forgot to reset the pipe fd value after closing in child and receive a RAII destruction (second close) for it:
::close(pg.p[0]); Oops, I forgot the brackets near
printf("4\n");Here is fixed patch:
else if (pid == 0) { ::close(pg.p[0]); #if !defined(BOOST_PROCESS_V2_DISABLE_NOTIFY_FORK) ctx.notify_fork(net::execution_context::fork_child); #endif printf("1\n"); ec = detail::on_exec_setup(*this, executable, argv, inits...); printf("2: %d\n", ec); if (!ec) { printf("3\n"); close_all_fds(ec); } if (!ec) { printf("4\n"); ::execve(executable.c_str(), const_cast<char * const *>(argv), const_cast<char * const *>(env)); } printf("5: %d\n", ec); ignore_unused(::write(pg.p[1], &errno, sizeof(int))); BOOST_PROCESS_V2_ASSIGN_EC(ec, errno, system_category()); detail::on_exec_error(*this, executable, argv, ec, inits...); ::exit(EXIT_FAILURE); return basic_process<Executor>{exec}; }
And the output:
./q Creating process... 1 2: 0 3 5: 2 Exception: default_launcher: No such file or directory [system:2 at /embuild/sysroot/src/cammeta-cpp/build/axxonsoft/sdk/debian10.armhf.gcc8.3.0/cammeta-cpp/boost_1_89_0/include/boost/process/v2/posix/default_launcher.hpp:417 in function 'operator()']. Error code: system:2So, the error has been returned from the
close_all_fds()callklemens-morgenstern commented
on Dec 22, 2025 CollaboratorMore actionsCan you figure you which
close_allfunction gets used?https://github.com/boostorg/process/blob/2a41d0a0dcef77ff362c1e3a7cc88b47191ff9d2/src/posix/close_handles.cppI reckon it's possible it uses this one:
process/src/posix/close_handles.cpp
Line 181 in 2a41d0a
std::unique_ptr<DIR, void(*)(DIR*)> dir{::opendir("/dev/fd"), +[](DIR* p){::closedir(p);}}; Which iterates over
/dev/fdwhich may fail if the directory structure is set up differently. If so, does your OS have an equivalent of/dev/fd?Hi @klemens-morgenstern ,
Yes, you're right, we have no
/dev/fd. We have a/proc/self/fd, and the/dev/fdshould point on it, as I can see in kernel docs.What about trying to open
/proc/self/fdas a second hope if thedirsmart pointer is empty?P.S. As I can see in disassembled test binary, you're right - we are using
process/src/posix/close_handles.cpp
Line 181 in 2a41d0a
std::unique_ptr<DIR, void(*)(DIR*)> dir{::opendir("/dev/fd"), +[](DIR* p){::closedir(p);}}; klemens-morgenstern commented
on Dec 22, 2025 CollaboratorMore actionsSounds right, but then the question is: what do we do if
/proc/self/fdisn't available? Just not closing handles sounds worse - do you have any ideas?Possibly we can generate some warning for the user. It's sounds not good, but it's not really critical.
To have the similar behavior, we're force marking all sockets and other descriptors with
O_CLOEXECafter cleating/opening.I've provided the PR #538, that help with our small example.
I hope it will be merged
Hello!
I'm using boost::process::v2 (boost version 1.89 - latest stable) in my project with cross-compiling the final binary. If I use the amd64 standard debian 12, all is ok and process creating ended successfully without errors. But if I using it in limited linux (system with busybox, specific process architecture (for example, armv7l)) I getting an unknown exception. Try/catch can't process that exception. Google breakpad also can't give me details.
I checked the system - clone(), execve(), fork() works there. But bp::v2::process give me an unknown exception.
Also I testing on aarch64 (arm64) limited system and on standard linux version system. In standard linux that works great, but on limited system I've got the same error.
Warning: the "limited" version I mean Linux core + standard utilities such as busybox, libc, sh and other configurated extremely necessary utils.
I tested work directory access - all is ok on my side. I running the "/bin/echo" manually from shell, and that works good.
System info:
armv7l, linux version 4.19.91,
GNU C Library (Buildroot) stable release version 2.29.
BusyBox v1.24.1 (2024-03-14 16:36:28 CST) multi-call binary
Binary compiled with GCC 8.3.0
Error log:
Creating process... terminate called after throwing an instance of 'boost::wrapexcept<boost::system::system_error>' terminate called recursively Aborted (core dumped)Code: