Add a guard page for each thread

This commit is contained in:
LemonBoy 2019-05-28 18:26:38 +02:00
parent 594366a482
commit 381f845287

View File

@ -223,15 +223,17 @@ pub const Thread = struct {
} }
}; };
const MAP_GROWSDOWN = if (os.linux.is_the_target) os.linux.MAP_GROWSDOWN else 0; var guard_end_offset: usize = undefined;
var stack_end_offset: usize = undefined; var stack_end_offset: usize = undefined;
var thread_start_offset: usize = undefined; var thread_start_offset: usize = undefined;
var context_start_offset: usize = undefined; var context_start_offset: usize = undefined;
var tls_start_offset: usize = undefined; var tls_start_offset: usize = undefined;
const mmap_len = blk: { const mmap_len = blk: {
// First in memory will be the stack, which grows downwards. var l: usize = mem.page_size;
var l: usize = mem.alignForward(default_stack_size, mem.page_size); // Allocate a guard page right after the end of the stack region
guard_end_offset = l;
// The stack itself, which grows downwards.
l = mem.alignForward(l + default_stack_size, mem.page_size);
stack_end_offset = l; stack_end_offset = l;
// Above the stack, so that it can be in the same mmap call, put the Thread object. // Above the stack, so that it can be in the same mmap call, put the Thread object.
l = mem.alignForward(l, @alignOf(Thread)); l = mem.alignForward(l, @alignOf(Thread));
@ -253,20 +255,33 @@ pub const Thread = struct {
} }
break :blk l; break :blk l;
}; };
// Map the whole stack with no rw permissions to avoid committing the
// whole region right away
const mmap_slice = os.mmap( const mmap_slice = os.mmap(
null, null,
mem.alignForward(mmap_len, mem.page_size), mem.alignForward(mmap_len, mem.page_size),
os.PROT_READ | os.PROT_WRITE, os.PROT_NONE,
os.MAP_PRIVATE | os.MAP_ANONYMOUS | MAP_GROWSDOWN, os.MAP_PRIVATE | os.MAP_ANONYMOUS,
-1, -1,
0, 0,
) catch |err| switch (err) { ) catch |err| switch (err) {
error.MemoryMappingNotSupported => unreachable, // no file descriptor error.MemoryMappingNotSupported => unreachable,
error.AccessDenied => unreachable, // no file descriptor error.AccessDenied => unreachable,
error.PermissionDenied => unreachable, // no file descriptor error.PermissionDenied => unreachable,
else => |e| return e, else => |e| return e,
}; };
errdefer os.munmap(mmap_slice); 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.OutOfMemory => unreachable,
error.AccessDenied => unreachable,
else => |e| return e,
};
const mmap_addr = @ptrToInt(mmap_slice.ptr); const mmap_addr = @ptrToInt(mmap_slice.ptr);
const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset)); const thread_ptr = @alignCast(@alignOf(Thread), @intToPtr(*Thread, mmap_addr + thread_start_offset));