authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-02-07 22:51:43-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-02-07 22:51:43-05:00
log0e7461d4a34272a94acba20b09aaee283e88a806
tree72b45e0feb56452e8d3fb25c8bf68a401b19b656
parenteff50abce68ffc69d236fcc0b919bc63fcd0e89a
parenta779450fefd623c54da37912995ffe7ad16b514e
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #4408 from LemonBoy/mmap-i386-fix

handle SIGBUS, fix mmap on i386 linux

3 files changed, 111 insertions(+), 4 deletions(-)

lib/std/debug.zig+3
...@@ -2256,6 +2256,7 @@ pub fn attachSegfaultHandler() void {...@@ -2256,6 +2256,7 @@ pub fn attachSegfaultHandler() void {
22562256
2257 os.sigaction(os.SIGSEGV, &act, null);2257 os.sigaction(os.SIGSEGV, &act, null);
2258 os.sigaction(os.SIGILL, &act, null);2258 os.sigaction(os.SIGILL, &act, null);
2259 os.sigaction(os.SIGBUS, &act, null);
2259}2260}
22602261
2261fn resetSegfaultHandler() void {2262fn resetSegfaultHandler() void {
...@@ -2273,6 +2274,7 @@ fn resetSegfaultHandler() void {...@@ -2273,6 +2274,7 @@ fn resetSegfaultHandler() void {
2273 };2274 };
2274 os.sigaction(os.SIGSEGV, &act, null);2275 os.sigaction(os.SIGSEGV, &act, null);
2275 os.sigaction(os.SIGILL, &act, null);2276 os.sigaction(os.SIGILL, &act, null);
2277 os.sigaction(os.SIGBUS, &act, null);
2276}2278}
22772279
2278fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_void) callconv(.C) noreturn {2280fn 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...@@ -2285,6 +2287,7 @@ fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *const c_vo
2285 switch (sig) {2287 switch (sig) {
2286 os.SIGSEGV => std.debug.warn("Segmentation fault at address 0x{x}\n", .{addr}),2288 os.SIGSEGV => std.debug.warn("Segmentation fault at address 0x{x}\n", .{addr}),
2287 os.SIGILL => std.debug.warn("Illegal instruction at address 0x{x}\n", .{addr}),2289 os.SIGILL => std.debug.warn("Illegal instruction at address 0x{x}\n", .{addr}),
2290 os.SIGBUS => std.debug.warn("Bus error at address 0x{x}\n", .{addr}),
2288 else => unreachable,2291 else => unreachable,
2289 }2292 }
2290 switch (builtin.arch) {2293 switch (builtin.arch) {
lib/std/os/linux/i386.zig+10-4
...@@ -72,11 +72,17 @@ pub fn syscall6(...@@ -72,11 +72,17 @@ pub fn syscall6(
72 arg5: usize,72 arg5: usize,
73 arg6: usize,73 arg6: usize,
74) usize {74) usize {
75 // The 6th argument is passed via memory as we're out of registers if ebp is
76 // used as frame pointer. We push arg6 value on the stack before changing
77 // ebp or esp as the compiler may reference it as an offset relative to one
78 // of those two registers.
75 return asm volatile (79 return asm volatile (
76 \\ push %%ebp80 \\ push %[arg6]
77 \\ mov %[arg6], %%ebp81 \\ push %%ebp
78 \\ int $0x8082 \\ mov 4(%%esp), %%ebp
79 \\ pop %%ebp83 \\ int $0x80
84 \\ pop %%ebp
85 \\ add $4, %%esp
80 : [ret] "={eax}" (-> usize)86 : [ret] "={eax}" (-> usize)
81 : [number] "{eax}" (number),87 : [number] "{eax}" (number),
82 [arg1] "{ebx}" (arg1),88 [arg1] "{ebx}" (arg1),
lib/std/os/test.zig+98
...@@ -256,3 +256,101 @@ test "memfd_create" {...@@ -256,3 +256,101 @@ test "memfd_create" {
256 expect(bytes_read == 4);256 expect(bytes_read == 4);
257 expect(mem.eql(u8, buf[0..4], "test"));257 expect(mem.eql(u8, buf[0..4], "test"));
258}258}
259
260test "mmap" {
261 if (builtin.os == .windows)
262 return error.SkipZigTest;
263
264 // Simple mmap() call with non page-aligned size
265 {
266 const data = try os.mmap(
267 null,
268 1234,
269 os.PROT_READ | os.PROT_WRITE,
270 os.MAP_ANONYMOUS | os.MAP_PRIVATE,
271 -1,
272 0,
273 );
274 defer os.munmap(data);
275
276 testing.expectEqual(@as(usize, 1234), data.len);
277
278 // By definition the data returned by mmap is zero-filled
279 std.mem.set(u8, data[0 .. data.len - 1], 0x55);
280 testing.expect(mem.indexOfScalar(u8, data, 0).? == 1234 - 1);
281 }
282
283 const test_out_file = "os_tmp_test";
284 // Must be a multiple of 4096 so that the test works with mmap2
285 const alloc_size = 8 * 4096;
286
287 // Create a file used for testing mmap() calls with a file descriptor
288 {
289 const file = try fs.cwd().createFile(test_out_file, .{});
290 defer file.close();
291
292 var out_stream = file.outStream();
293 const stream = &out_stream.stream;
294
295 var i: u32 = 0;
296 while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
297 try stream.writeIntNative(u32, i);
298 }
299 }
300
301 // Map the whole file
302 {
303 const file = try fs.cwd().createFile(test_out_file, .{
304 .read = true,
305 .truncate = false,
306 });
307 defer file.close();
308
309 const data = try os.mmap(
310 null,
311 alloc_size,
312 os.PROT_READ,
313 os.MAP_PRIVATE,
314 file.handle,
315 0,
316 );
317 defer os.munmap(data);
318
319 var mem_stream = io.SliceInStream.init(data);
320 const stream = &mem_stream.stream;
321
322 var i: u32 = 0;
323 while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
324 testing.expectEqual(i, try stream.readIntNative(u32));
325 }
326 }
327
328 // Map the upper half of the file
329 {
330 const file = try fs.cwd().createFile(test_out_file, .{
331 .read = true,
332 .truncate = false,
333 });
334 defer file.close();
335
336 const data = try os.mmap(
337 null,
338 alloc_size,
339 os.PROT_READ,
340 os.MAP_PRIVATE,
341 file.handle,
342 alloc_size / 2,
343 );
344 defer os.munmap(data);
345
346 var mem_stream = io.SliceInStream.init(data);
347 const stream = &mem_stream.stream;
348
349 var i: u32 = alloc_size / 2 / @sizeOf(u32);
350 while (i < alloc_size / @sizeOf(u32)) : (i += 1) {
351 testing.expectEqual(i, try stream.readIntNative(u32));
352 }
353 }
354
355 try fs.cwd().deleteFile(test_out_file);
356}