Skip to content

On Darwin, lock access to the environ block. #403

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 7, 2024

Conversation

grynspan
Copy link
Contributor

@grynspan grynspan commented May 7, 2024

This PR adds calls to Darwin's internal libc functions environ_lock_np() and environ_unlock_np() when directly accessing the environ block (via the CRT function _NSGetEnviron().)

These calls are necessary because direct access to environ is not thread-safe by default. The standard library guards accesses to getenv() and setenv(), but environ is a global variable and neither it nor _NSGetEnviron() can be made thread-safe internally.

This change does not prevent data races when using the result of getenv(), but short of a new copyenv_np() or getenv_r() function, there's not much we can do about it. This change has no effect on Linux since it doesn't have these non-portable functions, but if equivalents are added in the future, we can add support too. Windows' GetEnvironmentStringsW() API returns a copy of the environment block, so it doesn't need a lock.

Compare Foundation's use here.

Checklist:

  • Code and documentation should follow the style of the Style Guide.
  • If public symbols are renamed or modified, DocC references should be updated.

This PR adds calls to Darwin's internal libc functions `environ_lock_np()` and
`environ_unlock_np()` when directly accessing the `environ` block (via the CRT
function `_NSGetEnviron()`.)

These calls are necessary because direct access to `environ` is not thread-safe
by default. The standard library guards accesses to `getenv()` and `setenv()`,
but `environ` is a global variable and neither it nor `_NSGetEnviron()` can be
made thread-safe internally.

This change does not prevent data races when using the result of `getenv()`, but
short of a new `copyenv_np()` or `getenv_r()` function, there's not much we can
do about it. This change has no effect on Linux since it doesn't have these
non-portable functions, but if equivalents are added in the future, we can add
support too. Windows' `GetEnvironmentStringsW()` API returns a copy of the
environment block, so it doesn't need a lock.

Compare Foundation's use [here](https://github.com/apple/swift-foundation/blob/main/Sources/_CShims/platform_shims.c).
@grynspan grynspan added bug 🪲 Something isn't working concurrency 🔀 Swift concurrency/sendability issues darwin 🍎 macOS, iOS, watchOS, tvOS, and visionOS support labels May 7, 2024
@grynspan grynspan self-assigned this May 7, 2024
@grynspan
Copy link
Contributor Author

grynspan commented May 7, 2024

@swift-ci please test

@grynspan
Copy link
Contributor Author

grynspan commented May 7, 2024

@swift-ci please test

@grynspan grynspan merged commit d84ec9e into main May 7, 2024
@grynspan grynspan deleted the jgrynspan/thread-safe-environ-access branch May 7, 2024 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🪲 Something isn't working concurrency 🔀 Swift concurrency/sendability issues darwin 🍎 macOS, iOS, watchOS, tvOS, and visionOS support
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants