Skip to content

Commit 30e2e43

Browse files
committed
Use _NSGetEnviron instead of environ on iOS/tvOS/watchOS/visionOS
This should be slightly more correct, and matches the implementation in other programming languages: - [Python's `os.environ`](https://github.com/python/cpython/blob/v3.12.3/Modules/posixmodule.c#L1562-L1566). - [Swift's `Darwin.environ`](https://github.com/apple/swift-corelibs-foundation/blob/swift-5.10-RELEASE/CoreFoundation/Base.subproj/CFPlatform.c#L1811-L1812), though that library is bundled on the system, so they can change it if they want. - [Dart/Flutter](https://github.com/dart-lang/sdk/blob/3.4.0/runtime/bin/platform_macos.cc#L205-L234), doesn't support environment variables on iOS. - Node seems to not be entirely consistent with it: - [`process.c`](https://github.com/nodejs/node/blob/v22.1.0/deps/uv/src/unix/process.c#L38). - [`unix/core.c`](https://github.com/nodejs/node/blob/v22.1.0/deps/uv/src/unix/core.c#L59). - [.NET/Xamarin](https://github.com/dotnet/runtime/blob/v8.0.5/src/native/libs/configure.cmake#L1099-L1106). - [OpenJDK](https://github.com/openjdk/jdk/blob/jdk-23%2B22/src/java.base/unix/native/libjava/ProcessEnvironment_md.c#L31-L33).
1 parent b30cbc8 commit 30e2e43

File tree

1 file changed

+26
-2
lines changed
  • std/src/sys/pal/unix

1 file changed

+26
-2
lines changed

std/src/sys/pal/unix/os.rs

+26-2
Original file line numberDiff line numberDiff line change
@@ -576,12 +576,36 @@ impl Iterator for Env {
576576
}
577577
}
578578

579-
#[cfg(target_os = "macos")]
579+
// Use `_NSGetEnviron` on Apple platforms.
580+
//
581+
// `_NSGetEnviron` is the documented alternative (see `man environ`), and has
582+
// been available since the first versions of both macOS and iOS.
583+
//
584+
// Nowadays, specifically since macOS 10.8, `environ` has been exposed through
585+
// `libdyld.dylib`, which is linked via. `libSystem.dylib`:
586+
// <https://github.com/apple-oss-distributions/dyld/blob/dyld-1160.6/libdyld/libdyldGlue.cpp#L913>
587+
//
588+
// So in the end, it likely doesn't really matter which option we use, but the
589+
// performance cost of using `_NSGetEnviron` is extremely miniscule, and it
590+
// might be ever so slightly more supported, so let's just use that.
591+
//
592+
// NOTE: The header where this is defined (`crt_externs.h`) was added to the
593+
// iOS 13.0 SDK, which has been the source of a great deal of confusion in the
594+
// past about the availability of this API.
595+
//
596+
// NOTE(madsmtm): Neither this nor using `environ` has been verified to not
597+
// cause App Store rejections; if this is found to be the case, an alternative
598+
// implementation of this is possible using `[NSProcessInfo environment]`
599+
// - which internally uses `_NSGetEnviron` and a system-wide lock on the
600+
// environment variables to protect against `setenv`, so using that might be
601+
// desirable anyhow? Though it also means that we have to link to Foundation.
602+
#[cfg(target_vendor = "apple")]
580603
pub unsafe fn environ() -> *mut *const *const c_char {
581604
libc::_NSGetEnviron() as *mut *const *const c_char
582605
}
583606

584-
#[cfg(not(target_os = "macos"))]
607+
// Use the `environ` static which is part of POSIX.
608+
#[cfg(not(target_vendor = "apple"))]
585609
pub unsafe fn environ() -> *mut *const *const c_char {
586610
extern "C" {
587611
static mut environ: *const *const c_char;

0 commit comments

Comments
 (0)