From 29e438fd1f77a13c3a3f128434198ac024d3e195 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 25 Nov 2019 00:30:28 -0500 Subject: [PATCH] more sentinel-terminated pointers std lib integration See #3767 --- doc/langref.html.in | 2 +- lib/std/c.zig | 2 +- lib/std/debug.zig | 16 ++++----- lib/std/dynamic_library.zig | 8 ++--- lib/std/event/fs.zig | 6 ++-- lib/std/fs.zig | 44 ++++++++++++----------- lib/std/fs/file.zig | 14 ++++---- lib/std/os.zig | 70 ++++++++++++++++++++----------------- lib/std/os/bits/darwin.zig | 2 +- lib/std/os/bits/linux.zig | 2 +- lib/std/os/wasi.zig | 4 +-- lib/std/os/windows.zig | 16 ++++----- lib/std/process.zig | 4 +-- src/analyze.cpp | 2 +- 14 files changed, 98 insertions(+), 94 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index be6f09a93e94bca8a5bfbbb17a10cd62f41509a8..324906c36fe85c4eadb8b790492a8ddb3c548836 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -4865,7 +4865,7 @@ const mem = std.mem; test "cast *[1][*]const u8 to [*]const ?[*]const u8" { const window_name = [1][*]const u8{"window name"}; const x: [*]const ?[*]const u8 = &window_name; - assert(mem.eql(u8, std.mem.toSliceConst(u8, x[0].?), "window name")); + assert(mem.eql(u8, std.mem.toSliceConst(u8, @ptrCast([*:0]const u8, x[0].?)), "window name")); } {#code_end#} {#header_close#} diff --git a/lib/std/c.zig b/lib/std/c.zig index 33061b6620dd1af60f36fb033c5a094b473f9b97..19c3c8feb84e6c177d88cae6b4e4bea11bd3fe0a 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -102,7 +102,7 @@ pub extern "c" fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [ pub extern "c" fn dup(fd: fd_t) c_int; pub extern "c" fn dup2(old_fd: fd_t, new_fd: fd_t) c_int; pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize; -pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8; +pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*:0]u8; pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int; pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int; diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 7698443ce879548f290eec7195704cb2d0e263eb..dd4edf832bc98045bfacbe42cf55f110f347f337 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -401,7 +401,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset; const vaddr_end = vaddr_start + proc_sym.CodeSize; if (relative_address >= vaddr_start and relative_address < vaddr_end) { - break mem.toSliceConst(u8, @ptrCast([*]u8, proc_sym) + @sizeOf(pdb.ProcSym)); + break mem.toSliceConst(u8, @ptrCast([*:0]u8, proc_sym) + @sizeOf(pdb.ProcSym)); } }, else => {}, @@ -703,9 +703,9 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt return; }; - const symbol_name = mem.toSliceConst(u8, di.strings.ptr + symbol.nlist.n_strx); + const symbol_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + symbol.nlist.n_strx)); const compile_unit_name = if (symbol.ofile) |ofile| blk: { - const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx); + const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx)); break :blk fs.path.basename(ofile_path); } else "???"; if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| { @@ -915,7 +915,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { for (present) |_| { const name_offset = try pdb_stream.stream.readIntLittle(u32); const name_index = try pdb_stream.stream.readIntLittle(u32); - const name = mem.toSlice(u8, name_bytes.ptr + name_offset); + const name = mem.toSlice(u8, @ptrCast([*:0]u8, name_bytes.ptr + name_offset)); if (mem.eql(u8, name, "/names")) { break :str_tab_index name_index; } @@ -1708,7 +1708,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u const gop = try di.ofiles.getOrPut(ofile); const mach_o_file = if (gop.found_existing) &gop.kv.value else blk: { errdefer _ = di.ofiles.remove(ofile); - const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx); + const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx)); gop.kv.value = MachOFile{ .bytes = try std.fs.Dir.cwd().readFileAllocAligned( @@ -1741,7 +1741,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u if (sect.flags & macho.SECTION_TYPE == macho.S_REGULAR and (sect.flags & macho.SECTION_ATTRIBUTES) & macho.S_ATTR_DEBUG == macho.S_ATTR_DEBUG) { - const sect_name = mem.toSliceConst(u8, §.sectname); + const sect_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, §.sectname)); if (mem.eql(u8, sect_name, "__debug_line")) { gop.kv.value.sect_debug_line = sect; } else if (mem.eql(u8, sect_name, "__debug_info")) { @@ -2323,8 +2323,8 @@ fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 { } } -fn readStringMem(ptr: *[*]const u8) []const u8 { - const result = mem.toSliceConst(u8, ptr.*); +fn readStringMem(ptr: *[*]const u8) [:0]const u8 { + const result = mem.toSliceConst(u8, @ptrCast([*:0]const u8, ptr.*)); ptr.* += result.len + 1; return result; } diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig index 0e8792ca9099bff4bf0c2673b7e3d6f34cb1dce4..a4da9a8b03a38725a493b759c45d7fcef45e57b1 100644 --- a/lib/std/dynamic_library.zig +++ b/lib/std/dynamic_library.zig @@ -140,7 +140,7 @@ pub const LinuxDynLib = struct { }; pub const ElfLib = struct { - strings: [*]u8, + strings: [*:0]u8, syms: [*]elf.Sym, hashtab: [*]os.Elf_Symndx, versym: ?[*]u16, @@ -175,7 +175,7 @@ pub const ElfLib = struct { const dynv = maybe_dynv orelse return error.MissingDynamicLinkingInformation; if (base == maxInt(usize)) return error.BaseNotFound; - var maybe_strings: ?[*]u8 = null; + var maybe_strings: ?[*:0]u8 = null; var maybe_syms: ?[*]elf.Sym = null; var maybe_hashtab: ?[*]os.Elf_Symndx = null; var maybe_versym: ?[*]u16 = null; @@ -186,7 +186,7 @@ pub const ElfLib = struct { while (dynv[i] != 0) : (i += 2) { const p = base + dynv[i + 1]; switch (dynv[i]) { - elf.DT_STRTAB => maybe_strings = @intToPtr([*]u8, p), + elf.DT_STRTAB => maybe_strings = @intToPtr([*:0]u8, p), elf.DT_SYMTAB => maybe_syms = @intToPtr([*]elf.Sym, p), elf.DT_HASH => maybe_hashtab = @intToPtr([*]os.Elf_Symndx, p), elf.DT_VERSYM => maybe_versym = @intToPtr([*]u16, p), @@ -230,7 +230,7 @@ pub const ElfLib = struct { } }; -fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [*]u8) bool { +fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [*:0]u8) bool { var def = def_arg; const vsym = @bitCast(u32, vsym_arg) & 0x7fff; while (true) { diff --git a/lib/std/event/fs.zig b/lib/std/event/fs.zig index eef5cfae7d0b0a2191f1aeeacf187bea82d58f76..965302e1e6a9818c75aa65212859f2b68987dd49 100644 --- a/lib/std/event/fs.zig +++ b/lib/std/event/fs.zig @@ -58,8 +58,7 @@ pub const Request = struct { }; pub const Open = struct { - /// must be null terminated. TODO https://github.com/ziglang/zig/issues/265 - path: []const u8, + path: [:0]const u8, flags: u32, mode: File.Mode, result: Error!fd_t, @@ -68,8 +67,7 @@ pub const Request = struct { }; pub const WriteFile = struct { - /// must be null terminated. TODO https://github.com/ziglang/zig/issues/265 - path: []const u8, + path: [:0]const u8, contents: []const u8, mode: File.Mode, result: Error!void, diff --git a/lib/std/fs.zig b/lib/std/fs.zig index d5a7930970d5a0f19f742261c056bcc712975486..9fd204ae23b28e43040e66a8fd77927f4de25627 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -28,6 +28,7 @@ pub const GetAppDataDirError = @import("fs/get_app_data_dir.zig").GetAppDataDirE /// This represents the maximum size of a UTF-8 encoded file path. /// All file system operations which return a path are guaranteed to /// fit into a UTF-8 encoded array of this length. +/// The byte count includes room for a null sentinel byte. pub const MAX_PATH_BYTES = switch (builtin.os) { .linux, .macosx, .ios, .freebsd, .netbsd, .dragonfly => os.PATH_MAX, // Each UTF-16LE character may be expanded to 3 UTF-8 bytes. @@ -227,7 +228,7 @@ pub const AtomicFile = struct { try crypto.randomBytes(rand_buf[0..]); b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], rand_buf); - const file = File.openWriteNoClobberC(&tmp_path_buf, mode) catch |err| switch (err) { + const file = File.openWriteNoClobberC(@ptrCast([*:0]u8, &tmp_path_buf), mode) catch |err| switch (err) { error.PathAlreadyExists => continue, // TODO zig should figure out that this error set does not include PathAlreadyExists since // it is handled in the above switch @@ -247,7 +248,7 @@ pub const AtomicFile = struct { pub fn deinit(self: *AtomicFile) void { if (!self.finished) { self.file.close(); - deleteFileC(&self.tmp_path_buf) catch {}; + deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {}; self.finished = true; } } @@ -258,11 +259,11 @@ pub const AtomicFile = struct { self.finished = true; if (builtin.os == .windows) { const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path); - const tmp_path_w = try os.windows.cStrToPrefixedFileW(&self.tmp_path_buf); + const tmp_path_w = try os.windows.cStrToPrefixedFileW(@ptrCast([*:0]u8, &self.tmp_path_buf)); return os.renameW(&tmp_path_w, &dest_path_w); } const dest_path_c = try os.toPosixPath(self.dest_path); - return os.renameC(&self.tmp_path_buf, &dest_path_c); + return os.renameC(@ptrCast([*:0]u8, &self.tmp_path_buf), &dest_path_c); } }; @@ -274,12 +275,12 @@ pub fn makeDir(dir_path: []const u8) !void { } /// Same as `makeDir` except the parameter is a null-terminated UTF8-encoded string. -pub fn makeDirC(dir_path: [*]const u8) !void { +pub fn makeDirC(dir_path: [*:0]const u8) !void { return os.mkdirC(dir_path, default_new_dir_mode); } /// Same as `makeDir` except the parameter is a null-terminated UTF16LE-encoded string. -pub fn makeDirW(dir_path: [*]const u16) !void { +pub fn makeDirW(dir_path: [*:0]const u16) !void { return os.mkdirW(dir_path, default_new_dir_mode); } @@ -327,12 +328,12 @@ pub fn deleteDir(dir_path: []const u8) !void { } /// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string. -pub fn deleteDirC(dir_path: [*]const u8) !void { +pub fn deleteDirC(dir_path: [*:0]const u8) !void { return os.rmdirC(dir_path); } /// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string. -pub fn deleteDirW(dir_path: [*]const u16) !void { +pub fn deleteDirW(dir_path: [*:0]const u16) !void { return os.rmdirW(dir_path); } @@ -688,7 +689,7 @@ pub const Dir = struct { } /// Same as `open` except the parameter is null-terminated. - pub fn openC(dir_path_c: [*]const u8) OpenError!Dir { + pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir { return cwd().openDirC(dir_path_c); } @@ -708,7 +709,7 @@ pub const Dir = struct { } /// Call `File.close` on the result when done. - pub fn openReadC(self: Dir, sub_path: [*]const u8) File.OpenError!File { + pub fn openReadC(self: Dir, sub_path: [*:0]const u8) File.OpenError!File { if (builtin.os == .windows) { const path_w = try os.windows.cStrToPrefixedFileW(sub_path); return self.openReadW(&path_w); @@ -719,7 +720,7 @@ pub const Dir = struct { return File.openHandle(fd); } - pub fn openReadW(self: Dir, sub_path_w: [*]const u16) File.OpenError!File { + pub fn openReadW(self: Dir, sub_path_w: [*:0]const u16) File.OpenError!File { const w = os.windows; var result = File{ .handle = undefined }; @@ -786,7 +787,7 @@ pub const Dir = struct { } /// Same as `openDir` except the parameter is null-terminated. - pub fn openDirC(self: Dir, sub_path_c: [*]const u8) OpenError!Dir { + pub fn openDirC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { if (builtin.os == .windows) { const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); return self.openDirW(&sub_path_w); @@ -805,7 +806,7 @@ pub const Dir = struct { /// Same as `openDir` except the path parameter is UTF16LE, NT-prefixed. /// This function is Windows-only. - pub fn openDirW(self: Dir, sub_path_w: [*]const u16) OpenError!Dir { + pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16) OpenError!Dir { const w = os.windows; var result = Dir{ @@ -868,7 +869,7 @@ pub const Dir = struct { } /// Same as `deleteFile` except the parameter is null-terminated. - pub fn deleteFileC(self: Dir, sub_path_c: [*]const u8) DeleteFileError!void { + pub fn deleteFileC(self: Dir, sub_path_c: [*:0]const u8) DeleteFileError!void { os.unlinkatC(self.fd, sub_path_c, 0) catch |err| switch (err) { error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR else => |e| return e, @@ -903,7 +904,7 @@ pub const Dir = struct { } /// Same as `deleteDir` except the parameter is null-terminated. - pub fn deleteDirC(self: Dir, sub_path_c: [*]const u8) DeleteDirError!void { + pub fn deleteDirC(self: Dir, sub_path_c: [*:0]const u8) DeleteDirError!void { os.unlinkatC(self.fd, sub_path_c, os.AT_REMOVEDIR) catch |err| switch (err) { error.IsDir => unreachable, // not possible since we pass AT_REMOVEDIR else => |e| return e, @@ -912,7 +913,7 @@ pub const Dir = struct { /// Same as `deleteDir` except the parameter is UTF16LE, NT prefixed. /// This function is Windows-only. - pub fn deleteDirW(self: Dir, sub_path_w: [*]const u16) DeleteDirError!void { + pub fn deleteDirW(self: Dir, sub_path_w: [*:0]const u16) DeleteDirError!void { os.unlinkatW(self.fd, sub_path_w, os.AT_REMOVEDIR) catch |err| switch (err) { error.IsDir => unreachable, // not possible since we pass AT_REMOVEDIR else => |e| return e, @@ -927,7 +928,7 @@ pub const Dir = struct { } /// Same as `readLink`, except the `pathname` parameter is null-terminated. - pub fn readLinkC(self: Dir, sub_path_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { + pub fn readLinkC(self: Dir, sub_path_c: [*:0]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { return os.readlinkatC(self.fd, sub_path_c, buffer); } @@ -1250,7 +1251,8 @@ pub fn openSelfExe() OpenSelfExeError!File { var buf: [MAX_PATH_BYTES]u8 = undefined; const self_exe_path = try selfExePath(&buf); buf[self_exe_path.len] = 0; - return File.openReadC(self_exe_path.ptr); + // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 + return File.openReadC(@ptrCast([*:0]u8, self_exe_path.ptr)); } test "openSelfExe" { @@ -1277,7 +1279,7 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 { var u32_len: u32 = out_buffer.len; const rc = std.c._NSGetExecutablePath(out_buffer, &u32_len); if (rc != 0) return error.NameTooLong; - return mem.toSlice(u8, out_buffer); + return mem.toSlice(u8, @ptrCast([*:0]u8, out_buffer)); } switch (builtin.os) { .linux => return os.readlinkC("/proc/self/exe", out_buffer), @@ -1306,9 +1308,9 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 { } /// The result is UTF16LE-encoded. -pub fn selfExePathW() []const u16 { +pub fn selfExePathW() [:0]const u16 { const image_path_name = &os.windows.peb().ProcessParameters.ImagePathName; - return mem.toSliceConst(u16, image_path_name.Buffer); + return mem.toSliceConst(u16, @ptrCast([*:0]const u16, image_path_name.Buffer)); } /// `selfExeDirPath` except allocates the result on the heap. diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig index cd50fcdece9e50a0034c670fb95c41e76aaaf877..9cfdad3885ded3aafee4115dcf7481b0fdd7ed4e 100644 --- a/lib/std/fs/file.zig +++ b/lib/std/fs/file.zig @@ -31,7 +31,7 @@ pub const File = struct { } /// Deprecated; call `std.fs.Dir.openReadC` directly. - pub fn openReadC(path_c: [*]const u8) OpenError!File { + pub fn openReadC(path_c: [*:0]const u8) OpenError!File { return std.fs.Dir.cwd().openReadC(path_c); } @@ -61,7 +61,7 @@ pub const File = struct { /// Same as `openWriteMode` except `path` is null-terminated. /// TODO: deprecate this and move it to `std.fs.Dir`. - pub fn openWriteModeC(path: [*]const u8, file_mode: Mode) OpenError!File { + pub fn openWriteModeC(path: [*:0]const u8, file_mode: Mode) OpenError!File { if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); return openWriteModeW(&path_w, file_mode); @@ -74,7 +74,7 @@ pub const File = struct { /// Same as `openWriteMode` except `path` is null-terminated and UTF16LE encoded /// TODO: deprecate this and move it to `std.fs.Dir`. - pub fn openWriteModeW(path_w: [*]const u16, file_mode: Mode) OpenError!File { + pub fn openWriteModeW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File { const handle = try windows.CreateFileW( path_w, windows.GENERIC_WRITE, @@ -101,7 +101,7 @@ pub const File = struct { } /// TODO: deprecate this and move it to `std.fs.Dir`. - pub fn openWriteNoClobberC(path: [*]const u8, file_mode: Mode) OpenError!File { + pub fn openWriteNoClobberC(path: [*:0]const u8, file_mode: Mode) OpenError!File { if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); return openWriteNoClobberW(&path_w, file_mode); @@ -113,7 +113,7 @@ pub const File = struct { } /// TODO: deprecate this and move it to `std.fs.Dir`. - pub fn openWriteNoClobberW(path_w: [*]const u16, file_mode: Mode) OpenError!File { + pub fn openWriteNoClobberW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File { const handle = try windows.CreateFileW( path_w, windows.GENERIC_WRITE, @@ -142,13 +142,13 @@ pub const File = struct { /// Same as `access` except the parameter is null-terminated. /// TODO: deprecate this and move it to `std.fs.Dir`. - pub fn accessC(path: [*]const u8) !void { + pub fn accessC(path: [*:0]const u8) !void { return os.accessC(path, os.F_OK); } /// Same as `access` except the parameter is null-terminated UTF16LE-encoded. /// TODO: deprecate this and move it to `std.fs.Dir`. - pub fn accessW(path: [*]const u16) !void { + pub fn accessW(path: [*:0]const u16) !void { return os.accessW(path, os.F_OK); } diff --git a/lib/std/os.zig b/lib/std/os.zig index 9035d8ecbd850515a8963dd25b9f002cf88fe37b..cda65b7ea7929e48b723f23f5c513974c24b9cb5 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -655,8 +655,7 @@ pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t { /// Open and possibly create a file. Keeps trying if it gets interrupted. /// See also `open`. -/// TODO https://github.com/ziglang/zig/issues/265 -pub fn openC(file_path: [*]const u8, flags: u32, perm: usize) OpenError!fd_t { +pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t { while (true) { const rc = system.open(file_path, flags, perm); switch (errno(rc)) { @@ -697,7 +696,7 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: usize) Open /// Open and possibly create a file. Keeps trying if it gets interrupted. /// `file_path` is relative to the open directory handle `dir_fd`. /// See also `openat`. -pub fn openatC(dir_fd: fd_t, file_path: [*]const u8, flags: u32, mode: usize) OpenError!fd_t { +pub fn openatC(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: usize) OpenError!fd_t { while (true) { const rc = system.openat(dir_fd, file_path, flags, mode); switch (errno(rc)) { @@ -757,7 +756,7 @@ pub const ExecveError = error{ /// Like `execve` except the parameters are null-terminated, /// matching the syscall API on all targets. This removes the need for an allocator. /// This function ignores PATH environment variable. See `execvpeC` for that. -pub fn execveC(path: [*]const u8, child_argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) ExecveError { +pub fn execveC(path: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) ExecveError { switch (errno(system.execve(path, child_argv, envp))) { 0 => unreachable, EFAULT => unreachable, @@ -784,7 +783,7 @@ pub fn execveC(path: [*]const u8, child_argv: [*]const ?[*]const u8, envp: [*]co /// matching the syscall API on all targets. This removes the need for an allocator. /// This function also uses the PATH environment variable to get the full path to the executable. /// If `file` is an absolute path, this is the same as `execveC`. -pub fn execvpeC(file: [*:0]const u8, child_argv: [*]const ?[*:0]const u8, envp: [*]const ?[*:0]const u8) ExecveError { +pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) ExecveError { const file_slice = mem.toSliceConst(u8, file); if (mem.indexOfScalar(u8, file_slice, '/') != null) return execveC(file, child_argv, envp); @@ -799,7 +798,8 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*]const ?[*:0]const u8, envp: path_buf[search_path.len] = '/'; mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice); path_buf[search_path.len + file_slice.len + 1] = 0; - err = execveC(&path_buf, child_argv, envp); + // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 + err = execveC(@ptrCast([*:0]u8, &path_buf), child_argv, envp); switch (err) { error.AccessDenied => seen_eacces = true, error.FileNotFound, error.NotDir => {}, @@ -842,10 +842,13 @@ pub fn execvpe( const envp_buf = try createNullDelimitedEnvMap(allocator, env_map); defer freeNullDelimitedEnvMap(allocator, envp_buf); - return execvpeC(argv_buf.ptr[0].?, argv_buf.ptr, envp_buf.ptr); + // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 + const argv_ptr = @ptrCast([*:null]?[*:0]u8, argv_buf.ptr); + + return execvpeC(argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr); } -pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.BufMap) ![]?[*:0]u8 { +pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.BufMap) ![:null]?[*:0]u8 { const envp_count = env_map.count(); const envp_buf = try allocator.alloc(?[*:0]u8, envp_count + 1); mem.set(?[*:0]u8, envp_buf, null); @@ -860,13 +863,14 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std. @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len); env_buf[env_buf.len - 1] = 0; - // TODO avoid @ptrCast using slice syntax with https://github.com/ziglang/zig/issues/3731 + // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 envp_buf[i] = @ptrCast([*:0]u8, env_buf.ptr); } assert(i == envp_count); } + // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 assert(envp_buf[envp_count] == null); - return envp_buf; + return @ptrCast([*:null]?[*:0]u8, envp_buf.ptr)[0..envp_count]; } pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void { @@ -967,7 +971,7 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError! /// This is the same as `symlink` except the parameters are null-terminated pointers. /// See also `symlink`. -pub fn symlinkC(target_path: [*]const u8, sym_link_path: [*]const u8) SymLinkError!void { +pub fn symlinkC(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLinkError!void { if (builtin.os == .windows) { const target_path_w = try windows.cStrToPrefixedFileW(target_path); const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path); @@ -999,7 +1003,7 @@ pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const return symlinkatC(target_path_c, newdirfd, sym_link_path_c); } -pub fn symlinkatC(target_path: [*]const u8, newdirfd: fd_t, sym_link_path: [*]const u8) SymLinkError!void { +pub fn symlinkatC(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:0]const u8) SymLinkError!void { switch (errno(system.symlinkat(target_path, newdirfd, sym_link_path))) { 0 => return, EFAULT => unreachable, @@ -1053,7 +1057,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void { } /// Same as `unlink` except the parameter is a null terminated UTF8-encoded string. -pub fn unlinkC(file_path: [*]const u8) UnlinkError!void { +pub fn unlinkC(file_path: [*:0]const u8) UnlinkError!void { if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path); return windows.DeleteFileW(&file_path_w); @@ -1093,7 +1097,7 @@ pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!vo } /// Same as `unlinkat` but `file_path` is a null-terminated string. -pub fn unlinkatC(dirfd: fd_t, file_path_c: [*]const u8, flags: u32) UnlinkatError!void { +pub fn unlinkatC(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatError!void { if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path_c); return unlinkatW(dirfd, &file_path_w, flags); @@ -1122,7 +1126,7 @@ pub fn unlinkatC(dirfd: fd_t, file_path_c: [*]const u8, flags: u32) UnlinkatErro } /// Same as `unlinkat` but `sub_path_w` is UTF16LE, NT prefixed. Windows only. -pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*]const u16, flags: u32) UnlinkatError!void { +pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*:0]const u16, flags: u32) UnlinkatError!void { const w = windows; const want_rmdir_behavior = (flags & AT_REMOVEDIR) != 0; @@ -1217,7 +1221,7 @@ pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void { } /// Same as `rename` except the parameters are null-terminated byte arrays. -pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void { +pub fn renameC(old_path: [*:0]const u8, new_path: [*:0]const u8) RenameError!void { if (builtin.os == .windows) { const old_path_w = try windows.cStrToPrefixedFileW(old_path); const new_path_w = try windows.cStrToPrefixedFileW(new_path); @@ -1249,7 +1253,7 @@ pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void { /// Same as `rename` except the parameters are null-terminated UTF16LE encoded byte arrays. /// Assumes target is Windows. -pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) RenameError!void { +pub fn renameW(old_path: [*:0]const u16, new_path: [*:0]const u16) RenameError!void { const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH; return windows.MoveFileExW(old_path, new_path, flags); } @@ -1283,7 +1287,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void { } /// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string. -pub fn mkdirC(dir_path: [*]const u8, mode: u32) MakeDirError!void { +pub fn mkdirC(dir_path: [*:0]const u8, mode: u32) MakeDirError!void { if (builtin.os == .windows) { const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); return windows.CreateDirectoryW(&dir_path_w, null); @@ -1333,7 +1337,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void { } /// Same as `rmdir` except the parameter is null-terminated. -pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void { +pub fn rmdirC(dir_path: [*:0]const u8) DeleteDirError!void { if (builtin.os == .windows) { const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); return windows.RemoveDirectoryW(&dir_path_w); @@ -1380,7 +1384,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { } /// Same as `chdir` except the parameter is null-terminated. -pub fn chdirC(dir_path: [*]const u8) ChangeCurDirError!void { +pub fn chdirC(dir_path: [*:0]const u8) ChangeCurDirError!void { if (builtin.os == .windows) { const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); @compileError("TODO implement chdir for Windows"); @@ -1422,7 +1426,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 { } /// Same as `readlink` except `file_path` is null-terminated. -pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { +pub fn readlinkC(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 { if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path); @compileError("TODO implement readlink for Windows"); @@ -1443,7 +1447,7 @@ pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { } } -pub fn readlinkatC(dirfd: fd_t, file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { +pub fn readlinkatC(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 { if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path); @compileError("TODO implement readlink for Windows"); @@ -2130,7 +2134,7 @@ pub fn inotify_add_watch(inotify_fd: i32, pathname: []const u8, mask: u32) INoti } /// Same as `inotify_add_watch` except pathname is null-terminated. -pub fn inotify_add_watchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) INotifyAddWatchError!i32 { +pub fn inotify_add_watchC(inotify_fd: i32, pathname: [*:0]const u8, mask: u32) INotifyAddWatchError!i32 { const rc = system.inotify_add_watch(inotify_fd, pathname, mask); switch (errno(rc)) { 0 => return @intCast(i32, rc), @@ -2287,7 +2291,7 @@ pub fn access(path: []const u8, mode: u32) AccessError!void { } /// Same as `access` except `path` is null-terminated. -pub fn accessC(path: [*]const u8, mode: u32) AccessError!void { +pub fn accessC(path: [*:0]const u8, mode: u32) AccessError!void { if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); _ = try windows.GetFileAttributesW(&path_w); @@ -2314,7 +2318,7 @@ pub fn accessC(path: [*]const u8, mode: u32) AccessError!void { /// Call from Windows-specific code if you already have a UTF-16LE encoded, null terminated string. /// Otherwise use `access` or `accessC`. /// TODO currently this ignores `mode`. -pub fn accessW(path: [*]const u16, mode: u32) windows.GetFileAttributesError!void { +pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!void { const ret = try windows.GetFileAttributesW(path); if (ret != windows.INVALID_FILE_ATTRIBUTES) { return; @@ -2381,7 +2385,7 @@ pub fn sysctl( } pub fn sysctlbynameC( - name: [*]const u8, + name: [*:0]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, @@ -2563,7 +2567,7 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE } /// Same as `realpath` except `pathname` is null-terminated. -pub fn realpathC(pathname: [*]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { +pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { if (builtin.os == .windows) { const pathname_w = try windows.cStrToPrefixedFileW(pathname); return realpathW(&pathname_w, out_buffer); @@ -2572,10 +2576,10 @@ pub fn realpathC(pathname: [*]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPat const fd = try openC(pathname, linux.O_PATH | linux.O_NONBLOCK | linux.O_CLOEXEC, 0); defer close(fd); - var procfs_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined; + var procfs_buf: ["/proc/self/fd/-2147483648".len:0]u8 = undefined; const proc_path = std.fmt.bufPrint(procfs_buf[0..], "/proc/self/fd/{}\x00", fd) catch unreachable; - return readlinkC(proc_path.ptr, out_buffer); + return readlinkC(@ptrCast([*:0]const u8, proc_path.ptr), out_buffer); } const result_path = std.c.realpath(pathname, out_buffer) orelse switch (std.c._errno().*) { EINVAL => unreachable, @@ -2594,7 +2598,7 @@ pub fn realpathC(pathname: [*]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPat } /// Same as `realpath` except `pathname` is null-terminated and UTF16LE-encoded. -pub fn realpathW(pathname: [*]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { +pub fn realpathW(pathname: [*:0]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { const h_file = try windows.CreateFileW( pathname, windows.GENERIC_READ, @@ -2749,8 +2753,8 @@ pub fn sched_getaffinity(pid: pid_t) SchedGetAffinityError!cpu_set_t { /// Used to convert a slice to a null terminated slice on the stack. /// TODO https://github.com/ziglang/zig/issues/287 -pub fn toPosixPath(file_path: []const u8) ![PATH_MAX]u8 { - var path_with_null: [PATH_MAX]u8 = undefined; +pub fn toPosixPath(file_path: []const u8) ![PATH_MAX-1:0]u8 { + var path_with_null: [PATH_MAX-1:0]u8 = undefined; // >= rather than > to make room for the null byte if (file_path.len >= PATH_MAX) return error.NameTooLong; mem.copy(u8, &path_with_null, file_path); @@ -2855,7 +2859,7 @@ pub const GetHostNameError = error{PermissionDenied} || UnexpectedError; pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 { if (builtin.link_libc) { switch (errno(system.gethostname(name_buffer, name_buffer.len))) { - 0 => return mem.toSlice(u8, name_buffer), + 0 => return mem.toSlice(u8, @ptrCast([*:0]u8, name_buffer)), EFAULT => unreachable, ENAMETOOLONG => unreachable, // HOST_NAME_MAX prevents this EPERM => return error.PermissionDenied, diff --git a/lib/std/os/bits/darwin.zig b/lib/std/os/bits/darwin.zig index 9451df6e199224b69775392f9f11f0ee46e2c4b9..26c9e7ec9b0961201ab9647b96b6179f89867263 100644 --- a/lib/std/os/bits/darwin.zig +++ b/lib/std/os/bits/darwin.zig @@ -1205,7 +1205,7 @@ pub const addrinfo = extern struct { socktype: i32, protocol: i32, addrlen: socklen_t, - canonname: ?[*]u8, + canonname: ?[*:0]u8, addr: ?*sockaddr, next: ?*addrinfo, }; diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index e101337c3ad586b20d5377530707656d66aca0c8..0fdf1dc0362108adc97358d9c0565963da304c7e 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -1355,7 +1355,7 @@ pub const addrinfo = extern struct { protocol: i32, addrlen: socklen_t, addr: ?*sockaddr, - canonname: ?[*]u8, + canonname: ?[*:0]u8, next: ?*addrinfo, }; diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig index fce29ef0b30cb8d19ec2a2ef30d31210b6c39722..7661be1f856de0d92327e1a951141e6f9d5ac26e 100644 --- a/lib/std/os/wasi.zig +++ b/lib/std/os/wasi.zig @@ -19,13 +19,13 @@ comptime { pub const iovec_t = iovec; pub const ciovec_t = iovec_const; -pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t; +pub extern "wasi_unstable" fn args_get(argv: [*][*:0]u8, argv_buf: [*]u8) errno_t; pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t; pub extern "wasi_unstable" fn clock_res_get(clock_id: clockid_t, resolution: *timestamp_t) errno_t; pub extern "wasi_unstable" fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t; -pub extern "wasi_unstable" fn environ_get(environ: [*]?[*]u8, environ_buf: [*]u8) errno_t; +pub extern "wasi_unstable" fn environ_get(environ: [*]?[*:0]u8, environ_buf: [*]u8) errno_t; pub extern "wasi_unstable" fn environ_sizes_get(environ_count: *usize, environ_buf_size: *usize) errno_t; pub extern "wasi_unstable" fn fd_advise(fd: fd_t, offset: filesize_t, len: filesize_t, advice: advice_t) errno_t; diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index a04e351799e9de520820ddcf571023edeb20c5c7..ecb0462db104a9c81f46bcfd29bfc207630abf9f 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -192,7 +192,7 @@ pub const FindFirstFileError = error{ }; pub fn FindFirstFile(dir_path: []const u8, find_file_data: *WIN32_FIND_DATAW) FindFirstFileError!HANDLE { - const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, [_]u16{ '\\', '*', 0 }); + const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, [_]u16{ '\\', '*'}); const handle = kernel32.FindFirstFileW(&dir_path_w, find_file_data); if (handle == INVALID_HANDLE_VALUE) { @@ -919,18 +919,18 @@ pub fn nanoSecondsToFileTime(ns: i64) FILETIME { }; } -pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 { +pub fn cStrToPrefixedFileW(s: [*:0]const u8) ![PATH_MAX_WIDE:0]u16 { return sliceToPrefixedFileW(mem.toSliceConst(u8, s)); } -pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 { - return sliceToPrefixedSuffixedFileW(s, [_]u16{0}); +pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE:0]u16 { + return sliceToPrefixedSuffixedFileW(s, &[_]u16{}); } /// Assumes an absolute path. -pub fn wToPrefixedFileW(s: []const u16) ![PATH_MAX_WIDE + 1]u16 { +pub fn wToPrefixedFileW(s: []const u16) ![PATH_MAX_WIDE:0]u16 { // TODO https://github.com/ziglang/zig/issues/2765 - var result: [PATH_MAX_WIDE + 1]u16 = undefined; + var result: [PATH_MAX_WIDE:0]u16 = undefined; const start_index = if (mem.startsWith(u16, s, [_]u16{'\\', '?'})) 0 else blk: { const prefix = [_]u16{ '\\', '?', '?', '\\' }; @@ -945,9 +945,9 @@ pub fn wToPrefixedFileW(s: []const u16) ![PATH_MAX_WIDE + 1]u16 { } -pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 { +pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len:0]u16 { // TODO https://github.com/ziglang/zig/issues/2765 - var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined; + var result: [PATH_MAX_WIDE + suffix.len:0]u16 = undefined; // > File I/O functions in the Windows API convert "/" to "\" as part of // > converting the name to an NT-style name, except when using the "\\?\" // > prefix as detailed in the following sections. diff --git a/lib/std/process.zig b/lib/std/process.zig index 3f065de8fc304a6836d8efcabd59ed4ed6c1a9a8..9880108465773bbfeadc7c4c7cf41cd4058ac7f7 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -77,7 +77,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { // TODO: Verify that the documentation is incorrect // https://github.com/WebAssembly/WASI/issues/27 - var environ = try allocator.alloc(?[*]u8, environ_count + 1); + var environ = try allocator.alloc(?[*:0]u8, environ_count + 1); defer allocator.free(environ); var environ_buf = try std.heap.wasm_allocator.alloc(u8, environ_buf_size); defer allocator.free(environ_buf); @@ -397,7 +397,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 { return os.unexpectedErrno(args_sizes_get_ret); } - var argv = try allocator.alloc([*]u8, count); + var argv = try allocator.alloc([*:0]u8, count); defer allocator.free(argv); var argv_buf = try allocator.alloc(u8, buf_size); diff --git a/src/analyze.cpp b/src/analyze.cpp index 7c9171d74a56800369638d708911382ba876e32a..70dfd4f181a111e3853bae033d87330284cf53cb 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6550,7 +6550,7 @@ static bool const_values_equal_array(CodeGen *g, ConstExprValue *a, ConstExprVal } bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { - assert(a->type->id == b->type->id); + if (a->type->id != b->type->id) return false; assert(a->special == ConstValSpecialStatic); assert(b->special == ConstValSpecialStatic); if (a->type == b->type) { -- 2.54.0