@@ -318,22 +318,25 @@ impl Error for VarError {
318318///
319319/// # Safety
320320///
321- /// Even though this function is currently not marked as `unsafe`, it needs to
322- /// be because invoking it can cause undefined behaviour. The function will be
323- /// marked `unsafe` in a future version of Rust. This is tracked in
324- /// [rust#27970](https://github.com/rust-lang/rust/issues/27970).
325- ///
326321/// This function is safe to call in a single-threaded program.
327322///
328- /// In multi-threaded programs, you must ensure that are no other threads
329- /// concurrently writing or *reading*(!) from the environment through functions
330- /// other than the ones in this module. You are responsible for figuring out
331- /// how to achieve this, but we strongly suggest not using `set_var` or
332- /// `remove_var` in multi-threaded programs at all.
333- ///
334- /// Most C libraries, including libc itself do not advertise which functions
335- /// read from the environment. Even functions from the Rust standard library do
336- /// that, e.g. for DNS lookups from [`std::net::ToSocketAddrs`].
323+ /// This function is also always safe to call on Windows, in single-threaded
324+ /// and multi-threaded programs.
325+ ///
326+ /// In multi-threaded programs on other operating systems, we strongly suggest
327+ /// not using `set_var` or `remove_var` at all. The exact requirement is: you
328+ /// must ensure that there are no other threads concurrently writing or
329+ /// *reading*(!) the environment through functions or global variables other
330+ /// than the ones in this module. The problem is that these operating systems
331+ /// do not provide a thread-safe way to read the environment, and most C
332+ /// libraries, including libc itself, do not advertise which functions read
333+ /// from the environment. Even functions from the Rust standard library may
334+ /// read the environment without going through this module, e.g. for DNS
335+ /// lookups from [`std::net::ToSocketAddrs`]. No stable guarantee is made about
336+ /// which functions may read from the environment in future versions of a
337+ /// library. All this makes it not practically possible for you to guarantee
338+ /// that no other thread will read the environment, so the only safe option is
339+ /// to not use `set_var` or `remove_var` in multi-threaded programs at all.
337340///
338341/// Discussion of this unsafety on Unix may be found in:
339342///
@@ -353,15 +356,26 @@ impl Error for VarError {
353356/// use std::env;
354357///
355358/// let key = "KEY";
356- /// env::set_var(key, "VALUE");
359+ /// unsafe {
360+ /// env::set_var(key, "VALUE");
361+ /// }
357362/// assert_eq!(env::var(key), Ok("VALUE".to_string()));
358363/// ```
364+ #[ cfg( not( bootstrap) ) ]
365+ #[ rustc_deprecated_safe_2024]
359366#[ stable( feature = "env" , since = "1.0.0" ) ]
360- pub fn set_var < K : AsRef < OsStr > , V : AsRef < OsStr > > ( key : K , value : V ) {
367+ pub unsafe fn set_var < K : AsRef < OsStr > , V : AsRef < OsStr > > ( key : K , value : V ) {
361368 _set_var ( key. as_ref ( ) , value. as_ref ( ) )
362369}
363370
364- fn _set_var ( key : & OsStr , value : & OsStr ) {
371+ #[ cfg( bootstrap) ]
372+ #[ allow( missing_docs) ]
373+ #[ stable( feature = "env" , since = "1.0.0" ) ]
374+ pub fn set_var < K : AsRef < OsStr > , V : AsRef < OsStr > > ( key : K , value : V ) {
375+ unsafe { _set_var ( key. as_ref ( ) , value. as_ref ( ) ) }
376+ }
377+
378+ unsafe fn _set_var ( key : & OsStr , value : & OsStr ) {
365379 os_imp:: setenv ( key, value) . unwrap_or_else ( |e| {
366380 panic ! ( "failed to set environment variable `{key:?}` to `{value:?}`: {e}" )
367381 } )
@@ -371,22 +385,25 @@ fn _set_var(key: &OsStr, value: &OsStr) {
371385///
372386/// # Safety
373387///
374- /// Even though this function is currently not marked as `unsafe`, it needs to
375- /// be because invoking it can cause undefined behaviour. The function will be
376- /// marked `unsafe` in a future version of Rust. This is tracked in
377- /// [rust#27970](https://github.com/rust-lang/rust/issues/27970).
378- ///
379388/// This function is safe to call in a single-threaded program.
380389///
381- /// In multi-threaded programs, you must ensure that are no other threads
382- /// concurrently writing or *reading*(!) from the environment through functions
383- /// other than the ones in this module. You are responsible for figuring out
384- /// how to achieve this, but we strongly suggest not using `set_var` or
385- /// `remove_var` in multi-threaded programs at all.
386- ///
387- /// Most C libraries, including libc itself do not advertise which functions
388- /// read from the environment. Even functions from the Rust standard library do
389- /// that, e.g. for DNS lookups from [`std::net::ToSocketAddrs`].
390+ /// This function is also always safe to call on Windows, in single-threaded
391+ /// and multi-threaded programs.
392+ ///
393+ /// In multi-threaded programs on other operating systems, we strongly suggest
394+ /// not using `set_var` or `remove_var` at all. The exact requirement is: you
395+ /// must ensure that there are no other threads concurrently writing or
396+ /// *reading*(!) the environment through functions or global variables other
397+ /// than the ones in this module. The problem is that these operating systems
398+ /// do not provide a thread-safe way to read the environment, and most C
399+ /// libraries, including libc itself, do not advertise which functions read
400+ /// from the environment. Even functions from the Rust standard library may
401+ /// read the environment without going through this module, e.g. for DNS
402+ /// lookups from [`std::net::ToSocketAddrs`]. No stable guarantee is made about
403+ /// which functions may read from the environment in future versions of a
404+ /// library. All this makes it not practically possible for you to guarantee
405+ /// that no other thread will read the environment, so the only safe option is
406+ /// to not use `set_var` or `remove_var` in multi-threaded programs at all.
390407///
391408/// Discussion of this unsafety on Unix may be found in:
392409///
@@ -403,22 +420,35 @@ fn _set_var(key: &OsStr, value: &OsStr) {
403420///
404421/// # Examples
405422///
406- /// ```
423+ /// ```no_run
407424/// use std::env;
408425///
409426/// let key = "KEY";
410- /// env::set_var(key, "VALUE");
427+ /// unsafe {
428+ /// env::set_var(key, "VALUE");
429+ /// }
411430/// assert_eq!(env::var(key), Ok("VALUE".to_string()));
412431///
413- /// env::remove_var(key);
432+ /// unsafe {
433+ /// env::remove_var(key);
434+ /// }
414435/// assert!(env::var(key).is_err());
415436/// ```
437+ #[ cfg( not( bootstrap) ) ]
438+ #[ rustc_deprecated_safe_2024]
416439#[ stable( feature = "env" , since = "1.0.0" ) ]
417- pub fn remove_var < K : AsRef < OsStr > > ( key : K ) {
440+ pub unsafe fn remove_var < K : AsRef < OsStr > > ( key : K ) {
418441 _remove_var ( key. as_ref ( ) )
419442}
420443
421- fn _remove_var ( key : & OsStr ) {
444+ #[ cfg( bootstrap) ]
445+ #[ allow( missing_docs) ]
446+ #[ stable( feature = "env" , since = "1.0.0" ) ]
447+ pub fn remove_var < K : AsRef < OsStr > > ( key : K ) {
448+ unsafe { _remove_var ( key. as_ref ( ) ) }
449+ }
450+
451+ unsafe fn _remove_var ( key : & OsStr ) {
422452 os_imp:: unsetenv ( key)
423453 . unwrap_or_else ( |e| panic ! ( "failed to remove environment variable `{key:?}`: {e}" ) )
424454}
0 commit comments