@@ -137,12 +137,42 @@ impl Command {
137137 /// Returns a `true` if we're pretty sure that this'll blow OS spawn limits,
138138 /// or `false` if we should attempt to spawn and see what the OS says.
139139 pub ( crate ) fn very_likely_to_exceed_some_spawn_limit ( & self ) -> bool {
140- // We mostly only care about Windows in this method, on Unix the limits
141- // can be gargantuan anyway so we're pretty unlikely to hit them
142- if cfg ! ( unix) {
140+ #[ cfg( not( any( windows, unix) ) ) ]
141+ {
143142 return false ;
144143 }
145144
145+ // On Unix the limits can be gargantuan anyway so we're pretty
146+ // unlikely to hit them, but might still exceed it.
147+ // We consult ARG_MAX here to get an estimate.
148+ #[ cfg( unix) ]
149+ {
150+ let ptr_size = mem:: size_of :: < usize > ( ) ;
151+ // arg + \0 + pointer
152+ let args_size = self . args . iter ( ) . fold ( 0usize , |acc, a| {
153+ let arg = a. as_encoded_bytes ( ) . len ( ) ;
154+ let nul = 1 ;
155+ acc. saturating_add ( arg) . saturating_add ( nul) . saturating_add ( ptr_size)
156+ } ) ;
157+ // key + `=` + value + \0 + pointer
158+ let envs_size = self . env . iter ( ) . fold ( 0usize , |acc, ( k, v) | {
159+ let k = k. as_encoded_bytes ( ) . len ( ) ;
160+ let eq = 1 ;
161+ let v = v. as_encoded_bytes ( ) . len ( ) ;
162+ let nul = 1 ;
163+ acc. saturating_add ( k)
164+ . saturating_add ( eq)
165+ . saturating_add ( v)
166+ . saturating_add ( nul)
167+ . saturating_add ( ptr_size)
168+ } ) ;
169+ let arg_max = match unsafe { libc:: sysconf ( libc:: _SC_ARG_MAX) } {
170+ -1 => return false , // Go to OS anyway.
171+ max => max as usize ,
172+ } ;
173+ return args_size. saturating_add ( envs_size) > arg_max;
174+ }
175+
146176 // Ok so on Windows to spawn a process is 32,768 characters in its
147177 // command line [1]. Unfortunately we don't actually have access to that
148178 // as it's calculated just before spawning. Instead we perform a
@@ -165,9 +195,14 @@ impl Command {
165195 //
166196 // [1]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa
167197 // [2]: https://devblogs.microsoft.com/oldnewthing/?p=41553
168-
169- let estimated_command_line_len = self . args . iter ( ) . map ( |a| a. len ( ) ) . sum :: < usize > ( ) ;
170- estimated_command_line_len > 1024 * 6
198+ #[ cfg( windows) ]
199+ {
200+ let estimated_command_line_len = self
201+ . args
202+ . iter ( )
203+ . fold ( 0usize , |acc, a| acc. saturating_add ( a. as_encoded_bytes ( ) . len ( ) ) ) ;
204+ return estimated_command_line_len > 1024 * 6 ;
205+ }
171206 }
172207}
173208
0 commit comments