Commit 44d8d654a0

Andrew Kelley <superjoe30@gmail.com>
2018-02-05 15:26:39
fix test failure, organize code, add new compile error
1 parent ec59f76
src/ir.cpp
@@ -6193,6 +6193,15 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
     if (other_type->id == TypeTableEntryIdFloat) {
         return true;
     } else if (other_type->id == TypeTableEntryIdInt && const_val_is_int) {
+        if (!other_type->data.integral.is_signed && const_val->data.x_bigint.is_negative) {
+            Buf *val_buf = buf_alloc();
+            bigint_append_buf(val_buf, &const_val->data.x_bigint, 10);
+            ir_add_error(ira, instruction,
+                buf_sprintf("cannot cast negative value %s to unsigned integer type '%s'",
+                    buf_ptr(val_buf),
+                    buf_ptr(&other_type->name)));
+            return false;
+        }
         if (bigint_fits_in_bits(&const_val->data.x_bigint, other_type->data.integral.bit_count,
                     other_type->data.integral.is_signed))
         {
@@ -6205,6 +6214,15 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
         if (const_val_fits_in_num_lit(const_val, child_type)) {
             return true;
         } else if (child_type->id == TypeTableEntryIdInt && const_val_is_int) {
+            if (!child_type->data.integral.is_signed && const_val->data.x_bigint.is_negative) {
+                Buf *val_buf = buf_alloc();
+                bigint_append_buf(val_buf, &const_val->data.x_bigint, 10);
+                ir_add_error(ira, instruction,
+                    buf_sprintf("cannot cast negative value %s to unsigned integer type '%s'",
+                        buf_ptr(val_buf),
+                        buf_ptr(&child_type->name)));
+                return false;
+            }
             if (bigint_fits_in_bits(&const_val->data.x_bigint,
                         child_type->data.integral.bit_count,
                         child_type->data.integral.is_signed))
std/c/linux.zig
@@ -1,4 +1,4 @@
-pub use @import("../os/linux_errno.zig");
+pub use @import("../os/linux/errno.zig");
 
 pub extern "c" fn getrandom(buf_ptr: &u8, buf_len: usize, flags: c_uint) c_int;
 extern "c" fn __errno_location() &c_int;
std/os/linux_errno.zig → std/os/linux/errno.zig
File renamed without changes
std/os/linux_i386.zig → std/os/linux/i386.zig
@@ -1,4 +1,5 @@
-const linux = @import("linux.zig");
+const std = @import("../../index.zig");
+const linux = std.os.linux;
 const socklen_t = linux.socklen_t;
 const iovec = linux.iovec;
 
std/os/linux.zig → std/os/linux/index.zig
@@ -1,13 +1,12 @@
-const std = @import("../index.zig");
+const std = @import("../../index.zig");
 const assert = std.debug.assert;
 const builtin = @import("builtin");
 const arch = switch (builtin.arch) {
-    builtin.Arch.x86_64 => @import("linux_x86_64.zig"),
-    builtin.Arch.i386 => @import("linux_i386.zig"),
+    builtin.Arch.x86_64 => @import("x86_64.zig"),
+    builtin.Arch.i386 => @import("i386.zig"),
     else => @compileError("unsupported arch"),
 };
-pub use @import("linux_errno.zig");
-pub use @import("linux_random.zig");
+pub use @import("errno.zig");
 
 pub const PATH_MAX = 4096;
 
@@ -788,10 +787,10 @@ pub fn timerfd_settime(fd: i32, flags: u32, new_value: &const itimerspec, old_va
     return arch.syscall4(arch.SYS_timerfd_settime, usize(fd), usize(flags), @ptrToInt(new_value), @ptrToInt(old_value));
 }
 
-test "import linux_test" {
+test "import linux test" {
     // TODO lazy analysis should prevent this test from being compiled on windows, but
     // it is still compiled on windows
     if (builtin.os == builtin.Os.linux) {
-        _ = @import("linux_test.zig");
+        _ = @import("test.zig");
     }
 }
std/os/linux_test.zig → std/os/linux/test.zig
@@ -1,4 +1,4 @@
-const std = @import("std");
+const std = @import("../../index.zig");
 const linux = std.os.linux;
 const assert = std.debug.assert;
 
std/os/linux_x86_64.zig → std/os/linux/x86_64.zig
@@ -1,4 +1,5 @@
-const linux = @import("linux.zig");
+const std = @import("../../index.zig");
+const linux = std.os.linux;
 const socklen_t = linux.socklen_t;
 const iovec = linux.iovec;
 
std/os/index.zig
@@ -6,7 +6,7 @@ const os = this;
 
 pub const windows = @import("windows/index.zig");
 pub const darwin = @import("darwin.zig");
-pub const linux = @import("linux.zig");
+pub const linux = @import("linux/index.zig");
 pub const zen = @import("zen.zig");
 pub const posix = switch(builtin.os) {
     Os.linux => linux,
@@ -78,13 +78,28 @@ error WouldBlock;
 pub fn getRandomBytes(buf: []u8) %void {
     switch (builtin.os) {
         Os.linux => while (true) {
-            const err = posix.getErrno(posix.getRandomBytes(buf));
-            if (err > 0) return unexpectedErrorPosix(err);
+            // TODO check libc version and potentially call c.getrandom.
+            // See #397
+            const err = posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0));
+            if (err > 0) {
+                switch (err) {
+                    posix.EINVAL => unreachable,
+                    posix.EFAULT => unreachable,
+                    posix.EINTR  => continue,
+                    posix.ENOSYS => {
+                        const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY|posix.O_CLOEXEC, 0);
+                        defer close(fd);
+
+                        try posixRead(fd, buf);
+                        return;
+                    },
+                    else => return unexpectedErrorPosix(err),
+                }
+            }
             return;
         },
         Os.macosx, Os.ios => {
-            const fd = try posixOpen("/dev/urandom", posix.O_RDONLY|posix.O_CLOEXEC,
-                0, null);
+            const fd = try posixOpenC(c"/dev/urandom", posix.O_RDONLY|posix.O_CLOEXEC, 0);
             defer close(fd);
 
             try posixRead(fd, buf);
@@ -253,8 +268,12 @@ pub fn posixOpen(file_path: []const u8, flags: u32, perm: usize, allocator: ?&Al
     mem.copy(u8, path0, file_path);
     path0[file_path.len] = 0;
 
+    return posixOpenC(path0.ptr, flags, perm);
+}
+
+pub fn posixOpenC(file_path: &const u8, flags: u32, perm: usize) %i32 {
     while (true) {
-        const result = posix.open(path0.ptr, flags, perm);
+        const result = posix.open(file_path, flags, perm);
         const err = posix.getErrno(result);
         if (err > 0) {
             return switch (err) {
@@ -1486,10 +1505,10 @@ test "std.os" {
     _ = @import("darwin_errno.zig");
     _ = @import("darwin.zig");
     _ = @import("get_user_id.zig");
-    _ = @import("linux_errno.zig");
+    _ = @import("linux/errno.zig");
     //_ = @import("linux_i386.zig");
-    _ = @import("linux_x86_64.zig");
-    _ = @import("linux.zig");
+    _ = @import("linux/x86_64.zig");
+    _ = @import("linux/index.zig");
     _ = @import("path.zig");
     _ = @import("windows/index.zig");
 }
std/os/linux_random.zig
@@ -1,246 +0,0 @@
-const std = @import("../index.zig");
-const builtin = @import("builtin");
-const assert = std.debug.assert;
-const linux = std.os.linux;
-const math = std.math;
-const mem = std.mem;
-const os = std.os;
-
-use @import("linux_errno.zig");
-
-const arch = switch (builtin.arch) {
-    builtin.Arch.x86_64 => @import("linux_x86_64.zig"),
-    builtin.Arch.i386 => @import("linux_i386.zig"),
-    else => @compileError("unsupported arch"),
-};
-
-const Method = enum {
-    Syscall,
-    Sysctl,
-    Urandom,
-};
-
-const Callback = fn(&i32, []u8) usize;
-
-const Context = struct {
-    syscall: Callback,
-    sysctl: Callback,
-    urandom: Callback,
-};
-
-pub fn getRandomBytes(buf: []u8) usize {
-    const ctx = Context {
-        .syscall = syscall,
-        .sysctl = sysctl,
-        .urandom = urandom,
-    };
-    return withContext(ctx, buf);
-}
-
-fn withContext(comptime ctx: Context, buf: []u8) usize {
-    if (buf.len == 0) return 0;
-
-    var fd: i32 = -1;
-    defer if (fd != -1) {
-        const _ = linux.close(fd);  // Ignore errors, can't do anything sensible.
-    };
-
-    // TODO(bnoordhuis) Remember the method across invocations so we don't make
-    // unnecessary system calls that are going to fail with ENOSYS anyway.
-    var method = Method.Syscall;
-    var i: usize = 0;
-    while (i < buf.len) {
-        const rc = switch (method) {
-            Method.Syscall => ctx.syscall(&fd, buf[i..]),
-            Method.Sysctl => ctx.sysctl(&fd, buf[i..]),
-            Method.Urandom => ctx.urandom(&fd, buf[i..]),
-        };
-        if (rc == 0) return usize(-EIO);  // Can't really happen.
-        if (!isErr(rc)) {
-            i += rc;
-            continue;
-        }
-        if (rc == usize(-EINTR)) continue;
-        if (rc == usize(-ENOSYS) and method == Method.Syscall) {
-            method = Method.Urandom;
-            continue;
-        }
-        if (method == Method.Urandom) {
-            method = Method.Sysctl;
-            continue;
-        }
-        return rc;  // Unexpected error.
-    }
-
-    return i;
-}
-
-fn syscall(_: &i32, buf: []u8) usize {
-    return arch.syscall3(arch.SYS_getrandom, @ptrToInt(&buf[0]), buf.len, 0);
-}
-
-// Note: reads only 14 bytes at a time.
-fn sysctl(_: &i32, buf: []u8) usize {
-    const __sysctl_args = extern struct {
-        name: &c_int,
-        nlen: c_int,
-        oldval: &u8,
-        oldlenp: &usize,
-        newval: ?&u8,
-        newlen: usize,
-        unused: [4]usize,
-    };
-
-    var name = [3]c_int { 1, 40, 6 };  // { CTL_KERN, KERN_RANDOM, RANDOM_UUID }
-    var uuid: [16]u8 = undefined;
-
-    const expected: usize = @sizeOf(@typeOf(uuid));
-    var len = expected;
-
-    var args = __sysctl_args {
-        .name = &name[0],
-        .nlen = c_int(name.len),
-        .oldval = &uuid[0],
-        .oldlenp = &len,
-        .newval = null,
-        .newlen = 0,
-        .unused = []usize {0} ** 4,
-    };
-
-    const rc = arch.syscall1(arch.SYS__sysctl, @ptrToInt(&args));
-    if (rc != 0) return rc;
-    if (len != expected) return 0;  // Can't happen.
-
-    // uuid[] is now a type 4 UUID; bytes 6 and 8 (counting from zero)
-    // contain 4 and 5 bits of entropy, respectively.  For ease of use,
-    // we skip those and only use 14 of the 16 bytes.
-    uuid[6] = uuid[14];
-    uuid[8] = uuid[15];
-
-    const n = math.min(buf.len, usize(14));
-    @memcpy(&buf[0], &uuid[0], n);
-    return n;
-}
-
-fn urandom(fd: &i32, buf: []u8) usize {
-    if (*fd == -1) {
-        const flags = linux.O_CLOEXEC|linux.O_RDONLY;
-        const rc = linux.open(c"/dev/urandom", flags, 0);
-        if (isErr(rc)) return rc;
-        *fd = i32(rc);
-    }
-    // read() doesn't like reads > INT_MAX.
-    const n = math.min(buf.len, usize(0x7FFFFFFF));
-    return linux.read(*fd, &buf[0], n);
-}
-
-fn isErr(rc: usize) bool {
-    return rc > usize(-4096);
-}
-
-test "os.linux.getRandomBytes" {
-    try check(42, getRandomBytesTrampoline);
-}
-
-test "os.linux.getRandomBytes syscall" {
-    try check(42, syscall);
-}
-
-test "os.linux.getRandomBytes sysctl" {
-    try check(14, sysctl);
-}
-
-test "os.linux.getRandomBytes /dev/urandom" {
-    try check(42, urandom);
-}
-
-test "os.linux.getRandomBytes state machine" {
-    const ctx = Context {
-        .syscall = fortytwo,
-        .urandom = fail,
-        .sysctl = fail,
-    };
-    var buf = []u8 {0};
-    assert(1 == withContext(ctx, buf[0..]));
-    assert(42 == buf[0]);
-}
-
-test "os.linux.getRandomBytes no-syscall state machine" {
-    const ctx = Context {
-        .syscall = enosys,
-        .urandom = fortytwo,
-        .sysctl = fail,
-    };
-    var buf = []u8 {0};
-    assert(1 == withContext(ctx, buf[0..]));
-    assert(42 == buf[0]);
-}
-
-test "os.linux.getRandomBytes no-urandom state machine" {
-    const ctx = Context {
-        .syscall = enosys,
-        .urandom = einval,
-        .sysctl = fortytwo,
-    };
-    var buf = []u8 {0};
-    assert(1 == withContext(ctx, buf[0..]));
-    assert(42 == buf[0]);
-}
-
-test "os.linux.getRandomBytes no-sysctl state machine" {
-    const ctx = Context {
-        .syscall = enosys,
-        .urandom = einval,
-        .sysctl = einval,
-    };
-    var buf = []u8 {0};
-    assert(usize(-EINVAL) == withContext(ctx, buf[0..]));
-    assert(0 == buf[0]);
-}
-
-fn einval(_: &i32, buf: []u8) usize {
-    return usize(-EINVAL);
-}
-
-fn enosys(_: &i32, buf: []u8) usize {
-    return usize(-ENOSYS);
-}
-
-fn fail(_: &i32, buf: []u8) usize {
-    os.abort();
-}
-
-fn fortytwo(_: &i32, buf: []u8) usize {
-    assert(buf.len == 1);
-    buf[0] = 42;
-    return 1;
-}
-
-fn check(comptime N: usize, cb: Callback) %void {
-    if (builtin.os == builtin.Os.linux) {
-        var fd: i32 = -1;
-        defer if (fd != -1) {
-            const _ = linux.close(fd);  // Ignore errors, can't do anything sensible.
-        };
-
-        var bufs = [3][N]u8 {
-            []u8 {0} ** N,
-            []u8 {0} ** N,
-            []u8 {0} ** N,
-        };
-
-        for (bufs) |*buf| {
-            const err = cb(&fd, (*buf)[0..]);
-            assert(err == N);
-        }
-
-        for (bufs) |*a|
-            for (bufs) |*b|
-                if (a != b)
-                    assert(!mem.eql(u8, *a, *b));
-    }
-}
-
-fn getRandomBytesTrampoline(_: &i32, buf: []u8) usize {
-    return getRandomBytes(buf);
-}
std/io.zig
@@ -2,7 +2,7 @@ const std = @import("index.zig");
 const builtin = @import("builtin");
 const Os = builtin.Os;
 const system = switch(builtin.os) {
-    Os.linux => @import("os/linux.zig"),
+    Os.linux => @import("os/linux/index.zig"),
     Os.macosx, Os.ios => @import("os/darwin.zig"),
     Os.windows => @import("os/windows/index.zig"),
     else => @compileError("Unsupported OS"),
test/compile_errors.zig
@@ -1,6 +1,12 @@
 const tests = @import("tests.zig");
 
 pub fn addCases(cases: &tests.CompileErrorContext) void {
+    cases.add("cast negative integer literal to usize",
+        \\export fn entry() void {
+        \\    const x = usize(-10);
+        \\}
+    , ".tmp_source.zig:2:21: error: cannot cast negative value -10 to unsigned integer type 'usize'");
+
     cases.add("use invalid number literal as array index",
         \\var v = 25;
         \\export fn entry() void {
CMakeLists.txt
@@ -439,11 +439,10 @@ set(ZIG_STD_FILES
     "os/darwin_errno.zig"
     "os/get_user_id.zig"
     "os/index.zig"
-    "os/linux.zig"
-    "os/linux_errno.zig"
-    "os/linux_random.zig"
-    "os/linux_i386.zig"
-    "os/linux_x86_64.zig"
+    "os/linux/index.zig"
+    "os/linux/errno.zig"
+    "os/linux/i386.zig"
+    "os/linux/x86_64.zig"
     "os/path.zig"
     "os/windows/error.zig"
     "os/windows/index.zig"