commit 642d017fea531d1347b8ade16c33065389a20192 (tree)
parent 9b6dd7ee5c4137942f7fbbdd27d8e06f6ce7c7b1
Author: Andrew Kelley <andrew@ziglang.org>
Date: Sat, 23 May 2026 15:34:31 -0700
Maker: fix resolveLazyPath accidental mutation
Diffstat:
4 files changed, 35 insertions(+), 32 deletions(-)
diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig
@@ -1708,12 +1708,14 @@ pub fn resolveLazyPath(
.source_path => |sp| try packagePath(maker, arena, sp.owner, sp.sub_path.slice(c)),
.relative => |relative| relativePath(maker, relative),
.generated => |gen| {
- const base = generatedPath(maker, gen.index);
+ const base = generatedPath(maker, gen.index).*;
var file_path = base;
for (0..gen.flags.up) |_| {
file_path.sub_path = Dir.path.dirname(file_path.sub_path) orelse {
const s = stepByIndex(maker, asking_step_index);
- return s.fail(maker, "invalid LazyPath traversal: up {d} times from {f}", .{ gen.flags.up, base });
+ return s.fail(maker, "invalid LazyPath traversal: up {d} times from {f}", .{
+ gen.flags.up, base,
+ });
};
}
return file_path.join(arena, gen.sub_path.slice(c));
diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig
@@ -242,21 +242,23 @@ pub fn addPrefixedArtifactArg(run: *Run, prefix: []const u8, artifact: *Step.Com
/// Returns a `std.Build.LazyPath` which can be used as inputs to other APIs
/// throughout the build system.
///
+/// `sub_path` is the name of the generated output file which may have zero or
+/// more path components.
+///
/// Related:
/// * `addPrefixedOutputFileArg` - same thing but prepends a string to the argument
/// * `addFileArg` - for input files given to the child process
-pub fn addOutputFileArg(run: *Run, basename: []const u8) std.Build.LazyPath {
- return run.addPrefixedOutputFileArg("", basename);
+pub fn addOutputFileArg(run: *Run, sub_path: []const u8) std.Build.LazyPath {
+ return run.addPrefixedOutputFileArg("", sub_path);
}
/// Provides a file path as a command line argument to the command being run.
-/// Asserts `basename` is not empty.
///
-/// For example, a prefix of "-o" and basename of "output.txt" will result in
+/// For example, a prefix of "-o" and `sub_path` of "output.txt" will result in
/// the child process seeing something like this: "-ozig-cache/.../output.txt"
///
/// The child process will see a single argument, regardless of whether the
-/// prefix or basename have spaces.
+/// prefix or `sub_path` have spaces.
///
/// The returned `std.Build.LazyPath` can be used as inputs to other APIs
/// throughout the build system.
@@ -267,23 +269,27 @@ pub fn addOutputFileArg(run: *Run, basename: []const u8) std.Build.LazyPath {
pub fn addPrefixedOutputFileArg(
run: *Run,
prefix: []const u8,
- basename: []const u8,
+ /// The name of the generated output file which may have zero or more path
+ /// components.
+ ///
+ /// Asserted to be non-empty.
+ sub_path: []const u8,
) std.Build.LazyPath {
const b = run.step.owner;
const graph = b.graph;
const arena = graph.arena;
- if (basename.len == 0) @panic("basename must not be empty");
+ assert(sub_path.len != 0);
- const output = arena.create(Output) catch @panic("OOM");
+ const output = graph.create(Output);
output.* = .{
.prefix = graph.dupeString(prefix),
- .basename = graph.dupeString(basename),
+ .basename = graph.dupeString(sub_path),
.generated_file = graph.addGeneratedFile(&run.step),
};
run.argv.append(arena, .{ .output_file = output }) catch @panic("OOM");
if (run.rename_step_with_output_arg) {
- run.setName(b.fmt("{s} ({s})", .{ run.step.name, basename }));
+ run.setName(b.fmt("{s} ({s})", .{ run.step.name, sub_path }));
}
return .{ .generated = .{ .index = output.generated_file } };
diff --git a/test/standalone/dirname/build.zig b/test/standalone/dirname/build.zig
@@ -27,22 +27,16 @@ pub fn build(b: *std.Build) void {
}),
});
- // Known path:
- addTestRun(test_step, exists_in, touch_src.dirname(), &.{"touch.zig"});
-
- // Generated file:
- addTestRun(test_step, exists_in, generated.dirname(), &.{"generated.txt"});
-
- // Generated file multiple levels:
- addTestRun(test_step, exists_in, generated.dirname().dirname(), &.{
+ addTestRun(test_step, exists_in, "run exists_in (known path)", touch_src.dirname(), &.{"touch.zig"});
+ addTestRun(test_step, exists_in, "run exists_in (generated file)", generated.dirname(), &.{"generated.txt"});
+ addTestRun(test_step, exists_in, "run exists_in (generated file multi level)", generated.dirname().dirname(), &.{
"subdir" ++ std.fs.path.sep_str ++ "generated.txt",
});
- // Absolute path:
const write_files = b.addWriteFiles();
_ = write_files.add("foo.txt", "");
const abs_path = write_files.getDirectory();
- addTestRun(test_step, exists_in, abs_path, &.{"foo.txt"});
+ addTestRun(test_step, exists_in, "run exists_in (absolute path)", abs_path, &.{"foo.txt"});
}
// Runs exe with the parameters [dirname, args...].
@@ -50,10 +44,12 @@ pub fn build(b: *std.Build) void {
fn addTestRun(
test_step: *std.Build.Step,
exe: *std.Build.Step.Compile,
+ step_name: []const u8,
dirname: std.Build.LazyPath,
args: []const []const u8,
) void {
const run = test_step.owner.addRunArtifact(exe);
+ run.setName(step_name);
run.addDirectoryArg(dirname);
run.addArgs(args);
run.expectExitCode(0);
diff --git a/test/standalone/dirname/touch.zig b/test/standalone/dirname/touch.zig
@@ -7,27 +7,26 @@
//! Path must be absolute.
const std = @import("std");
+const Io = std.Io;
pub fn main(init: std.process.Init) !void {
+ const io = init.io;
+
var args = try init.minimal.args.iterateAllocator(init.gpa);
defer args.deinit();
- _ = args.next() orelse unreachable; // skip binary name
+ _ = args.next().?; // skip binary name
const path = args.next() orelse {
std.log.err("missing <path> argument", .{});
return error.BadUsage;
};
- const dir_path = std.Io.Dir.path.dirname(path) orelse unreachable;
- const basename = std.Io.Dir.path.basename(path);
-
- const io = std.Io.Threaded.global_single_threaded.io();
+ const dir_path = Io.Dir.path.dirname(path).?;
+ const basename = Io.Dir.path.basename(path);
- var dir = try std.Io.Dir.cwd().openDir(io, dir_path, .{});
+ var dir = try Io.Dir.cwd().openDir(io, dir_path, .{});
defer dir.close(io);
- _ = dir.statFile(io, basename, .{}) catch {
- var file = try dir.createFile(io, basename, .{});
- file.close(io);
- };
+ var file = try dir.createFile(io, basename, .{ .truncate = false });
+ file.close(io);
}