authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-06-05 13:23:20+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-06-13 16:30:39+01:00
log14e033ed95a43a5ff994df9dc524e5bc4f34452a
tree94d91e0eeceff82157e6741c0c386780529ae4d8
parent5c8b92db7f6e99d075af1cf87d48a5af0c748603
signaturelock-open Commit is signed but in an unrecognized format.

std.Build.Step.Run: convert relative paths to be relative to child cwd

Because any `LazyPath` might be resolved to a relative path, it's incorrect to pass that directly to a child process whose cwd might differ. Instead, if the child has an overriden cwd, we need to convert such paths to be relative to the child cwd using `std.fs.path.relative`.

1 files changed, 46 insertions(+), 22 deletions(-)

lib/std/Build/Step/Run.zig+46-22
...@@ -622,6 +622,18 @@ fn checksContainStderr(checks: []const StdIo.Check) bool {...@@ -622,6 +622,18 @@ fn checksContainStderr(checks: []const StdIo.Check) bool {
622 return false;622 return false;
623}623}
624624
625/// If `path` is cwd-relative, make it relative to the cwd of the child instead.
626///
627/// Whenever a path is included in the argv of a child, it should be put through this function first
628/// to make sure the child doesn't see paths relative to a cwd other than its own.
629fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 {
630 const b = run.step.owner;
631 const path_str = path.toString(b.graph.arena) catch @panic("OOM");
632 const child_lazy_cwd = run.cwd orelse return path_str;
633 const child_cwd = child_lazy_cwd.getPath3(b, &run.step).toString(b.graph.arena) catch @panic("OOM");
634 return std.fs.path.relative(b.graph.arena, child_cwd, path_str) catch @panic("OOM");
635}
636
625const IndexedOutput = struct {637const IndexedOutput = struct {
626 index: usize,638 index: usize,
627 tag: @typeInfo(Arg).@"union".tag_type.?,639 tag: @typeInfo(Arg).@"union".tag_type.?,
...@@ -676,14 +688,14 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -676,14 +688,14 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
676 man.hash.addBytes(bytes);688 man.hash.addBytes(bytes);
677 },689 },
678 .lazy_path => |file| {690 .lazy_path => |file| {
679 const file_path = file.lazy_path.getPath2(b, step);691 const file_path = file.lazy_path.getPath3(b, step);
680 try argv_list.append(b.fmt("{s}{s}", .{ file.prefix, file_path }));692 try argv_list.append(b.fmt("{s}{s}", .{ file.prefix, run.convertPathArg(file_path) }));
681 man.hash.addBytes(file.prefix);693 man.hash.addBytes(file.prefix);
682 _ = try man.addFile(file_path, null);694 _ = try man.addFilePath(file_path, null);
683 },695 },
684 .decorated_directory => |dd| {696 .decorated_directory => |dd| {
685 const file_path = dd.lazy_path.getPath3(b, step);697 const file_path = dd.lazy_path.getPath3(b, step);
686 const resolved_arg = b.fmt("{s}{}{s}", .{ dd.prefix, file_path, dd.suffix });698 const resolved_arg = b.fmt("{s}{s}{s}", .{ dd.prefix, run.convertPathArg(file_path), dd.suffix });
687 try argv_list.append(resolved_arg);699 try argv_list.append(resolved_arg);
688 man.hash.addBytes(resolved_arg);700 man.hash.addBytes(resolved_arg);
689 },701 },
...@@ -696,7 +708,10 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -696,7 +708,10 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
696 }708 }
697 const file_path = artifact.installed_path orelse artifact.generated_bin.?.path.?;709 const file_path = artifact.installed_path orelse artifact.generated_bin.?.path.?;
698710
699 try argv_list.append(b.fmt("{s}{s}", .{ pa.prefix, file_path }));711 try argv_list.append(b.fmt("{s}{s}", .{
712 pa.prefix,
713 run.convertPathArg(.{ .root_dir = .cwd(), .sub_path = file_path }),
714 }));
700715
701 _ = try man.addFile(file_path, null);716 _ = try man.addFile(file_path, null);
702 },717 },
...@@ -787,11 +802,14 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -787,11 +802,14 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
787 b.cache_root, output_sub_dir_path, @errorName(err),802 b.cache_root, output_sub_dir_path, @errorName(err),
788 });803 });
789 };804 };
790 const output_path = placeholder.output.generated_file.path.?;805 const arg_output_path = run.convertPathArg(.{
806 .root_dir = .cwd(),
807 .sub_path = placeholder.output.generated_file.getPath(),
808 });
791 argv_list.items[placeholder.index] = if (placeholder.output.prefix.len == 0)809 argv_list.items[placeholder.index] = if (placeholder.output.prefix.len == 0)
792 output_path810 arg_output_path
793 else811 else
794 b.fmt("{s}{s}", .{ placeholder.output.prefix, output_path });812 b.fmt("{s}{s}", .{ placeholder.output.prefix, arg_output_path });
795 }813 }
796814
797 try runCommand(run, argv_list.items, has_side_effects, output_dir_path, prog_node, null);815 try runCommand(run, argv_list.items, has_side_effects, output_dir_path, prog_node, null);
...@@ -816,12 +834,15 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -816,12 +834,15 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
816 b.cache_root, output_sub_dir_path, @errorName(err),834 b.cache_root, output_sub_dir_path, @errorName(err),
817 });835 });
818 };836 };
819 const output_path = try b.cache_root.join(arena, &output_components);837 const raw_output_path: Build.Cache.Path = .{
820 placeholder.output.generated_file.path = output_path;838 .root_dir = b.cache_root,
821 argv_list.items[placeholder.index] = if (placeholder.output.prefix.len == 0)839 .sub_path = b.pathJoin(&output_components),
822 output_path840 };
823 else841 placeholder.output.generated_file.path = raw_output_path.toString(b.graph.arena) catch @panic("OOM");
824 b.fmt("{s}{s}", .{ placeholder.output.prefix, output_path });842 argv_list.items[placeholder.index] = b.fmt("{s}{s}", .{
843 placeholder.output.prefix,
844 run.convertPathArg(raw_output_path),
845 });
825 }846 }
826847
827 try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, prog_node, null);848 try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, prog_node, null);
...@@ -899,20 +920,23 @@ pub fn rerunInFuzzMode(...@@ -899,20 +920,23 @@ pub fn rerunInFuzzMode(
899 try argv_list.append(arena, bytes);920 try argv_list.append(arena, bytes);
900 },921 },
901 .lazy_path => |file| {922 .lazy_path => |file| {
902 const file_path = file.lazy_path.getPath2(b, step);923 const file_path = file.lazy_path.getPath3(b, step);
903 try argv_list.append(arena, b.fmt("{s}{s}", .{ file.prefix, file_path }));924 try argv_list.append(arena, b.fmt("{s}{s}", .{ file.prefix, run.convertPathArg(file_path) }));
904 },925 },
905 .decorated_directory => |dd| {926 .decorated_directory => |dd| {
906 const file_path = dd.lazy_path.getPath3(b, step);927 const file_path = dd.lazy_path.getPath3(b, step);
907 try argv_list.append(arena, b.fmt("{s}{}{s}", .{ dd.prefix, file_path, dd.suffix }));928 try argv_list.append(arena, b.fmt("{s}{s}{s}", .{ dd.prefix, run.convertPathArg(file_path), dd.suffix }));
908 },929 },
909 .artifact => |pa| {930 .artifact => |pa| {
910 const artifact = pa.artifact;931 const artifact = pa.artifact;
911 const file_path = if (artifact == run.producer.?)932 const file_path: []const u8 = p: {
912 b.fmt("{}", .{run.rebuilt_executable.?})933 if (artifact == run.producer.?) break :p b.fmt("{}", .{run.rebuilt_executable.?});
913 else934 break :p artifact.installed_path orelse artifact.generated_bin.?.path.?;
914 (artifact.installed_path orelse artifact.generated_bin.?.path.?);935 };
915 try argv_list.append(arena, b.fmt("{s}{s}", .{ pa.prefix, file_path }));936 try argv_list.append(arena, b.fmt("{s}{s}", .{
937 pa.prefix,
938 run.convertPathArg(.{ .root_dir = .cwd(), .sub_path = file_path }),
939 }));
916 },940 },
917 .output_file, .output_directory => unreachable,941 .output_file, .output_directory => unreachable,
918 }942 }