From b612512bb500defd399a11dfa47c83cefe4d87b5 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 3 May 2019 13:11:53 +0200 Subject: [PATCH 1/3] std: Remove some assumptions about the host platform The stdlib is now 32-bit friendly. --- std/crypto/chacha20.zig | 5 +++-- std/heap.zig | 2 +- std/os/linux.zig | 4 ++-- std/os/time.zig | 4 ++-- std/rand.zig | 4 ++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/std/crypto/chacha20.zig b/std/crypto/chacha20.zig index 78ef700bdfe029af9590f78c05e61d80c81acd8b..796b5c6e4f7cc644af90cbecbc9bd573f29b79ac 100644 --- a/std/crypto/chacha20.zig +++ b/std/crypto/chacha20.zig @@ -142,7 +142,7 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32] assert(in.len >= out.len); assert(counter +% (in.len >> 6) >= counter); - var cursor: u64 = 0; + var cursor: usize = 0; var k: [8]u32 = undefined; var c: [4]u32 = undefined; @@ -161,7 +161,8 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32] c[3] = mem.readIntSliceLittle(u32, nonce[4..8]); const block_size = (1 << 6); - const big_block = (block_size << 32); + // The full block size is greater than the address space on a 32bit machine + const big_block = if (@sizeOf(usize) > 4) (block_size << 32) else maxInt(usize); // first partial big block if (((@intCast(u64, maxInt(u32) - @truncate(u32, counter)) + 1) << 6) < in.len) { diff --git a/std/heap.zig b/std/heap.zig index 65d346262b11858852e87256d8bfee9ff8b42826..c365fa0306492fd192d49a9adc2859f4d6869d89 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -601,7 +601,7 @@ test "ArenaAllocator" { try testAllocatorAlignedShrink(&arena_allocator.allocator); } -var test_fixed_buffer_allocator_memory: [40000 * @sizeOf(usize)]u8 = undefined; +var test_fixed_buffer_allocator_memory: [40000 * @sizeOf(u64)]u8 = undefined; test "FixedBufferAllocator" { var fixed_buffer_allocator = FixedBufferAllocator.init(test_fixed_buffer_allocator_memory[0..]); diff --git a/std/os/linux.zig b/std/os/linux.zig index e7f822185bc495302a67eae30bf48048c1a81fdc..abfed410cca2dbc130f40224671a561de14050fd 100644 --- a/std/os/linux.zig +++ b/std/os/linux.zig @@ -1100,8 +1100,8 @@ pub fn sigaction(sig: u6, noalias act: *const Sigaction, noalias oact: ?*Sigacti const NSIG = 65; const sigset_t = [128 / @sizeOf(usize)]usize; -const all_mask = []usize{maxInt(usize)}; -const app_mask = []usize{0xfffffffc7fffffff}; +const all_mask = []u32{0xffffffff, 0xffffffff}; +const app_mask = []u32{0xfffffffc, 0x7fffffff}; const k_sigaction = extern struct { handler: extern fn (i32) void, diff --git a/std/os/time.zig b/std/os/time.zig index d742c5d03b3efb4a0e22f04ca9162c243d332fc4..fb39fda1def092deda2465920a3a9a649f70cc01 100644 --- a/std/os/time.zig +++ b/std/os/time.zig @@ -31,8 +31,8 @@ pub fn sleep(nanoseconds: u64) void { pub fn posixSleep(seconds: u63, nanoseconds: u63) void { var req = posix.timespec{ - .tv_sec = seconds, - .tv_nsec = nanoseconds, + .tv_sec = @intCast(isize, seconds), + .tv_nsec = @intCast(isize, nanoseconds), }; var rem: posix.timespec = undefined; while (true) { diff --git a/std/rand.zig b/std/rand.zig index a2fdfed6fd5787127d3c1dbb57d77d5bd5acc1e2..4a6563f65a86dde234bd5ee1a50ef9a83c86b320 100644 --- a/std/rand.zig +++ b/std/rand.zig @@ -768,10 +768,10 @@ pub const Isaac64 = struct { const x = self.m[base + m1]; self.a = mix +% self.m[base + m2]; - const y = self.a +% self.b +% self.m[(x >> 3) % self.m.len]; + const y = self.a +% self.b +% self.m[@intCast(usize, (x >> 3) % self.m.len)]; self.m[base + m1] = y; - self.b = x +% self.m[(y >> 11) % self.m.len]; + self.b = x +% self.m[@intCast(usize, (y >> 11) % self.m.len)]; self.r[self.r.len - 1 - base - m1] = self.b; } -- 2.54.0 From 98bc2b73bf6974a782e2df0ea71b409a68e030fd Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 4 May 2019 09:03:01 +0200 Subject: [PATCH 2/3] Implement failsafe logic for posixSleep Now we'll sleep for the specified amount of time even though the number of seconds doesn't fit in a `isize` field. --- std/os/time.zig | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/std/os/time.zig b/std/os/time.zig index fb39fda1def092deda2465920a3a9a649f70cc01..99c8b599271a7a36ac444ec5991b1a989496fcfc 100644 --- a/std/os/time.zig +++ b/std/os/time.zig @@ -3,6 +3,7 @@ const builtin = @import("builtin"); const Os = builtin.Os; const debug = std.debug; const testing = std.testing; +const math = std.math; const windows = std.os.windows; const linux = std.os.linux; @@ -30,16 +31,26 @@ pub fn sleep(nanoseconds: u64) void { } pub fn posixSleep(seconds: u63, nanoseconds: u63) void { - var req = posix.timespec{ - .tv_sec = @intCast(isize, seconds), - .tv_nsec = @intCast(isize, nanoseconds), - }; + var req: posix.timespec = undefined; var rem: posix.timespec = undefined; + + var req_sec = seconds; + var req_nsec = nanoseconds; + while (true) { + req.tv_sec = math.min(math.maxInt(isize), req_sec); + req.tv_nsec = @intCast(isize, req_nsec); + + req_sec -= @intCast(u63, req.tv_sec); + req_nsec = 0; + const ret_val = posix.nanosleep(&req, &rem); const err = posix.getErrno(ret_val); - if (err == 0) return; switch (err) { + 0 => { + // If there's still time to wait keep running the loop + if (req_sec == 0 and req_nsec == 0) return; + }, posix.EFAULT => unreachable, posix.EINVAL => { // Sometimes Darwin returns EINVAL for no reason. @@ -47,7 +58,8 @@ pub fn posixSleep(seconds: u63, nanoseconds: u63) void { return; }, posix.EINTR => { - req = rem; + req_sec += @intCast(u63, rem.tv_sec); + req_nsec = @intCast(u63, rem.tv_nsec); continue; }, else => return, -- 2.54.0 From 09cbcf8841a0b80cdbdf40c2b48acccbaa945ce8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 4 May 2019 15:16:39 -0400 Subject: [PATCH 3/3] std lib sleep APIs: add doc comments and no @intCast The sleep APIs are now documented as having spurious wakeups and no precision of timing guaranteed. They also cannot fail. This commit makes the entire range of u64 legal values to pass to std.os.time.sleep and std.os.time.posixSleep. Values that do not fit in the native system APIs will cause a sleep for the longest possible duration and then be handled as a spurious wakeup. --- std/os/time.zig | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/std/os/time.zig b/std/os/time.zig index 99c8b599271a7a36ac444ec5991b1a989496fcfc..abb64128431084949f6d8e11f93d2ce4026e5506 100644 --- a/std/os/time.zig +++ b/std/os/time.zig @@ -13,44 +13,35 @@ const posix = std.os.posix; pub const epoch = @import("epoch.zig"); -/// Sleep for the specified duration +/// Spurious wakeups are possible and no precision of timing is guaranteed. pub fn sleep(nanoseconds: u64) void { switch (builtin.os) { Os.linux, Os.macosx, Os.ios, Os.freebsd, Os.netbsd => { const s = nanoseconds / ns_per_s; const ns = nanoseconds % ns_per_s; - posixSleep(@intCast(u63, s), @intCast(u63, ns)); + posixSleep(s, ns); }, Os.windows => { const ns_per_ms = ns_per_s / ms_per_s; const milliseconds = nanoseconds / ns_per_ms; - windows.Sleep(@intCast(windows.DWORD, milliseconds)); + const ms_that_will_fit = std.math.cast(windows.DWORD, milliseconds) catch std.math.maxInt(windows.DWORD); + windows.Sleep(ms_that_will_fit); }, else => @compileError("Unsupported OS"), } } -pub fn posixSleep(seconds: u63, nanoseconds: u63) void { - var req: posix.timespec = undefined; +/// Spurious wakeups are possible and no precision of timing is guaranteed. +pub fn posixSleep(seconds: u64, nanoseconds: u64) void { + var req = posix.timespec{ + .tv_sec = std.math.cast(isize, seconds) catch std.math.maxInt(isize), + .tv_nsec = std.math.cast(isize, nanoseconds) catch std.math.maxInt(isize), + }; var rem: posix.timespec = undefined; - - var req_sec = seconds; - var req_nsec = nanoseconds; - while (true) { - req.tv_sec = math.min(math.maxInt(isize), req_sec); - req.tv_nsec = @intCast(isize, req_nsec); - - req_sec -= @intCast(u63, req.tv_sec); - req_nsec = 0; - const ret_val = posix.nanosleep(&req, &rem); const err = posix.getErrno(ret_val); switch (err) { - 0 => { - // If there's still time to wait keep running the loop - if (req_sec == 0 and req_nsec == 0) return; - }, posix.EFAULT => unreachable, posix.EINVAL => { // Sometimes Darwin returns EINVAL for no reason. @@ -58,10 +49,10 @@ pub fn posixSleep(seconds: u63, nanoseconds: u63) void { return; }, posix.EINTR => { - req_sec += @intCast(u63, rem.tv_sec); - req_nsec = @intCast(u63, rem.tv_nsec); + req = rem; continue; }, + // This prong handles success as well as unexpected errors. else => return, } } -- 2.54.0