Skip to content

Commit 016c575

Browse files
committed
fix
1 parent 194e2a6 commit 016c575

File tree

1 file changed

+65
-7
lines changed
  • crates/vm/src/stdlib

1 file changed

+65
-7
lines changed

crates/vm/src/stdlib/os.rs

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,39 @@ pub(super) mod _os {
436436
Ok(())
437437
}
438438

439+
#[cfg(windows)]
440+
#[pyfunction]
441+
fn putenv(key: PyStrRef, value: PyStrRef, vm: &VirtualMachine) -> PyResult<()> {
442+
use crate::common::windows::_MAX_ENV;
443+
let key_str = key.as_str();
444+
let value_str = value.as_str();
445+
// Search from index 1 because on Windows starting '=' is allowed for
446+
// defining hidden environment variables.
447+
if key_str.is_empty()
448+
|| key_str.get(1..).is_some_and(|s| s.contains('='))
449+
|| key_str.contains('\0')
450+
|| value_str.contains('\0')
451+
{
452+
return Err(vm.new_value_error("illegal environment variable name"));
453+
}
454+
let env_str = format!("{}={}", key_str, value_str);
455+
let wide = env_str.to_wide_with_nul();
456+
if wide.len() > _MAX_ENV + 1 {
457+
return Err(vm.new_value_error(format!(
458+
"the environment variable is longer than {} characters",
459+
_MAX_ENV
460+
)));
461+
}
462+
463+
// Use _wputenv like CPython (not SetEnvironmentVariableW) to update CRT environ
464+
let result = unsafe { suppress_iph!(libc::wputenv(wide.as_ptr())) };
465+
if result != 0 {
466+
return Err(vm.new_last_errno_error());
467+
}
468+
Ok(())
469+
}
470+
471+
#[cfg(not(windows))]
439472
#[pyfunction]
440473
fn putenv(
441474
key: Either<PyStrRef, PyBytesRef>,
@@ -450,15 +483,45 @@ pub(super) mod _os {
450483
if key.is_empty() || key.contains(&b'=') {
451484
return Err(vm.new_value_error("illegal environment variable name"));
452485
}
453-
#[cfg(windows)]
454-
check_env_var_len(key.len() + value.len() + 2, vm)?;
455486
let key = super::bytes_as_os_str(key, vm)?;
456487
let value = super::bytes_as_os_str(value, vm)?;
457488
// SAFETY: requirements forwarded from the caller
458489
unsafe { env::set_var(key, value) };
459490
Ok(())
460491
}
461492

493+
#[cfg(windows)]
494+
#[pyfunction]
495+
fn unsetenv(key: PyStrRef, vm: &VirtualMachine) -> PyResult<()> {
496+
use crate::common::windows::_MAX_ENV;
497+
let key_str = key.as_str();
498+
// Search from index 1 because on Windows starting '=' is allowed for
499+
// defining hidden environment variables.
500+
if key_str.is_empty()
501+
|| key_str.get(1..).is_some_and(|s| s.contains('='))
502+
|| key_str.contains('\0')
503+
{
504+
return Err(vm.new_value_error("illegal environment variable name"));
505+
}
506+
// "key=" to unset (empty value removes the variable)
507+
let env_str = format!("{}=", key_str);
508+
let wide = env_str.to_wide_with_nul();
509+
if wide.len() > _MAX_ENV + 1 {
510+
return Err(vm.new_value_error(format!(
511+
"the environment variable is longer than {} characters",
512+
_MAX_ENV
513+
)));
514+
}
515+
516+
// Use _wputenv like CPython (not SetEnvironmentVariableW) to update CRT environ
517+
let result = unsafe { suppress_iph!(libc::wputenv(wide.as_ptr())) };
518+
if result != 0 {
519+
return Err(vm.new_last_errno_error());
520+
}
521+
Ok(())
522+
}
523+
524+
#[cfg(not(windows))]
462525
#[pyfunction]
463526
fn unsetenv(key: Either<PyStrRef, PyBytesRef>, vm: &VirtualMachine) -> PyResult<()> {
464527
let key = env_bytes_as_bytes(&key);
@@ -474,11 +537,6 @@ pub(super) mod _os {
474537
),
475538
));
476539
}
477-
#[cfg(windows)]
478-
{
479-
// For unsetenv, size is key + '=' (no value, just clearing)
480-
check_env_var_len(key.len() + 1, vm)?;
481-
}
482540
let key = super::bytes_as_os_str(key, vm)?;
483541
// SAFETY: requirements forwarded from the caller
484542
unsafe { env::remove_var(key) };

0 commit comments

Comments
 (0)