@@ -254,7 +254,7 @@ struct Crystal::System::Process
254254 end
255255 end
256256
257- def self.spawn (command_args , env, clear_env, input, output, error, chdir)
257+ def self.spawn (prepared_args , env, clear_env, input, output, error, chdir)
258258 r, w = FileDescriptor .system_pipe
259259
260260 pid = fork(will_exec: true ) do
@@ -266,7 +266,7 @@ struct Crystal::System::Process
266266 if ! pid
267267 LibC .close(r)
268268 begin
269- self .try_replace(command_args , env, clear_env, input, output, error, chdir)
269+ self .try_replace(prepared_args , env, clear_env, input, output, error, chdir)
270270 byte = 1 _u8
271271 errno = Errno .value.to_i32
272272 FileDescriptor .write_fully(w, pointerof (byte))
@@ -292,15 +292,15 @@ struct Crystal::System::Process
292292 when 0
293293 # Error message coming
294294 message = reader_pipe.gets_to_end
295- raise RuntimeError .new(" Error executing process: '#{ command_args [0 ]} ': #{ message } " )
295+ raise RuntimeError .new(" Error executing process: '#{ prepared_args [0 ]} ': #{ message } " )
296296 when 1
297297 # Errno coming
298298 # can't use IO#read_bytes(Int32) because we skipped system/network
299299 # endianness check when writing the integer while read_bytes would;
300300 # we thus read it in the same as order as written
301301 buf = uninitialized StaticArray (UInt8 , 4 )
302302 reader_pipe.read_fully(buf.to_slice)
303- raise_exception_from_errno(command_args [0 ], Errno .new(buf.unsafe_as(Int32 )))
303+ raise_exception_from_errno(prepared_args [0 ], Errno .new(buf.unsafe_as(Int32 )))
304304 else
305305 raise RuntimeError .new(" BUG: Invalid error response received from subprocess" )
306306 end
@@ -311,28 +311,30 @@ struct Crystal::System::Process
311311 pid
312312 end
313313
314- def self.prepare_args (command : String , args : Enumerable (String )?, shell : Bool ) : Array ( String )
314+ def self.prepare_args (command : String , args : Enumerable (String )?, shell : Bool ) : { String , LibC :: Char ** }
315315 if shell
316316 command = %( #{ command } "${@}") unless command.includes?(' ' )
317- shell_args = [" /bin/sh" , " -c" , command, " sh" ]
317+ argv_ary = [" /bin/sh" , " -c" , command, " sh" ]
318318
319319 if args
320320 unless command.includes?(%( "${@}") )
321321 raise ArgumentError .new(%( Can't specify arguments in both command and args without including "${@}" into your command) )
322322 end
323-
324- shell_args.concat(args)
325323 end
326324
327- shell_args
325+ pathname = " /bin/sh "
328326 else
329- command_args = [command]
330- command_args.concat(args) if args
331- command_args
327+ argv_ary = [command]
328+ pathname = command
332329 end
330+
331+ argv_ary.concat(args) if args
332+
333+ argv = argv_ary.map(& .check_no_null_byte.to_unsafe)
334+ {pathname, argv.to_unsafe}
333335 end
334336
335- private def self.try_replace (command_args , env , clear_env , input , output , error , chdir )
337+ private def self.try_replace (prepared_args , env , clear_env , input , output , error , chdir )
336338 reopen_io(input, ORIGINAL_STDIN )
337339 reopen_io(output, ORIGINAL_STDOUT )
338340 reopen_io(error, ORIGINAL_STDERR )
@@ -348,11 +350,7 @@ struct Crystal::System::Process
348350
349351 ::Dir .cd(chdir) if chdir
350352
351- command = command_args[0 ]
352- argv = command_args.map & .check_no_null_byte.to_unsafe
353- argv << Pointer (UInt8 ).null
354-
355- lock_write { execvpe(command, argv, LibC .environ) }
353+ lock_write { LibC .execvp(* prepared_args) }
356354 end
357355
358356 private def self.execvpe (command , argv , envp )
@@ -373,9 +371,9 @@ struct Crystal::System::Process
373371 LibC .execvp(command, argv)
374372 end
375373
376- def self.replace (command_args , env, clear_env, input, output, error, chdir)
377- try_replace(command_args , env, clear_env, input, output, error, chdir)
378- raise_exception_from_errno(command_args[ 0 ] )
374+ def self.replace (command, prepared_args , env, clear_env, input, output, error, chdir)
375+ try_replace(prepared_args , env, clear_env, input, output, error, chdir)
376+ raise_exception_from_errno(command )
379377 end
380378
381379 private def self.raise_exception_from_errno (command , errno = Errno .value)
0 commit comments