@@ -156,19 +156,11 @@ feature! {
156156#[ allow( missing_docs) ]
157157pub mod unistd;
158158
159- /*
160- *
161- * ===== Result / Error =====
162- *
163- */
164-
165- use libc:: PATH_MAX ;
166-
167- use std:: { ptr, result, slice} ;
168- use std:: ffi:: { CStr , OsStr } ;
159+ use std:: ffi:: { CStr , CString , OsStr } ;
169160use std:: mem:: MaybeUninit ;
170161use std:: os:: unix:: ffi:: OsStrExt ;
171162use std:: path:: { Path , PathBuf } ;
163+ use std:: { ptr, result, slice} ;
172164
173165use errno:: Errno ;
174166
@@ -242,12 +234,9 @@ impl NixPath for CStr {
242234 }
243235
244236 fn with_nix_path < T , F > ( & self , f : F ) -> Result < T >
245- where F : FnOnce ( & CStr ) -> T {
246- // Equivalence with the [u8] impl.
247- if self . len ( ) >= PATH_MAX as usize {
248- return Err ( Errno :: ENAMETOOLONG )
249- }
250-
237+ where
238+ F : FnOnce ( & CStr ) -> T ,
239+ {
251240 Ok ( f ( self ) )
252241 }
253242}
@@ -265,11 +254,19 @@ impl NixPath for [u8] {
265254 where
266255 F : FnOnce ( & CStr ) -> T ,
267256 {
268- if self . len ( ) >= PATH_MAX as usize {
269- return Err ( Errno :: ENAMETOOLONG ) ;
257+ // The real PATH_MAX is typically 4096, but it's statistically unlikely to have a path
258+ // longer than ~300 bytes. See the the PR description to get stats for your own machine.
259+ // https://github.com/nix-rust/nix/pull/1656
260+ //
261+ // By being smaller than a memory page, we also avoid the compiler inserting a probe frame:
262+ // https://docs.rs/compiler_builtins/latest/compiler_builtins/probestack/index.html
263+ const MAX_STACK_ALLOCATION : usize = 1024 ;
264+
265+ if self . len ( ) >= MAX_STACK_ALLOCATION {
266+ return with_nix_path_allocating ( self , f) ;
270267 }
271268
272- let mut buf = MaybeUninit :: < [ u8 ; PATH_MAX as usize ] > :: uninit ( ) ;
269+ let mut buf = MaybeUninit :: < [ u8 ; MAX_STACK_ALLOCATION ] > :: uninit ( ) ;
273270 let buf_ptr = buf. as_mut_ptr ( ) as * mut u8 ;
274271
275272 unsafe {
@@ -284,6 +281,18 @@ impl NixPath for [u8] {
284281 }
285282}
286283
284+ #[ cold]
285+ #[ inline( never) ]
286+ fn with_nix_path_allocating < T , F > ( from : & [ u8 ] , f : F ) -> Result < T >
287+ where
288+ F : FnOnce ( & CStr ) -> T ,
289+ {
290+ match CString :: new ( from) {
291+ Ok ( s) => Ok ( f ( & s) ) ,
292+ Err ( _) => Err ( Errno :: EINVAL ) ,
293+ }
294+ }
295+
287296impl NixPath for Path {
288297 fn is_empty ( & self ) -> bool {
289298 NixPath :: is_empty ( self . as_os_str ( ) )
0 commit comments