aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorLemonBoy <thatlemon@gmail.com>2021-05-20 15:26:17 +0200
committerLemonBoy <thatlemon@gmail.com>2021-05-20 15:26:17 +0200
commitabfe7f96dd45e22d43c3e14ed64e1fbb8e94b419 (patch)
treee4283d3203940eb4588d8c87f12964ad6902dfb7 /lib/std
parent992c02ab95e8297a1558bcf011f15a5cf1cd8e1b (diff)
downloadzig-abfe7f96dd45e22d43c3e14ed64e1fbb8e94b419.tar.gz
zig-abfe7f96dd45e22d43c3e14ed64e1fbb8e94b419.zip
std: Call pthread_atfork only once
Some libc implementations (glib) deduplicate identical hooks, others (musl, macos) do not and blindly append them to an internal list. Ensure there's only a single call to pthread_atfork to prevent unbounded memory use when lots of threads/forks are used.
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/crypto/tlcsprng.zig20
1 files changed, 12 insertions, 8 deletions
diff --git a/lib/std/crypto/tlcsprng.zig b/lib/std/crypto/tlcsprng.zig
index 1e39b125f6..c23e99e2dd 100644
--- a/lib/std/crypto/tlcsprng.zig
+++ b/lib/std/crypto/tlcsprng.zig
@@ -48,6 +48,16 @@ const Context = struct {
gimli: std.crypto.core.Gimli,
};
+var install_atfork_handler = std.once(struct {
+ // Install the global handler only once.
+ // The same handler is shared among threads and is inherinted by fork()-ed
+ // processes.
+ fn do() void {
+ const r = std.c.pthread_atfork(null, null, childAtForkHandler);
+ std.debug.assert(r == 0);
+ }
+}.do);
+
threadlocal var wipe_mem: []align(mem.page_size) u8 = &[_]u8{};
fn tlsCsprngFill(_: *const std.rand.Random, buffer: []u8) void {
@@ -135,14 +145,8 @@ fn tlsCsprngFill(_: *const std.rand.Random, buffer: []u8) void {
}
fn setupPthreadAtforkAndFill(buffer: []u8) void {
- const failed = std.c.pthread_atfork(null, null, childAtForkHandler) != 0;
- if (failed) {
- const ctx = @ptrCast(*Context, wipe_mem.ptr);
- ctx.init_state = .failed;
- return fillWithOsEntropy(buffer);
- } else {
- return initAndFill(buffer);
- }
+ install_atfork_handler.call();
+ return initAndFill(buffer);
}
fn childAtForkHandler() callconv(.C) void {