Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/c/string.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ comptime {

fn strcmp(s1: [*:0]const c_char, s2: [*:0]const c_char) callconv(.c) c_int {
// We need to perform unsigned comparisons.
return switch (std.mem.orderZ(u8, @ptrCast(s1), @ptrCast(s2))) {
return switch (std.mem.orderSentinel(u8, 0, @ptrCast(s1), @ptrCast(s2))) {
.lt => -1,
.eq => 0,
.gt => 1,
Expand Down
4 changes: 2 additions & 2 deletions lib/compiler/aro/aro/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -890,7 +890,7 @@ fn genLval(c: *CodeGen, node_index: Node.Index) Error!Ir.Ref {
}
}

const duped_name = try c.builder.arena.allocator().dupeZ(u8, slice);
const duped_name = try c.builder.arena.allocator().dupeSentinel(u8, slice, 0);
const ref: Ir.Ref = @enumFromInt(c.builder.instructions.len);
try c.builder.instructions.append(c.builder.gpa, .{ .tag = .symbol, .data = .{ .label = duped_name }, .ty = .ptr });
return ref;
Expand Down Expand Up @@ -1108,7 +1108,7 @@ fn genCall(c: *CodeGen, call: Node.Call) Error!Ir.Ref {
}
}

const duped_name = try c.builder.arena.allocator().dupeZ(u8, slice);
const duped_name = try c.builder.arena.allocator().dupeSentinel(u8, slice, 0);
const ref: Ir.Ref = @enumFromInt(c.builder.instructions.len);
try c.builder.instructions.append(c.builder.gpa, .{ .tag = .symbol, .data = .{ .label = duped_name }, .ty = .ptr });
break :blk ref;
Expand Down
2 changes: 1 addition & 1 deletion lib/std/Build/Watch/FsEvents.zig
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ pub fn setPaths(fse: *FsEvents, gpa: Allocator, steps: []const *std.Build.Step)
} else {
fse.watch_roots = try gpa.realloc(fse.watch_roots, need_dirs.count());
for (fse.watch_roots, need_dirs.keys()) |*out, in| {
out.* = try paths_arena.dupeZ(u8, in);
out.* = try paths_arena.dupeSentinel(u8, in, 0);
}
}
if (enable_debug_logs) {
Expand Down
2 changes: 1 addition & 1 deletion lib/std/debug.zig
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@ pub fn defaultPanic(

if (uefi.system_table.boot_services) |bs| {
// ExitData buffer must be allocated using boot_services.allocatePool (spec: page 220)
const exit_data = uefi.raw_pool_allocator.dupeZ(u16, exit_msg) catch @trap();
const exit_data = uefi.raw_pool_allocator.dupeSentinel(u16, exit_msg, 0) catch @trap();
bs.exit(uefi.handle, .aborted, exit_data) catch {};
}
@trap();
Expand Down
2 changes: 1 addition & 1 deletion lib/std/fs/get_app_data_dir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub fn getAppDataDir(allocator: mem.Allocator, appname: []const u8) GetAppDataDi
.haiku => {
var dir_path_buf: [std.fs.max_path_bytes]u8 = undefined;
const rc = std.c.find_directory(.B_USER_SETTINGS_DIRECTORY, -1, true, &dir_path_buf, dir_path_buf.len);
const settings_dir = try allocator.dupeZ(u8, mem.sliceTo(&dir_path_buf, 0));
const settings_dir = try allocator.dupeSentinel(u8, mem.sliceTo(&dir_path_buf, 0), 0);
defer allocator.free(settings_dir);
switch (rc) {
0 => return fs.path.join(allocator, &[_][]const u8{ settings_dir, appname }),
Expand Down
4 changes: 2 additions & 2 deletions lib/std/fs/test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const TestContext = struct {
const allocator = self.arena.allocator();
const transformed_path = try self.transform_fn(allocator, self.dir, relative_path);
if (native_os == .windows) {
const transformed_sep_path = try allocator.dupeZ(u8, transformed_path);
const transformed_sep_path = try allocator.dupeSentinel(u8, transformed_path, 0);
std.mem.replaceScalar(u8, transformed_sep_path, switch (self.path_sep) {
'/' => '\\',
'\\' => '/',
Expand All @@ -123,7 +123,7 @@ const TestContext = struct {
pub fn toCanonicalPathSep(self: *TestContext, path: [:0]const u8) ![:0]const u8 {
if (native_os == .windows) {
const allocator = self.arena.allocator();
const transformed_sep_path = try allocator.dupeZ(u8, path);
const transformed_sep_path = try allocator.dupeSentinel(u8, path, 0);
std.mem.replaceScalar(u8, transformed_sep_path, '/', '\\');
return transformed_sep_path;
}
Expand Down
32 changes: 27 additions & 5 deletions lib/std/mem.zig
Original file line number Diff line number Diff line change
Expand Up @@ -658,11 +658,21 @@ pub fn order(comptime T: type, lhs: []const T, rhs: []const T) math.Order {
return math.order(lhs.len, rhs.len);
}

/// Compares two many-item pointers with NUL-termination lexicographically.
pub fn orderZ(comptime T: type, lhs: [*:0]const T, rhs: [*:0]const T) math.Order {
/// Compares two many-item pointers with sentinel-termination lexicographically.
pub fn orderSentinel(comptime T: type, comptime s: T, lhs: [*:s]const T, rhs: [*:s]const T) math.Order {
var i: usize = 0;
while (lhs[i] == rhs[i] and lhs[i] != 0) : (i += 1) {}
return math.order(lhs[i], rhs[i]);
while (lhs[i] == rhs[i] and lhs[i] != s) : (i += 1) {}
if (lhs[i] == s) {
return if (rhs[i] == s) .eq else .lt;
} else if (rhs[i] == s) {
return .gt;
} else {
return math.order(lhs[i], rhs[i]);
}
}
/// Deprecated in favor of `orderSentinel`.
pub fn orderZ(comptime T: type, lhs: [*:0]const T, rhs: [*:0]const T) math.Order {
return orderSentinel(T, 0, lhs, rhs);
}

test order {
Expand All @@ -671,8 +681,20 @@ test order {
try testing.expect(order(u8, "abc", "abc0") == .lt);
try testing.expect(order(u8, "", "") == .eq);
try testing.expect(order(u8, "", "a") == .lt);
try testing.expect(order(i8, &.{ -1, -2 }, &.{ -1, -2, -3 }) == .lt);
}

test orderSentinel {
try testing.expect(orderSentinel(u8, 0, "abcd", "bee") == .lt);
try testing.expect(orderSentinel(u8, 0, "abc", "abc") == .eq);
try testing.expect(orderSentinel(u8, 0, "abc", "abc0") == .lt);
try testing.expect(orderSentinel(u8, 0, "", "") == .eq);
try testing.expect(orderSentinel(u8, 0, "", "a") == .lt);
try testing.expect(orderSentinel(i8, 0, &.{ -1, -2 }, &.{ -1, -2, -3 }) == .lt);
try testing.expect(orderSentinel(u4, 4, &.{ 1, 2, 3 }, &.{ 1, 2, 3 }) == .eq);
try testing.expect(orderSentinel(u4, 4, &.{ 1, 2, 3 }, &.{ 1, 2 }) == .gt);
try testing.expect(orderSentinel(u4, 4, &.{ 1, 2, 3 }, &.{ 1, 2, 3, 5 }) == .lt);
}
test orderZ {
try testing.expect(orderZ(u8, "abcd", "bee") == .lt);
try testing.expect(orderZ(u8, "abc", "abc") == .eq);
Expand Down Expand Up @@ -4862,7 +4884,7 @@ test isAligned {
}

test "freeing empty string with null-terminated sentinel" {
const empty_string = try testing.allocator.dupeZ(u8, "");
const empty_string = try testing.allocator.dupeSentinel(u8, "", 0);
testing.allocator.free(empty_string);
}

Expand Down
12 changes: 8 additions & 4 deletions lib/std/mem/Allocator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -451,12 +451,16 @@ pub fn dupe(allocator: Allocator, comptime T: type, m: []const T) Error![]T {
return new_buf;
}

/// Copies `m` to newly allocated memory, with a null-terminated element. Caller owns the memory.
pub fn dupeZ(allocator: Allocator, comptime T: type, m: []const T) Error![:0]T {
/// Copies `m` to newly allocated memory, with a sentinel-terminated element. Caller owns the memory.
pub fn dupeSentinel(allocator: Allocator, comptime T: type, m: []const T, comptime s: T) Error![:s]T {
const new_buf = try allocator.alloc(T, m.len + 1);
@memcpy(new_buf[0..m.len], m);
new_buf[m.len] = 0;
return new_buf[0..m.len :0];
new_buf[m.len] = s;
return new_buf[0..m.len :s];
}
/// Deprecated in favor of `dupeSentinel`
pub fn dupeZ(allocator: Allocator, comptime T: type, m: []const T) Error![:0]T {
return try dupeSentinel(allocator, T, m, 0);
}

/// An allocator that always fails to allocate.
Expand Down
4 changes: 2 additions & 2 deletions lib/std/net.zig
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,7 @@ pub fn getAddressList(gpa: Allocator, name: []const u8, port: u16) GetAddressLis
errdefer result.deinit();

if (native_os == .windows) {
const name_c = try gpa.dupeZ(u8, name);
const name_c = try gpa.dupeSentinel(u8, name, 0);
defer gpa.free(name_c);

const port_c = try std.fmt.allocPrintSentinel(gpa, "{d}", .{port}, 0);
Expand Down Expand Up @@ -982,7 +982,7 @@ pub fn getAddressList(gpa: Allocator, name: []const u8, port: u16) GetAddressLis
}

if (builtin.link_libc) {
const name_c = try gpa.dupeZ(u8, name);
const name_c = try gpa.dupeSentinel(u8, name, 0);
defer gpa.free(name_c);

const port_c = try std.fmt.allocPrintSentinel(gpa, "{d}", .{port}, 0);
Expand Down
2 changes: 1 addition & 1 deletion lib/std/os/plan9.zig
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ pub fn openat(dirfd: i32, path: [*:0]const u8, flags: u32, _: mode_t) usize {
const dir_path = std.mem.span(@as([*:0]u8, @ptrCast(&dir_path_buf)));
const total_path = std.fs.path.join(alloc, &.{ dir_path, std.mem.span(path) }) catch unreachable; // the allocation shouldn't fail because it should not exceed max_path_bytes
fba.reset();
const total_path_z = alloc.dupeZ(u8, total_path) catch unreachable; // should not exceed max_path_bytes + 1
const total_path_z = alloc.dupeSentinel(u8, total_path, 0) catch unreachable; // should not exceed max_path_bytes + 1
return open(total_path_z.ptr, flags);
}

Expand Down
4 changes: 2 additions & 2 deletions lib/std/process.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1721,7 +1721,7 @@ pub fn execve(
const arena = arena_allocator.allocator();

const argv_buf = try arena.allocSentinel(?[*:0]const u8, argv.len, null);
for (argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr;
for (argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeSentinel(u8, arg, 0)).ptr;

const envp = m: {
if (env_map) |m| {
Expand Down Expand Up @@ -1999,7 +1999,7 @@ pub fn createEnvironFromExisting(
},
.nothing => {},
};
envp_buf[i] = try arena.dupeZ(u8, mem.span(line));
envp_buf[i] = try arena.dupeSentinel(u8, mem.span(line), 0);
i += 1;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/std/process/Child.zig
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ fn spawnPosix(self: *ChildProcess) SpawnError!void {
// Therefore, we do all the allocation for the execve() before the fork().
// This means we must do the null-termination of argv and env vars here.
const argv_buf = try arena.allocSentinel(?[*:0]const u8, self.argv.len, null);
for (self.argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr;
for (self.argv, 0..) |arg, i| argv_buf[i] = (try arena.dupeSentinel(u8, arg, 0)).ptr;

const prog_fileno = 3;
comptime assert(@max(posix.STDIN_FILENO, posix.STDOUT_FILENO, posix.STDERR_FILENO) + 1 == prog_fileno);
Expand Down
20 changes: 10 additions & 10 deletions lib/std/zig/LibCInstallation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub fn parse(
if (value.len == 0) {
@field(self, field.name) = null;
} else {
found_keys[i].allocated = try allocator.dupeZ(u8, value);
found_keys[i].allocated = try allocator.dupeSentinel(u8, value, 0);
@field(self, field.name) = found_keys[i].allocated;
}
break;
Expand Down Expand Up @@ -197,16 +197,16 @@ pub fn findNative(args: FindNativeOptions) FindError!LibCInstallation {
} else if (is_haiku) {
try self.findNativeIncludeDirPosix(args);
try self.findNativeGccDirHaiku(args);
self.crt_dir = try args.allocator.dupeZ(u8, "/system/develop/lib");
self.crt_dir = try args.allocator.dupeSentinel(u8, "/system/develop/lib", 0);
} else if (builtin.target.os.tag.isSolarish()) {
// There is only one libc, and its headers/libraries are always in the same spot.
self.include_dir = try args.allocator.dupeZ(u8, "/usr/include");
self.sys_include_dir = try args.allocator.dupeZ(u8, "/usr/include");
self.crt_dir = try args.allocator.dupeZ(u8, "/usr/lib/64");
self.include_dir = try args.allocator.dupeSentinel(u8, "/usr/include", 0);
self.sys_include_dir = try args.allocator.dupeSentinel(u8, "/usr/include", 0);
self.crt_dir = try args.allocator.dupeSentinel(u8, "/usr/lib/64", 0);
} else if (std.process.can_spawn) {
try self.findNativeIncludeDirPosix(args);
switch (builtin.target.os.tag) {
.freebsd, .netbsd, .openbsd, .dragonfly => self.crt_dir = try args.allocator.dupeZ(u8, "/usr/lib"),
.freebsd, .netbsd, .openbsd, .dragonfly => self.crt_dir = try args.allocator.dupeSentinel(u8, "/usr/lib", 0),
.linux => try self.findNativeCrtDirPosix(args),
else => {},
}
Expand Down Expand Up @@ -330,7 +330,7 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) F

if (self.include_dir == null) {
if (search_dir.accessZ(include_dir_example_file, .{})) |_| {
self.include_dir = try allocator.dupeZ(u8, search_path);
self.include_dir = try allocator.dupeSentinel(u8, search_path, 0);
} else |err| switch (err) {
error.FileNotFound => {},
else => return error.FileSystem,
Expand All @@ -339,7 +339,7 @@ fn findNativeIncludeDirPosix(self: *LibCInstallation, args: FindNativeOptions) F

if (self.sys_include_dir == null) {
if (search_dir.accessZ(sys_include_dir_example_file, .{})) |_| {
self.sys_include_dir = try allocator.dupeZ(u8, search_path);
self.sys_include_dir = try allocator.dupeSentinel(u8, search_path, 0);
} else |err| switch (err) {
error.FileNotFound => {},
else => return error.FileSystem,
Expand Down Expand Up @@ -622,10 +622,10 @@ fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 {
// So we detect failure by checking if the output matches exactly the input.
if (std.mem.eql(u8, line, args.search_basename)) return error.LibCRuntimeNotFound;
switch (args.want_dirname) {
.full_path => return allocator.dupeZ(u8, line),
.full_path => return allocator.dupeSentinel(u8, line, 0),
.only_dir => {
const dirname = fs.path.dirname(line) orelse return error.LibCRuntimeNotFound;
return allocator.dupeZ(u8, dirname);
return allocator.dupeSentinel(u8, dirname, 0);
},
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1933,7 +1933,7 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options
const comp: *Compilation = comp: {
// We put the `Compilation` itself in the arena. Freeing the arena will free the module.
// It's initialized later after we prepare the initialization options.
const root_name = try arena.dupeZ(u8, options.root_name);
const root_name = try arena.dupeSentinel(u8, options.root_name, 0);

// The "any" values provided by resolved config only account for
// explicitly-provided settings. We now make them additionally account
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/llvm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -936,7 +936,7 @@ pub const Object = struct {
}

const target_triple_sentinel =
try o.gpa.dupeZ(u8, o.builder.target_triple.slice(&o.builder).?);
try o.gpa.dupeSentinel(u8, o.builder.target_triple.slice(&o.builder).?, 0);
defer o.gpa.free(target_triple_sentinel);

const emit_asm_msg = options.asm_path orelse "(none)";
Expand Down
2 changes: 1 addition & 1 deletion src/libs/mingw.zig
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {

if (!build_options.have_llvm) return error.ZigCompilerNotBuiltWithLLVMExtensions;
const llvm_bindings = @import("../codegen/llvm/bindings.zig");
const def_final_path_z = try arena.dupeZ(u8, def_final_path);
const def_final_path_z = try arena.dupeSentinel(u8, def_final_path, 0);
const lib_final_path_z = try comp.dirs.global_cache.joinZ(arena, &.{lib_final_path});
if (llvm_bindings.WriteImportLibrary(
def_final_path_z.ptr,
Expand Down
4 changes: 2 additions & 2 deletions src/link/Lld.zig
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) !void {
const comp = base.comp;
const directory = base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{base.emit.sub_path});
const full_out_path_z = try arena.dupeZ(u8, full_out_path);
const full_out_path_z = try arena.dupeSentinel(u8, full_out_path, 0);
const opt_zcu = comp.zcu;

const zcu_obj_path: ?Cache.Path = if (opt_zcu != null) p: {
Expand Down Expand Up @@ -325,7 +325,7 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) !void {
object_files.appendAssumeCapacity(try key.status.success.object_path.toStringZ(arena));
}
for (comp.win32_resource_table.keys()) |key| {
object_files.appendAssumeCapacity(try arena.dupeZ(u8, key.status.success.res_path));
object_files.appendAssumeCapacity(try arena.dupeSentinel(u8, key.status.success.res_path, 0));
}
if (zcu_obj_path) |p| object_files.appendAssumeCapacity(try p.toStringZ(arena));
if (compiler_rt_path) |p| object_files.appendAssumeCapacity(try p.toStringZ(arena));
Expand Down
6 changes: 3 additions & 3 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4471,7 +4471,7 @@ fn runOrTestHotSwap(
const arena = arena_allocator.allocator();

const argv_buf = try arena.allocSentinel(?[*:0]u8, argv.items.len, null);
for (argv.items, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr;
for (argv.items, 0..) |arg, i| argv_buf[i] = (try arena.dupeSentinel(u8, arg, 0)).ptr;

const pid = try PosixSpawn.spawn(argv.items[0], null, attr, argv_buf, std.c.environ);
return pid;
Expand Down Expand Up @@ -5600,7 +5600,7 @@ extern "c" fn ZigLlvmAr_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
fn argsCopyZ(alloc: Allocator, args: []const []const u8) ![:null]?[*:0]u8 {
var argv = try alloc.allocSentinel(?[*:0]u8, args.len, null);
for (args, 0..) |arg, i| {
argv[i] = try alloc.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation.
argv[i] = try alloc.dupeSentinel(u8, arg, 0); // TODO If there was an argsAllocZ we could avoid this allocation.
}
return argv;
}
Expand Down Expand Up @@ -6322,7 +6322,7 @@ fn cmdDumpLlvmInts(
if (!build_options.have_llvm)
fatal("compiler does not use LLVM; cannot dump LLVM integer sizes", .{});

const triple = try arena.dupeZ(u8, args[0]);
const triple = try arena.dupeSentinel(u8, args[0], 0);

const llvm = @import("codegen/llvm/bindings.zig");

Expand Down