Skip to content

Modifying a file and then executing it can fail on Linux #58964

@agocke

Description

@agocke

golang/go#22315 sets out the issue.

Fundamentally, this seems like an inescapable race in multi-threaded programs on Linux.

My understanding of the failure is this:

  1. A process with two threads wants to write a file and then execute it.
  2. Thread 1 opens a file for writing
  3. Thread 2 issues a call to create a new process and completes a fork call.
  4. The new process inherits all file descriptors open in Process 1, including the file opened by Thread 1.
  5. Thread 1 finishes writing and closes the file descriptor.
  6. Thread 1 attempts to execute the file.
  7. Linux produces ETXTBSY ("Text file is busy") because Process 2 still has an open handle to the file.

I don't see a way to completely prevent this race, as there's no way to avoid executing fork to create a new process on Linux. However, there are two mitigations we could consider:

  1. Unix supports a FD_CLOEXEC flag on file descriptors, which indicates that the file descriptor should be closed after a call to exec. Since the "new process" procedure in Unix is fork+exec, this would narrow the window of the race to just after fork and just before exec. It may be possible to always set this flag when opening file descriptors on Linux from managed code -- we don't support fork without exec and inheriting non-tty open file descriptors does not appear to be in any .NET contract.
  2. Introduce a retry into Process.Create if encountering ETXTBSY. This could workaround the issue, at the expense of taking longer to fail in a real contention situation.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions