Skip to content

Commit cbf5f02

Browse files
committed
exec
1 parent 0638147 commit cbf5f02

File tree

1 file changed

+203
-2
lines changed
  • crates/vm/src/stdlib

1 file changed

+203
-2
lines changed

crates/vm/src/stdlib/nt.rs

Lines changed: 203 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,12 +263,143 @@ pub(crate) mod module {
263263
#[cfg(target_env = "msvc")]
264264
unsafe extern "C" {
265265
fn _wexecv(cmdname: *const u16, argv: *const *const u16) -> intptr_t;
266+
fn _wexecve(
267+
cmdname: *const u16,
268+
argv: *const *const u16,
269+
envp: *const *const u16,
270+
) -> intptr_t;
271+
fn _wspawnv(mode: i32, cmdname: *const u16, argv: *const *const u16) -> intptr_t;
272+
fn _wspawnve(
273+
mode: i32,
274+
cmdname: *const u16,
275+
argv: *const *const u16,
276+
envp: *const *const u16,
277+
) -> intptr_t;
278+
}
279+
280+
#[cfg(target_env = "msvc")]
281+
#[pyfunction]
282+
fn spawnv(
283+
mode: i32,
284+
path: OsPath,
285+
argv: Either<PyListRef, PyTupleRef>,
286+
vm: &VirtualMachine,
287+
) -> PyResult<intptr_t> {
288+
use std::iter::once;
289+
290+
let make_widestring =
291+
|s: &str| widestring::WideCString::from_os_str(s).map_err(|err| err.to_pyexception(vm));
292+
293+
let path = path.to_wide_cstring(vm)?;
294+
295+
let argv = vm.extract_elements_with(argv.as_ref(), |obj| {
296+
let arg = PyStrRef::try_from_object(vm, obj)?;
297+
make_widestring(arg.as_str())
298+
})?;
299+
300+
let first = argv
301+
.first()
302+
.ok_or_else(|| vm.new_value_error("spawnv() arg 3 must not be empty"))?;
303+
304+
if first.is_empty() {
305+
return Err(vm.new_value_error("spawnv() arg 3 first element cannot be empty"));
306+
}
307+
308+
let argv_spawn: Vec<*const u16> = argv
309+
.iter()
310+
.map(|v| v.as_ptr())
311+
.chain(once(std::ptr::null()))
312+
.collect();
313+
314+
let result = unsafe { suppress_iph!(_wspawnv(mode, path.as_ptr(), argv_spawn.as_ptr())) };
315+
if result == -1 {
316+
Err(errno_err(vm))
317+
} else {
318+
Ok(result)
319+
}
320+
}
321+
322+
#[cfg(target_env = "msvc")]
323+
#[pyfunction]
324+
fn spawnve(
325+
mode: i32,
326+
path: OsPath,
327+
argv: Either<PyListRef, PyTupleRef>,
328+
env: PyDictRef,
329+
vm: &VirtualMachine,
330+
) -> PyResult<intptr_t> {
331+
use std::iter::once;
332+
333+
let make_widestring =
334+
|s: &str| widestring::WideCString::from_os_str(s).map_err(|err| err.to_pyexception(vm));
335+
336+
let path = path.to_wide_cstring(vm)?;
337+
338+
let argv = vm.extract_elements_with(argv.as_ref(), |obj| {
339+
let arg = PyStrRef::try_from_object(vm, obj)?;
340+
make_widestring(arg.as_str())
341+
})?;
342+
343+
let first = argv
344+
.first()
345+
.ok_or_else(|| vm.new_value_error("spawnve() arg 2 cannot be empty"))?;
346+
347+
if first.is_empty() {
348+
return Err(vm.new_value_error("spawnve() arg 2 first element cannot be empty"));
349+
}
350+
351+
let argv_spawn: Vec<*const u16> = argv
352+
.iter()
353+
.map(|v| v.as_ptr())
354+
.chain(once(std::ptr::null()))
355+
.collect();
356+
357+
// Build environment strings as "KEY=VALUE\0" wide strings
358+
let mut env_strings: Vec<widestring::WideCString> = Vec::new();
359+
for (key, value) in env.into_iter() {
360+
let key = PyStrRef::try_from_object(vm, key)?;
361+
let value = PyStrRef::try_from_object(vm, value)?;
362+
let key_str = key.as_str();
363+
let value_str = value.as_str();
364+
365+
// Validate: no null characters in key or value
366+
if key_str.contains('\0') || value_str.contains('\0') {
367+
return Err(vm.new_value_error("embedded null character"));
368+
}
369+
// Validate: no '=' in key
370+
if key_str.contains('=') {
371+
return Err(vm.new_value_error("illegal environment variable name"));
372+
}
373+
374+
let env_str = format!("{}={}", key_str, value_str);
375+
env_strings.push(make_widestring(&env_str)?);
376+
}
377+
378+
let envp: Vec<*const u16> = env_strings
379+
.iter()
380+
.map(|s| s.as_ptr())
381+
.chain(once(std::ptr::null()))
382+
.collect();
383+
384+
let result = unsafe {
385+
suppress_iph!(_wspawnve(
386+
mode,
387+
path.as_ptr(),
388+
argv_spawn.as_ptr(),
389+
envp.as_ptr()
390+
))
391+
};
392+
if result == -1 {
393+
Err(errno_err(vm))
394+
} else {
395+
Ok(result)
396+
}
266397
}
267398

268399
#[cfg(target_env = "msvc")]
269400
#[pyfunction]
270401
fn execv(
271-
path: PyStrRef,
402+
path: OsPath,
272403
argv: Either<PyListRef, PyTupleRef>,
273404
vm: &VirtualMachine,
274405
) -> PyResult<()> {
@@ -277,7 +408,7 @@ pub(crate) mod module {
277408
let make_widestring =
278409
|s: &str| widestring::WideCString::from_os_str(s).map_err(|err| err.to_pyexception(vm));
279410

280-
let path = make_widestring(path.as_str())?;
411+
let path = path.to_wide_cstring(vm)?;
281412

282413
let argv = vm.extract_elements_with(argv.as_ref(), |obj| {
283414
let arg = PyStrRef::try_from_object(vm, obj)?;
@@ -305,6 +436,76 @@ pub(crate) mod module {
305436
}
306437
}
307438

439+
#[cfg(target_env = "msvc")]
440+
#[pyfunction]
441+
fn execve(
442+
path: OsPath,
443+
argv: Either<PyListRef, PyTupleRef>,
444+
env: PyDictRef,
445+
vm: &VirtualMachine,
446+
) -> PyResult<()> {
447+
use std::iter::once;
448+
449+
let make_widestring =
450+
|s: &str| widestring::WideCString::from_os_str(s).map_err(|err| err.to_pyexception(vm));
451+
452+
let path = path.to_wide_cstring(vm)?;
453+
454+
let argv = vm.extract_elements_with(argv.as_ref(), |obj| {
455+
let arg = PyStrRef::try_from_object(vm, obj)?;
456+
make_widestring(arg.as_str())
457+
})?;
458+
459+
let first = argv
460+
.first()
461+
.ok_or_else(|| vm.new_value_error("execve: argv must not be empty"))?;
462+
463+
if first.is_empty() {
464+
return Err(vm.new_value_error("execve: argv first element cannot be empty"));
465+
}
466+
467+
let argv_execve: Vec<*const u16> = argv
468+
.iter()
469+
.map(|v| v.as_ptr())
470+
.chain(once(std::ptr::null()))
471+
.collect();
472+
473+
// Build environment strings as "KEY=VALUE\0" wide strings
474+
let mut env_strings: Vec<widestring::WideCString> = Vec::new();
475+
for (key, value) in env.into_iter() {
476+
let key = PyStrRef::try_from_object(vm, key)?;
477+
let value = PyStrRef::try_from_object(vm, value)?;
478+
let key_str = key.as_str();
479+
let value_str = value.as_str();
480+
481+
// Validate: no null characters in key or value
482+
if key_str.contains('\0') || value_str.contains('\0') {
483+
return Err(vm.new_value_error("embedded null character"));
484+
}
485+
// Validate: no '=' in key
486+
if key_str.contains('=') {
487+
return Err(vm.new_value_error("illegal environment variable name"));
488+
}
489+
490+
let env_str = format!("{}={}", key_str, value_str);
491+
env_strings.push(make_widestring(&env_str)?);
492+
}
493+
494+
let envp: Vec<*const u16> = env_strings
495+
.iter()
496+
.map(|s| s.as_ptr())
497+
.chain(once(std::ptr::null()))
498+
.collect();
499+
500+
if (unsafe { suppress_iph!(_wexecve(path.as_ptr(), argv_execve.as_ptr(), envp.as_ptr())) }
501+
== -1)
502+
{
503+
Err(errno_err(vm))
504+
} else {
505+
Ok(())
506+
}
507+
}
508+
308509
#[pyfunction]
309510
fn _getfinalpathname(path: OsPath, vm: &VirtualMachine) -> PyResult {
310511
let real = path

0 commit comments

Comments
 (0)