@@ -156,19 +156,11 @@ feature! {
156
156
#[ allow( missing_docs) ]
157
157
pub mod unistd;
158
158
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 } ;
169
160
use std:: mem:: MaybeUninit ;
170
161
use std:: os:: unix:: ffi:: OsStrExt ;
171
162
use std:: path:: { Path , PathBuf } ;
163
+ use std:: { ptr, result, slice} ;
172
164
173
165
use errno:: Errno ;
174
166
@@ -242,12 +234,9 @@ impl NixPath for CStr {
242
234
}
243
235
244
236
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
+ {
251
240
Ok ( f ( self ) )
252
241
}
253
242
}
@@ -265,11 +254,19 @@ impl NixPath for [u8] {
265
254
where
266
255
F : FnOnce ( & CStr ) -> T ,
267
256
{
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) ;
270
267
}
271
268
272
- let mut buf = MaybeUninit :: < [ u8 ; PATH_MAX as usize ] > :: uninit ( ) ;
269
+ let mut buf = MaybeUninit :: < [ u8 ; MAX_STACK_ALLOCATION ] > :: uninit ( ) ;
273
270
let buf_ptr = buf. as_mut_ptr ( ) as * mut u8 ;
274
271
275
272
unsafe {
@@ -284,6 +281,18 @@ impl NixPath for [u8] {
284
281
}
285
282
}
286
283
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
+
287
296
impl NixPath for Path {
288
297
fn is_empty ( & self ) -> bool {
289
298
NixPath :: is_empty ( self . as_os_str ( ) )
0 commit comments