From be02616c869c5fe089bc9a80ea44817df2f5c2ba Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 7 Feb 2020 16:06:33 +0100 Subject: [PATCH 1/3] debug: Show a nice error message on SIGBUS --- lib/std/debug.zig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 100ac3e79..b9fafab07 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -2256,6 +2256,7 @@ pub fn attachSegfaultHandler() void { os.sigaction(os.SIGSEGV, &act, null); os.sigaction(os.SIGILL, &act, null); + os.sigaction(os.SIGBUS, &act, null); } fn resetSegfaultHandler() void { @@ -2273,6 +2274,7 @@ fn resetSegfaultHandler() void { }; os.sigaction(os.SIGSEGV, &act, null); os.sigaction(os.SIGILL, &act, null); + os.sigaction(os.SIGBUS, &act, null); } fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_void) callconv(.C) noreturn { @@ -2285,6 +2287,7 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_vo switch (sig) { os.SIGSEGV => std.debug.warn("Segmentation fault at address 0x{x}\n", .{addr}), os.SIGILL => std.debug.warn("Illegal instruction at address 0x{x}\n", .{addr}), + os.SIGBUS => std.debug.warn("Bus error at address 0x{x}\n", .{addr}), else => unreachable, } switch (builtin.arch) { From 7a58ec81ecfbf64baabdf883a458ca7296a34fc7 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 7 Feb 2020 16:07:12 +0100 Subject: [PATCH 2/3] std: Add a few tests for mmap/munmap --- lib/std/os/test.zig | 98 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index a872c03fd..f33b5d526 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -256,3 +256,101 @@ test "memfd_create" { expect(bytes_read == 4); expect(mem.eql(u8, buf[0..4], "test")); } + +test "mmap" { + if (builtin.os == .windows) + return error.SkipZigTest; + + // Simple mmap() call with non page-aligned size + { + const data = try os.mmap( + null, + 1234, + os.PROT_READ | os.PROT_WRITE, + os.MAP_ANONYMOUS | os.MAP_PRIVATE, + -1, + 0, + ); + defer os.munmap(data); + + testing.expectEqual(@as(usize, 1234), data.len); + + // By definition the data returned by mmap is zero-filled + std.mem.set(u8, data[0 .. data.len - 1], 0x55); + testing.expect(mem.indexOfScalar(u8, data, 0).? == 1234 - 1); + } + + const test_out_file = "os_tmp_test"; + // Must be a multiple of 4096 so that the test works with mmap2 + const alloc_size = 8 * 4096; + + // Create a file used for testing mmap() calls with a file descriptor + { + const file = try fs.cwd().createFile(test_out_file, .{}); + defer file.close(); + + var out_stream = file.outStream(); + const stream = &out_stream.stream; + + var i: u32 = 0; + while (i < alloc_size / @sizeOf(u32)) : (i += 1) { + try stream.writeIntNative(u32, i); + } + } + + // Map the whole file + { + const file = try fs.cwd().createFile(test_out_file, .{ + .read = true, + .truncate = false, + }); + defer file.close(); + + const data = try os.mmap( + null, + alloc_size, + os.PROT_READ, + os.MAP_PRIVATE, + file.handle, + 0, + ); + defer os.munmap(data); + + var mem_stream = io.SliceInStream.init(data); + const stream = &mem_stream.stream; + + var i: u32 = 0; + while (i < alloc_size / @sizeOf(u32)) : (i += 1) { + testing.expectEqual(i, try stream.readIntNative(u32)); + } + } + + // Map the upper half of the file + { + const file = try fs.cwd().createFile(test_out_file, .{ + .read = true, + .truncate = false, + }); + defer file.close(); + + const data = try os.mmap( + null, + alloc_size, + os.PROT_READ, + os.MAP_PRIVATE, + file.handle, + alloc_size / 2, + ); + defer os.munmap(data); + + var mem_stream = io.SliceInStream.init(data); + const stream = &mem_stream.stream; + + var i: u32 = alloc_size / 2 / @sizeOf(u32); + while (i < alloc_size / @sizeOf(u32)) : (i += 1) { + testing.expectEqual(i, try stream.readIntNative(u32)); + } + } + + try fs.cwd().deleteFile(test_out_file); +} From a779450fefd623c54da37912995ffe7ad16b514e Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 7 Feb 2020 16:07:51 +0100 Subject: [PATCH 3/3] linux/i386: Make syscall6 more robust and correct LLVM10 exposed a subtle flaw in the previous implementation that made the mmap tests fail. --- lib/std/os/linux/i386.zig | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/std/os/linux/i386.zig b/lib/std/os/linux/i386.zig index 7652ece43..ecdf361b6 100644 --- a/lib/std/os/linux/i386.zig +++ b/lib/std/os/linux/i386.zig @@ -72,11 +72,17 @@ pub fn syscall6( arg5: usize, arg6: usize, ) usize { + // The 6th argument is passed via memory as we're out of registers if ebp is + // used as frame pointer. We push arg6 value on the stack before changing + // ebp or esp as the compiler may reference it as an offset relative to one + // of those two registers. return asm volatile ( - \\ push %%ebp - \\ mov %[arg6], %%ebp - \\ int $0x80 - \\ pop %%ebp + \\ push %[arg6] + \\ push %%ebp + \\ mov 4(%%esp), %%ebp + \\ int $0x80 + \\ pop %%ebp + \\ add $4, %%esp : [ret] "={eax}" (-> usize) : [number] "{eax}" (number), [arg1] "{ebx}" (arg1),