Skip to content

current_exe() returns invalid path on linux when exe has been deleted #69343

Closed

Description

@tsurai

Calling current_exe() on linux after the original executable has been deleted or replaced results in an invalid path being returned.

use std::env::current_exe;

fn main() {
    // current_exe = /path/to/executable
    remove_file(current_exe().unwrap()).ok();
    println!("{:?}", current_exe());
}

Output

Ok("/path/to/executable (deleted)")

Desired behavior

While it is the correct behavior of the underlying /proc/self/exe to append the string (deleted) to the original pathname the result is not a valid path and might even end up pointing to a completely different file.

I would either expect the docs to explicitly mention this behavior or classify it as an error and return io::ErrorKind::NotFound accordingly.

Meta

rustc --version --verbose:

rustc 1.41.0 (5e1a79984 2020-01-27)
binary: rustc
commit-hash: 5e1a799842ba6ed4a57e91f7ab9435947482f7d8
commit-date: 2020-01-27
host: x86_64-unknown-linux-gnu
release: 1.41.0
LLVM version: 9.0

I would gladly claim this issue if you agree to it.

Activity

  1. the8472 commented on Feb 21, 2020

    @the8472
    Member

    Since (deleted) is a valid unix path it would take extra syscalls to check if it actually exists. Additionally there are other cases where /proc/self/exe may point to something that's not accessible, e.g. when mount namespaces or chroot are in play or when a process was launched via memfd_create + fexecve.

    So it probably needs a doc update. In the case of mount namespaces this might also be subject to confusion attacks, so this value generally shouldn't be given too much trust.

  2. clarfonthey commented on Feb 24, 2020

    @clarfonthey
    Contributor

    Rather than simply checking for " (deleted)", it makes more sense to open and stat /proc/self/exe and the path returned. If the inos are different, then the currently running binary isn't the same as the one at the path (it's been replaced or deleted) and an error should be returned.

    IMHO. This doesn't explicitly go against the docs on current_exe and I think it'd be good to support that behaviour.

  3. tesuji commented on Feb 24, 2020

    @tesuji
    Contributor

    Isn't it Linux only?

  4. tsurai commented on Feb 24, 2020

    @tsurai
    ContributorAuthor

    While current_exe() might return all kinds of different paths caused by symlinks or mounts it should return something that points to the executable even if you might not have the permissions to access it.

    But /path/to/exe (deleted) has at no point in time been the correct path for the executable and should thus be considered an error. In the end it comes down to how the libraries subteam wants to handle this.

  5. the8472 commented on Feb 24, 2020

    @the8472
    Member

    Rather than simply checking for " (deleted)", it makes more sense to open and stat /proc/self/exe and the path returned. If the inos are different, then the currently running binary isn't the same as the one at the path

    Does /proc/<pid>/exe have similar magical properties to /proc/<pid>/fd/*?

  6. clarfonthey commented on Feb 27, 2020

    @clarfonthey
    Contributor

    Isn't it Linux only?

    Does /proc/<pid>/exe have similar magical properties to /proc/<pid>/fd/*?

    Yes and yes.

  7. the8472 commented on Feb 27, 2020

    @the8472
    Member

    Then another option is to simply return the symlink itself instead of the target. At least as a fallback.

    After all it may be the only existing reference to an inode, e.g. in the mem_fd case

  8. bjorn3 commented on Feb 27, 2020

    @bjorn3
    Member

    That won't work if you pass the result of current_exe to another process and then exit.

  9. the8472 commented on Feb 27, 2020

    @the8472
    Member

    If that symlink was the last reference to the inode then it will never work. So if it's just a fallback you don't lose anything.

  10. Kixunil commented on Apr 23, 2020

    @Kixunil
    Contributor

    Returning the symlink itself would be a bad idea, even if /proc/<ID>/fd was returned:

    • Debugging purpose would break
    • Calculating parent directory would break
    • Even if the program doesn't exist, giving /proc/self/exe to another program would cause that other program to point to itself.
  11. the8472 commented on Apr 23, 2020

    @the8472
    Member

    Even if the program doesn't exist, giving /proc/self/exe to another program would cause that other program to point to itself.

    You would pass /proc/<pid>/exe which is valid for the lifetime of the program.

    But yes, all of these are workarounds with their own limitations. The proper solution is, at least on linux, to pass around file descriptors which are valid for their whole existence.

  12. clarfonthey commented on Apr 26, 2020

    @clarfonthey
    Contributor

    As i mentioned in the other thread, it may be worth just deprecating this API in favour of another crate which offers multiple options with different guarantees.

  13. 6 remaining items

  14. added
    A-processArea: `std::process` (note: `std::env` is A-env)
    on Nov 8, 2025
  15. sourcefrog commented on Jan 15, 2026

    @sourcefrog
    Contributor

    As i mentioned in the other thread, it may be worth just deprecating this API in favour of another crate which offers multiple options with different guarantees.

    IMO this is a basically reasonable cross-platform API to have in the standard library, even though it exposes some OS-specific (not Rust-specific) quirks (see #150824) and even though external crates could have richer APIs. In that sense it seems a bit analogous to std::process vs subcommand, or std::time vs Jiff/Time/Chrono, and similarly for other APIs.

    A really rich API for this could try to address many dimensions:

    • Do you want an FD to the current exe even if it's been deleted, or do you want a path?
    • Do you want the path from which it was once run, even if it's been deleted and renamed?
    • Do you want to know if it's been deleted?
    • If it's been renamed do you want the new name?
    • Do you want a guarantee it's safe (under some definition) to exec the target?
    • If the answer to any of these can't be known for sure, do you want the library to guess (e.g. by searching the path or returning a possibly old path)?
    • If you want one of the above but your target OS doesn't support it, do you want a compile time error or do you want a fallback?
    • What about if your target OS has the API but it doesn't work at runtime (e.g. /proc isn't mounted or a sysctl fails)?

    I'm sure that could be done in a crate but I'd rather not lose it altogether from std.

  16. bjorn3 commented on Jan 15, 2026

    @bjorn3
    Member

    If it's been renamed do you want the new name?

    Is there even an option to know the old name on Linux?

    Do you want a guarantee it's safe (under some definition) to exec the target?

    Only an fd returning api can do that in combination with fexecve. Most OSes don't have an fexecve equivalent afaik.

  17. sourcefrog commented on Jan 15, 2026

    @sourcefrog
    Contributor

    If it's been renamed do you want the new name?

    Is there even an option to know the old name on Linux?

    Do you want a guarantee it's safe (under some definition) to exec the target?

    Only an fd returning api can do that in combination with fexecve. Most OSes don't have an fexecve equivalent afaik.

    Well yes, my point is that there aren't any strongly defined behaviors that are really portable. You can use current_exe and get a rough indication of the path, with some caveats about semantics varying across platforms, or you can deal with OS-specific quirks. Someone could write a crate with per-OS precise semantics.

    Anyhow, the original comment says

    I would either expect the docs to explicitly mention this behavior or classify it as an error and return io::ErrorKind::NotFound accordingly.

    I think that's reasonable to expect. I think it's more helpful to document the Linux behavior than to hide the information altogether, so #150824 does that and perhaps it could be considered to fix this.

  18. added
    T-libsRelevant to the library team, which will review and decide on the PR/issue.
    and removed
    T-libs-api[DEPRECATED; DO NOT USE]
    on Aug 12, 2026
  19. added a commit that references this issue on Sep 26, 2026
    3eb41ed
  20. added a commit that references this issue on Sep 26, 2026
    495d5b4
  21. added a commit that references this issue on Sep 26, 2026
    c200fd4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-processArea: `std::process` (note: `std::env` is A-env)C-bugCategory: This is a bug.O-linuxOperating system: LinuxT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions