Skip to content

Allocations in pre_exec #3501

@purplesyringa

Description

@purplesyringa

As far as I'm aware, yagna is a multi-threaded application; please correct me if I'm wrong.

There are multiple locations where pre_exec closures use the system allocator:

  • golem_cli/src/command/yagna.rs:383, utils/process/src/lib.rs:{58,78}, test-utils/test-framework/src/yagna.rs:102 invoke std::io::Error::other, which allocates (see Document Error::{new,other} as to be avoided in pre_exec rust-lang/rust#148971). This is why I originally stumbled upon this problem, but that's not the only issue.
  • exe-unit/tokio-process-ns/src/pre_exec.rs allocates many times, both directly via calls to format!, and indirectly by invoking operations on paths, which require allocation to append NUL bytes.

Allocating in pre_exec is bad in multi-threaded programs. If forking happens while the allocator lock is held by another thread, deadlocks can occur, since there's no one left in the new process to unlock the mutex. I do not believe this is UB, and modern libc offer protections against this issue, but this isn't POSIX-compliant and should preferably be avoided.

A valid fix would be to use impl From<nix::Error> for std::io::Error. This also ensures the correct error code is forwarded to the parent process, instead of the default -EINVAL. I do not understand why this wasn't done in some places, and .map_err(Into::into) was used in others, since ? already performs From-conversion, but I'm not familiar with your codebase, so maybe there's a reason for that.

I could not quickly discern whether exe-unit/tokio-process-ns/src/pre_exec.rs is invoked from multi-threaded contexts. Since it's called for tokio::process::Command in exe-unit/tokio-process-ns/src/lib.rs:35, I would assume that's the case, but I'm not sure. If that's the case, the code should either be rearchitectured to allocate outside of pre_exec, or invoke non-allocating APIs from libc and avoid format!.

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