From d05156eb71b521b0b7bbd8332f0c81b55244c087 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl=20=C3=85stholm?= Date: Fri, 7 Nov 2025 22:01:40 +0100 Subject: [PATCH 1/2] Don't pull in a dependency on `pthread_kill` in single-threaded builds Fixes a regression preventing single-threaded Emscripten builds from linking successfully without passing `-pthread` to emcc. --- lib/std/Io/Threaded.zig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index 2d569f8f9cb9..2cef8a739e3e 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -797,9 +797,10 @@ fn await( result_alignment: std.mem.Alignment, ) void { _ = result_alignment; + if (builtin.single_threaded) return; const t: *Threaded = @ptrCast(@alignCast(userdata)); - const closure: *AsyncClosure = @ptrCast(@alignCast(any_future)); - closure.waitAndDeinit(t.allocator, result); + const ac: *AsyncClosure = @ptrCast(@alignCast(any_future)); + ac.waitAndDeinit(t.allocator, result); } fn cancel( @@ -809,6 +810,7 @@ fn cancel( result_alignment: std.mem.Alignment, ) void { _ = result_alignment; + if (builtin.single_threaded) return; const t: *Threaded = @ptrCast(@alignCast(userdata)); const ac: *AsyncClosure = @ptrCast(@alignCast(any_future)); ac.closure.requestCancel(); From 3f1e290b45b1013109a0d9943430545e0aa42c56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl=20=C3=85stholm?= Date: Fri, 7 Nov 2025 22:15:30 +0100 Subject: [PATCH 2/2] Use `mmap` `std.heap.page_allocator` impl when compiling for Wasm + libc When linking libc, it should be the libc that manages the heap. The main Wasm memory might have been configured as non-growable, which makes `WasmAllocator` a poor default and causes the common `DebugAllocator` use case fail with OOM errors unless the user uses `std_options` to override the default page allocator. Additionally, on Emscripten, growing Wasm memory without notifying the JS glue code will cause array buffers to get detached and lead to spurious crashes. --- lib/std/c.zig | 15 +++++++++++++-- lib/std/heap.zig | 2 +- lib/std/os/emscripten.zig | 9 --------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/std/c.zig b/lib/std/c.zig index 326b587b511d..55a219b97b8b 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -1830,7 +1830,16 @@ pub const POLL = switch (native_os) { /// Basic memory protection flags pub const PROT = switch (native_os) { .linux => linux.PROT, - .emscripten => emscripten.PROT, + // https://github.com/emscripten-core/emscripten/blob/08e2de1031913e4ba7963b1c56f35f036a7d4d56/system/lib/libc/musl/include/sys/mman.h#L57-L62 + // lib/libc/include/wasm-wasi-musl/sys/mman.h + .emscripten, .wasi => struct { + pub const NONE = 0; + pub const READ = 1; + pub const WRITE = 2; + pub const EXEC = 4; + pub const GROWSDOWN = 0x01000000; + pub const GROWSUP = 0x02000000; + }, // https://github.com/SerenityOS/serenity/blob/6d59d4d3d9e76e39112842ec487840828f1c9bfe/Kernel/API/POSIX/sys/mman.h#L28-L31 .openbsd, .haiku, .dragonfly, .netbsd, .illumos, .freebsd, .windows, .serenity => struct { /// page can not be accessed @@ -8692,7 +8701,9 @@ pub const O = switch (native_os) { pub const MAP = switch (native_os) { .linux => linux.MAP, - .emscripten => packed struct(u32) { + // https://github.com/emscripten-core/emscripten/blob/08e2de1031913e4ba7963b1c56f35f036a7d4d56/system/lib/libc/musl/include/sys/mman.h#L21-L39 + // lib/libc/include/wasm-wasi-musl/sys/mman.h + .emscripten, .wasi => packed struct(u32) { TYPE: enum(u4) { SHARED = 0x01, PRIVATE = 0x02, diff --git a/lib/std/heap.zig b/lib/std/heap.zig index c35e6f6684b5..00e7f3154269 100644 --- a/lib/std/heap.zig +++ b/lib/std/heap.zig @@ -366,7 +366,7 @@ pub const page_allocator: Allocator = if (@hasDecl(root, "os") and @hasDecl(root.os, "heap") and @hasDecl(root.os.heap, "page_allocator")) root.os.heap.page_allocator -else if (builtin.target.cpu.arch.isWasm()) .{ +else if (builtin.target.cpu.arch.isWasm() and !builtin.link_libc) .{ .ptr = undefined, .vtable = &WasmAllocator.vtable, } else if (builtin.target.os.tag == .plan9) .{ diff --git a/lib/std/os/emscripten.zig b/lib/std/os/emscripten.zig index cb444b360dd0..8dbf90dad9bc 100644 --- a/lib/std/os/emscripten.zig +++ b/lib/std/os/emscripten.zig @@ -331,15 +331,6 @@ pub const POLL = struct { pub const RDBAND = 0x080; }; -pub const PROT = struct { - pub const NONE = 0x0; - pub const READ = 0x1; - pub const WRITE = 0x2; - pub const EXEC = 0x4; - pub const GROWSDOWN = 0x01000000; - pub const GROWSUP = 0x02000000; -}; - pub const rlim_t = u64; pub const RLIM = struct {