diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 47 |
1 files changed, 28 insertions, 19 deletions
@@ -156,19 +156,11 @@ feature! { #[allow(missing_docs)] pub mod unistd; -/* - * - * ===== Result / Error ===== - * - */ - -use libc::PATH_MAX; - -use std::{ptr, result, slice}; -use std::ffi::{CStr, OsStr}; +use std::ffi::{CStr, CString, OsStr}; use std::mem::MaybeUninit; use std::os::unix::ffi::OsStrExt; use std::path::{Path, PathBuf}; +use std::{ptr, result, slice}; use errno::Errno; @@ -242,12 +234,9 @@ impl NixPath for CStr { } fn with_nix_path<T, F>(&self, f: F) -> Result<T> - where F: FnOnce(&CStr) -> T { - // Equivalence with the [u8] impl. - if self.len() >= PATH_MAX as usize { - return Err(Errno::ENAMETOOLONG) - } - + where + F: FnOnce(&CStr) -> T, + { Ok(f(self)) } } @@ -265,11 +254,19 @@ impl NixPath for [u8] { where F: FnOnce(&CStr) -> T, { - if self.len() >= PATH_MAX as usize { - return Err(Errno::ENAMETOOLONG); + // The real PATH_MAX is typically 4096, but it's statistically unlikely to have a path + // longer than ~300 bytes. See the the PR description to get stats for your own machine. + // https://github.com/nix-rust/nix/pull/1656 + // + // By being smaller than a memory page, we also avoid the compiler inserting a probe frame: + // https://docs.rs/compiler_builtins/latest/compiler_builtins/probestack/index.html + const MAX_STACK_ALLOCATION: usize = 1024; + + if self.len() >= MAX_STACK_ALLOCATION { + return with_nix_path_allocating(self, f); } - let mut buf = MaybeUninit::<[u8; PATH_MAX as usize]>::uninit(); + let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit(); let buf_ptr = buf.as_mut_ptr() as *mut u8; unsafe { @@ -284,6 +281,18 @@ impl NixPath for [u8] { } } +#[cold] +#[inline(never)] +fn with_nix_path_allocating<T, F>(from: &[u8], f: F) -> Result<T> +where + F: FnOnce(&CStr) -> T, +{ + match CString::new(from) { + Ok(s) => Ok(f(&s)), + Err(_) => Err(Errno::EINVAL), + } +} + impl NixPath for Path { fn is_empty(&self) -> bool { NixPath::is_empty(self.as_os_str()) |