Remove PATH_MAX restriction from with_nix_path

Signed-off-by: Alex Saveau <saveau.alexandre@gmail.com>
This commit is contained in:
Alex Saveau 2022-02-02 19:40:50 -08:00
parent 15af9b6d81
commit 378a66dd18
No known key found for this signature in database
GPG Key ID: 3F8D5B16EB169D48
2 changed files with 31 additions and 19 deletions

View File

@ -64,6 +64,9 @@ This project adheres to [Semantic Versioning](https://semver.org/).
Because of this change, you now need `use std::iter::Extend` to call `extend`
on a `SigSet`.
(#[1553](https://github.com/nix-rust/nix/pull/1553))
- Removed the the `PATH_MAX` restriction from APIs accepting paths. Paths
will now be allocated on the heap if they are too long. In addition, large
instruction count improvements (~30x) were made to path handling.
### Fixed

View File

@ -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())