Commit 09a5f172f8

LemonBoy <thatlemon@gmail.com>
2020-03-23 19:50:29
std: Different thread stack allocation for NetBSD
* NetBSD is stricter than other OSs and doesn't allow mprotect to mark a non-accessible region as RW * Fix mprotect call over the whole stack, oops
1 parent cda73c3
Changed files (1)
lib
lib/std/thread.zig
@@ -292,32 +292,69 @@ pub const Thread = struct {
                     l += tls_img.alloc_size;
                 }
             }
-            break :blk l;
+            // Round the size to the page size.
+            break :blk mem.alignForward(l, mem.page_size);
         };
-        // Map the whole stack with no rw permissions to avoid committing the
-        // whole region right away
-        const mmap_slice = os.mmap(
-            null,
-            mem.alignForward(mmap_len, mem.page_size),
-            os.PROT_NONE,
-            os.MAP_PRIVATE | os.MAP_ANONYMOUS,
-            -1,
-            0,
-        ) catch |err| switch (err) {
-            error.MemoryMappingNotSupported => unreachable,
-            error.AccessDenied => unreachable,
-            error.PermissionDenied => unreachable,
-            else => |e| return e,
-        };
-        errdefer os.munmap(mmap_slice);
-
-        // Map everything but the guard page as rw
-        os.mprotect(
-            mmap_slice,
-            os.PROT_READ | os.PROT_WRITE,
-        ) catch |err| switch (err) {
-            error.AccessDenied => unreachable,
-            else => |e| return e,
+
+        const mmap_slice = mem: {
+            if (std.Target.current.os.tag != .netbsd) {
+                // Map the whole stack with no rw permissions to avoid
+                // committing the whole region right away
+                const mmap_slice = os.mmap(
+                    null,
+                    mmap_len,
+                    os.PROT_NONE,
+                    os.MAP_PRIVATE | os.MAP_ANONYMOUS,
+                    -1,
+                    0,
+                ) catch |err| switch (err) {
+                    error.MemoryMappingNotSupported => unreachable,
+                    error.AccessDenied => unreachable,
+                    error.PermissionDenied => unreachable,
+                    else => |e| return e,
+                };
+                errdefer os.munmap(mmap_slice);
+
+                // Map everything but the guard page as rw
+                os.mprotect(
+                    mmap_slice[guard_end_offset..],
+                    os.PROT_READ | os.PROT_WRITE,
+                ) catch |err| switch (err) {
+                    error.AccessDenied => unreachable,
+                    else => |e| return e,
+                };
+
+                break :mem mmap_slice;
+            } else {
+                // NetBSD mprotect is very strict and doesn't allow to "upgrade"
+                // a PROT_NONE mapping to a RW one so let's allocate everything
+                // right away
+                const mmap_slice = os.mmap(
+                    null,
+                    mmap_len,
+                    os.PROT_READ | os.PROT_WRITE,
+                    os.MAP_PRIVATE | os.MAP_ANONYMOUS,
+                    -1,
+                    0,
+                ) catch |err| switch (err) {
+                    error.MemoryMappingNotSupported => unreachable,
+                    error.AccessDenied => unreachable,
+                    error.PermissionDenied => unreachable,
+                    else => |e| return e,
+                };
+                errdefer os.munmap(mmap_slice);
+
+                // Remap the guard page with no permissions
+                os.mprotect(
+                    mmap_slice[0..guard_end_offset],
+                    os.PROT_NONE,
+                ) catch |err| switch (err) {
+                    error.AccessDenied => unreachable,
+                    else => |e| return e,
+                };
+
+                break :mem mmap_slice;
+            }
         };
 
         const mmap_addr = @ptrToInt(mmap_slice.ptr);