When is creation of the ```std::io::Error``` instance async-signal-safe?

Hello everyone!

In the Rust standard library, a lot of fallible functions interacting with the operating system use std::io::Error as their error type -- it's flexible and allows both reporting errors from an operating system and wrapping a custom error type if it implements std::error::Error trait. One of such facilities is the std::process::Command type, which is a builder type used to configure spawning of the child process. In some operating systems, such as GNU/Linux, the child process is spawned in two steps: first, a copy of the parent process is created and then the new program is loaded to that copy with execve(). Before execve() occurs, a copy of the parent process can configure the environment for the child process -- open the necessary file descriptors and close the unnecessary one, reset or ignore signals, determine a signal mask (which may be necessary if the parent process handles signals synchronously with signalfd), which is exposed in the Rust standard library as the unsafe Command::pre_exec() method. However, in a multithreaded process, only a forking thread is forked -- which requires the pre-execve() preparation to be async-signal-safe -- it cannot allocate (because the memory allocator may be left in the indeterminate state), take any locks (because they may have been locked by other threads), however, the closure passed to the pre_exec() method reports an error with the std::io::Error method, which does sometimes allocate. As far as I understand, creating an error object with std::io::Error::new() is not safe, because it allocates. I wonder, which constructors for it are acceptable? Specifically, I'm interested about these constructors:

  • std::io::Error::from_raw_os_error()
  • std::io::Error::last_os_error()
  • From<std::io::ErrorKind> trait
  • std::io::const_error!()

If the documentation doesn’t say that the function is async-signal-safe then you can’t assume that the function is async-signal-safe. I think it would be reasonable to request that such documentation be added to these constructors, or to pre_exec() since pre_exec() has an existing relationship to io::Error.