mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-26 13:01:34 +03:00
std.Io.Threaded: make environ init non-optional
and argv0 on systems that need it too. fixes surprising behavior for applications that forget to initialize the environment field.
This commit is contained in:
@@ -39,7 +39,10 @@ pub fn main(init: process.Init.Minimal) !void {
|
||||
|
||||
const args = try init.args.toSlice(arena);
|
||||
|
||||
var threaded: std.Io.Threaded = .init(gpa, .{});
|
||||
var threaded: std.Io.Threaded = .init(gpa, .{
|
||||
.environ = init.environ,
|
||||
.argv0 = .init(init.args),
|
||||
});
|
||||
defer threaded.deinit();
|
||||
const io = threaded.io();
|
||||
|
||||
|
||||
@@ -65,13 +65,13 @@ pub fn main(init: std.process.Init.Minimal) void {
|
||||
}
|
||||
|
||||
if (listen) {
|
||||
return mainServer(args) catch @panic("internal test runner failure");
|
||||
return mainServer(init) catch @panic("internal test runner failure");
|
||||
} else {
|
||||
return mainTerminal(args);
|
||||
return mainTerminal(init);
|
||||
}
|
||||
}
|
||||
|
||||
fn mainServer(args: []const [:0]const u8) !void {
|
||||
fn mainServer(init: std.process.Init.Minimal) !void {
|
||||
@disableInstrumentation();
|
||||
var stdin_reader = Io.File.stdin().readerStreaming(runner_threaded_io, &stdin_buffer);
|
||||
var stdout_writer = Io.File.stdout().writerStreaming(runner_threaded_io, &stdout_buffer);
|
||||
@@ -131,7 +131,8 @@ fn mainServer(args: []const [:0]const u8) !void {
|
||||
.run_test => {
|
||||
testing.allocator_instance = .{};
|
||||
testing.io_instance = .init(testing.allocator, .{
|
||||
.argv0 = if (@hasField(Io.Threaded.Argv0, "value")) .{ .value = args[0] } else .{},
|
||||
.argv0 = .init(init.args),
|
||||
.environ = init.environ,
|
||||
});
|
||||
log_err_count = 0;
|
||||
const index = try server.receiveBody_u32();
|
||||
@@ -216,7 +217,7 @@ fn mainServer(args: []const [:0]const u8) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn mainTerminal(args: []const [:0]const u8) void {
|
||||
fn mainTerminal(init: std.process.Init.Minimal) void {
|
||||
@disableInstrumentation();
|
||||
if (builtin.fuzz) @panic("fuzz test requires server");
|
||||
|
||||
@@ -235,7 +236,8 @@ fn mainTerminal(args: []const [:0]const u8) void {
|
||||
for (test_fn_list, 0..) |test_fn, i| {
|
||||
testing.allocator_instance = .{};
|
||||
testing.io_instance = .init(testing.allocator, .{
|
||||
.argv0 = if (@hasField(Io.Threaded.Argv0, "value")) .{ .value = args[0] } else .{},
|
||||
.argv0 = .init(init.args),
|
||||
.environ = init.environ,
|
||||
});
|
||||
defer {
|
||||
testing.io_instance.deinit();
|
||||
|
||||
+4
-12
@@ -1881,19 +1881,11 @@ pub fn runAllowFail(
|
||||
/// inside step make() functions. If any errors occur, it fails the build with
|
||||
/// a helpful message.
|
||||
pub fn run(b: *Build, argv: []const []const u8) []u8 {
|
||||
if (!process.can_spawn) {
|
||||
std.debug.print("unable to spawn the following command: cannot spawn child process\n{s}\n", .{
|
||||
try Step.allocPrintCmd(b.allocator, null, null, argv),
|
||||
});
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var code: u8 = undefined;
|
||||
return b.runAllowFail(argv, &code, .inherit) catch |err| {
|
||||
const printed_cmd = Step.allocPrintCmd(b.allocator, null, null, argv) catch @panic("OOM");
|
||||
std.debug.print("unable to spawn the following command: {t}\n{s}\n", .{ err, printed_cmd });
|
||||
process.exit(1);
|
||||
};
|
||||
return b.runAllowFail(argv, &code, .inherit) catch |err| process.fatal(
|
||||
"the following command failed with {t}:\n{s}",
|
||||
.{ err, Step.allocPrintCmd(b.allocator, null, null, argv) catch @panic("OOM") },
|
||||
);
|
||||
}
|
||||
|
||||
pub fn addSearchPrefix(b: *Build, search_prefix: []const u8) void {
|
||||
|
||||
+20
-5
@@ -66,12 +66,25 @@ environ: Environ,
|
||||
|
||||
pub const Argv0 = switch (native_os) {
|
||||
.openbsd, .haiku => struct {
|
||||
value: ?[*:0]const u8 = null,
|
||||
value: ?[*:0]const u8,
|
||||
|
||||
pub const empty: Argv0 = .{ .value = null };
|
||||
|
||||
pub fn init(args: process.Args) Argv0 {
|
||||
return .{ .value = args.value[0] };
|
||||
}
|
||||
},
|
||||
else => struct {
|
||||
pub const empty: Argv0 = .{};
|
||||
|
||||
pub fn init(args: process.Args) Argv0 {
|
||||
_ = args;
|
||||
return .{};
|
||||
}
|
||||
},
|
||||
else => struct {},
|
||||
};
|
||||
|
||||
pub const Environ = struct {
|
||||
const Environ = struct {
|
||||
/// Unmodified data directly from the OS.
|
||||
block: process.Environ.Block = &.{},
|
||||
/// Protected by `mutex`. Determines whether the other fields have been
|
||||
@@ -1141,7 +1154,8 @@ pub const InitOptions = struct {
|
||||
/// Affects the following operations:
|
||||
/// * `fileIsTty`
|
||||
/// * `processExecutablePath` on OpenBSD and Haiku (observes "PATH").
|
||||
environ: Environ = .{},
|
||||
/// * `processSpawn`, `processSpawnPath`, `processReplace`, `processReplacePath`
|
||||
environ: process.Environ,
|
||||
};
|
||||
|
||||
/// Related:
|
||||
@@ -1171,8 +1185,9 @@ pub fn init(
|
||||
.old_sig_pipe = undefined,
|
||||
.have_signal_handler = false,
|
||||
.argv0 = options.argv0,
|
||||
.environ = options.environ,
|
||||
.worker_threads = .init(null),
|
||||
.environ = .{ .block = options.environ.block },
|
||||
.robust_cancel = options.robust_cancel,
|
||||
};
|
||||
|
||||
if (posix.Sigaction != void) {
|
||||
|
||||
@@ -13,7 +13,10 @@ test "concurrent vs main prevents deadlock via oversubscription" {
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
var threaded: Io.Threaded = .init(std.testing.allocator, .{});
|
||||
var threaded: Io.Threaded = .init(std.testing.allocator, .{
|
||||
.argv0 = .empty,
|
||||
.environ = .empty,
|
||||
});
|
||||
defer threaded.deinit();
|
||||
const io = threaded.io();
|
||||
|
||||
@@ -46,7 +49,10 @@ test "concurrent vs concurrent prevents deadlock via oversubscription" {
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
var threaded: Io.Threaded = .init(std.testing.allocator, .{});
|
||||
var threaded: Io.Threaded = .init(std.testing.allocator, .{
|
||||
.argv0 = .empty,
|
||||
.environ = .empty,
|
||||
});
|
||||
defer threaded.deinit();
|
||||
const io = threaded.io();
|
||||
|
||||
@@ -80,7 +86,10 @@ test "async/concurrent context and result alignment" {
|
||||
var buffer: [2048]u8 align(@alignOf(ByteArray512)) = undefined;
|
||||
var fba: std.heap.FixedBufferAllocator = .init(&buffer);
|
||||
|
||||
var threaded: std.Io.Threaded = .init(fba.allocator(), .{});
|
||||
var threaded: std.Io.Threaded = .init(fba.allocator(), .{
|
||||
.argv0 = .empty,
|
||||
.environ = .empty,
|
||||
});
|
||||
defer threaded.deinit();
|
||||
const io = threaded.io();
|
||||
|
||||
@@ -113,7 +122,10 @@ test "Group.async context alignment" {
|
||||
var buffer: [2048]u8 align(@alignOf(ByteArray512)) = undefined;
|
||||
var fba: std.heap.FixedBufferAllocator = .init(&buffer);
|
||||
|
||||
var threaded: std.Io.Threaded = .init(fba.allocator(), .{});
|
||||
var threaded: std.Io.Threaded = .init(fba.allocator(), .{
|
||||
.argv0 = .empty,
|
||||
.environ = .empty,
|
||||
});
|
||||
defer threaded.deinit();
|
||||
const io = threaded.io();
|
||||
|
||||
@@ -133,7 +145,10 @@ fn returnArray() [32]u8 {
|
||||
}
|
||||
|
||||
test "async with array return type" {
|
||||
var threaded: std.Io.Threaded = .init(std.testing.allocator, .{});
|
||||
var threaded: std.Io.Threaded = .init(std.testing.allocator, .{
|
||||
.argv0 = .empty,
|
||||
.environ = .empty,
|
||||
});
|
||||
defer threaded.deinit();
|
||||
const io = threaded.io();
|
||||
|
||||
|
||||
@@ -19,6 +19,13 @@ const mem = std.mem;
|
||||
/// queried and heap-allocated at runtime.
|
||||
block: Block,
|
||||
|
||||
pub const empty: Environ = .{
|
||||
.block = switch (@TypeOf(Block)) {
|
||||
void => {},
|
||||
else => &.{},
|
||||
},
|
||||
};
|
||||
|
||||
pub const Block = switch (native_os) {
|
||||
.windows => [*:0]const u16,
|
||||
.wasi => switch (builtin.link_libc) {
|
||||
|
||||
+25
-18
@@ -186,36 +186,43 @@ pub fn main(init: std.process.Init.Minimal) anyerror!void {
|
||||
|
||||
if (args.len > 0) crash_report.zig_argv0 = args[0];
|
||||
|
||||
var env_map = init.environ.createMap(arena) catch |err| fatal("failed to parse environment: {t}", .{err});
|
||||
|
||||
if (tracy.enable_allocation) {
|
||||
var gpa_tracy = tracy.tracyAllocator(gpa);
|
||||
return mainArgs(gpa_tracy.allocator(), arena, args, &env_map);
|
||||
}
|
||||
|
||||
if (native_os == .wasi) {
|
||||
wasi_preopens = try fs.wasi.preopensAlloc(arena);
|
||||
}
|
||||
|
||||
return mainArgs(gpa, arena, args, &env_map);
|
||||
}
|
||||
|
||||
fn mainArgs(gpa: Allocator, arena: Allocator, args: []const [:0]const u8, env_map: *process.Environ.Map) !void {
|
||||
Compilation.setMainThread();
|
||||
|
||||
if (args.len <= 1) {
|
||||
std.log.info("{s}", .{usage});
|
||||
fatal("expected command argument", .{});
|
||||
}
|
||||
|
||||
var env_map = init.environ.createMap(arena) catch |err| fatal("failed to parse environment: {t}", .{err});
|
||||
|
||||
Compilation.setMainThread();
|
||||
|
||||
var threaded: Io.Threaded = .init(gpa, .{
|
||||
.argv0 = if (@hasField(Io.Threaded.Argv0, "value")) .{ .value = args[0] } else .{},
|
||||
.argv0 = .init(init.args),
|
||||
.environ = init.environ,
|
||||
});
|
||||
defer threaded.deinit();
|
||||
threaded_impl_ptr = &threaded;
|
||||
threaded.stack_size = thread_stack_size;
|
||||
const io = threaded.io();
|
||||
|
||||
if (tracy.enable_allocation) {
|
||||
var gpa_tracy = tracy.tracyAllocator(gpa);
|
||||
return mainArgs(gpa_tracy.allocator(), arena, io, args, &env_map);
|
||||
}
|
||||
|
||||
if (native_os == .wasi) {
|
||||
wasi_preopens = try fs.wasi.preopensAlloc(arena);
|
||||
}
|
||||
|
||||
return mainArgs(gpa, arena, io, args, &env_map);
|
||||
}
|
||||
|
||||
fn mainArgs(
|
||||
gpa: Allocator,
|
||||
arena: Allocator,
|
||||
io: Io,
|
||||
args: []const [:0]const u8,
|
||||
env_map: *process.Environ.Map,
|
||||
) !void {
|
||||
if (process.can_replace and EnvVar.ZIG_IS_DETECTING_LIBC_PATHS.isSet(env_map)) {
|
||||
dev.check(.cc_command);
|
||||
// In this case we have accidentally invoked ourselves as "the system C compiler"
|
||||
|
||||
Reference in New Issue
Block a user