# Does rust abstract file operations incorrectly?

**URL:** <https://internals.rust-lang.org/t/does-rust-abstract-file-operations-incorrectly/24560>\
**Category:** Unsafe Code Guidelines\
**Created:** [August 28, 2026, 4:42am UTC](https://internals.rust-lang.org/t/does-rust-abstract-file-operations-incorrectly/24560 "2026-08-28T04:42:03Z")\
**Posts on this page:** 1\
**Showing post:** 5

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [August 28, 2026, 11:58am UTC](https://internals.rust-lang.org/t/does-rust-abstract-file-operations-incorrectly/24560/5 "2026-08-28T11:58:50Z")

</div>

You have to consider that programs operate on a lot of exclusively owned resources, e.g. mmap'd database files. Interfering with those can lead to UB. To be able to do those things safely the hand-wavy rule is "don't touch FDs you have no right to touch". IO-safety rules are a bit more formalized version of that.

For an inherited resource someone has to decide whether it's a single-owner that grabs it at program startup or a shared resource. Someone has to make that decision, Rust can't make it for you and the implicit IPC protocols are underspecified in that area, so the programmer has to make a choice. This results in the need for `unsafe` code where the programmer makes the choice and then has to ensure that it is upheld for the rest of the program.

* * *

> try\_clone exists and is a "safe" function. In other words two threads could get access to a single file _description_ and modify it simultaneously which, while technically within the posix spec, would still result in race conditions if both tried to edit/seek/modify their separate "owned" instances at the same time.

You don't need `try_clone` for that, you can share a `&File` across threads and get concurrent access to the same fd. This isn't unsafe and it's perfectly fine in many cases such as O\_APPEND files, datagram sockets, eventfd, ...

> because inheriting file descriptors is both possible and frequent in all major operating systems, yet rusts' abstractions make the feature universally unsafe so either a developer must give up a fairly major part of I/O _or_ they must break the guarantees that rust makes about file descriptors, and

It's somewhat possible, but hard to get right. File descriptors are shared global program state. So all parts of the program have to agree on ownership. And if you're coordinating through environment variables then the FD state needs to stay consistent with the environment variables.

So recommended patterns would be:

- use unix domain sockets in the filesystem or abstract-namespace, then use SCM\_RIGHTS for passing to a single receiver
- or on linux:
  - pass as a path to `/proc/<other process id>/fd/N` instead of inheritance
  - use `pidfd_getfd()`

- do the setup early during single-threaded main
- add safety nets such as including dev/ino in the environment variable so that a child can crosscheck
  - Afaik systemd do this in some cases

- use `BorrowedFd<'static>` instead of `OwnedFd` if it's a shared resource
- in cases where you take ownership
  - if you set O\_CLOEXEC also unset the environment variables
  - also use `try_clone_to_owned/try_clone` to renumber the Fd and close the original to make incorrect shared access more obvious

---

_[View the full topic](https://internals.rust-lang.org/t/does-rust-abstract-file-operations-incorrectly/24560)._
