thinking of chickening out

This commit is contained in:
Andrew Kelley
2025-02-14 13:26:04 -08:00
parent ffdacaac18
commit 5e51205119
4 changed files with 303 additions and 355 deletions

View File

@ -5650,3 +5650,43 @@ pub fn ProcessBaseAddress(handle: HANDLE) ProcessBaseAddressError!HMODULE {
const ppeb: *const PEB = @ptrCast(@alignCast(peb_out.ptr));
return ppeb.ImageBaseAddress;
}
/// Get an environment variable with a null-terminated, WTF-16 encoded name.
///
/// This function performs a Unicode-aware case-insensitive lookup using RtlEqualUnicodeString.
///
/// See also:
/// * `std.process.Init.Env.map`
/// * `std.process.Init.Env.getOwned`
/// * `std.process.Init.Env.hasConstant`
/// * `std.process.Init.Env.has`
pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 {
const key_slice = mem.sliceTo(key, 0);
const ptr = peb().ProcessParameters.Environment;
var i: usize = 0;
while (ptr[i] != 0) {
const key_start = i;
// There are some special environment variables that start with =,
// so we need a special case to not treat = as a key/value separator
// if it's the first character.
// https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
if (ptr[key_start] == '=') i += 1;
while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
const this_key = ptr[key_start..i];
if (ptr[i] == '=') i += 1;
const value_start = i;
while (ptr[i] != 0) : (i += 1) {}
const this_value = ptr[value_start..i :0];
if (eqlIgnoreCaseWTF16(key_slice, this_key)) {
return this_value;
}
i += 1; // skip over null byte
}
return null;
}

View File

@ -1985,54 +1985,8 @@ pub fn execvpeZ(
return execvpeZ_expandArg0(.no_expand, file, argv_ptr, envp);
}
/// Get an environment variable.
/// See also `getenvZ`.
pub fn getenv(key: []const u8) ?[:0]const u8 {
if (native_os == .windows) {
@compileError("std.posix.getenv is unavailable for Windows because environment strings are in WTF-16 format. See std.process.getEnvVarOwned for a cross-platform API or std.process.getenvW for a Windows-specific API.");
}
if (builtin.link_libc) {
var ptr = std.c.environ;
while (ptr[0]) |line| : (ptr += 1) {
var line_i: usize = 0;
while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
const this_key = line[0..line_i];
if (!mem.eql(u8, this_key, key)) continue;
return mem.sliceTo(line + line_i + 1, 0);
}
return null;
}
if (native_os == .wasi) {
@compileError("std.posix.getenv is unavailable for WASI. See std.process.getEnvMap or std.process.getEnvVarOwned for a cross-platform API.");
}
// The simplified start logic doesn't populate environ.
if (std.start.simplified_logic) return null;
// TODO see https://github.com/ziglang/zig/issues/4524
for (std.os.environ) |ptr| {
var line_i: usize = 0;
while (ptr[line_i] != 0 and ptr[line_i] != '=') : (line_i += 1) {}
const this_key = ptr[0..line_i];
if (!mem.eql(u8, key, this_key)) continue;
return mem.sliceTo(ptr + line_i + 1, 0);
}
return null;
}
/// Get an environment variable with a null-terminated name.
/// See also `getenv`.
pub fn getenvZ(key: [*:0]const u8) ?[:0]const u8 {
if (builtin.link_libc) {
const value = system.getenv(key) orelse return null;
return mem.sliceTo(value, 0);
}
if (native_os == .windows) {
@compileError("std.posix.getenvZ is unavailable for Windows because environment string is in WTF-16 format. See std.process.getEnvVarOwned for cross-platform API or std.process.getenvW for Windows-specific API.");
}
return getenv(mem.sliceTo(key, 0));
}
pub const getenv = @compileError("environment variables are passed as an argument to the main function");
pub const getenvZ = getenv;
pub const GetCwdError = error{
NameTooLong,

View File

@ -568,6 +568,267 @@ pub const Init = struct {
.freestanding, .other, .windows, .wasi => void,
else => [][*:0]u8,
};
/// On Windows, `key` must be valid UTF-8.
pub fn hasConstant(comptime key: []const u8) bool {
if (native_os == .windows) {
const key_w = comptime unicode.utf8ToUtf16LeStringLiteral(key);
return windows.getenvW(key_w) != null;
} else if (native_os == .wasi and !builtin.link_libc) {
@compileError("hasConstant is not supported for WASI without libc");
} else {
return posix.getenv(key) != null;
}
}
/// On Windows, `key` must be valid UTF-8.
pub fn hasNonEmptyConstant(comptime key: []const u8) bool {
if (native_os == .windows) {
const key_w = comptime unicode.utf8ToUtf16LeStringLiteral(key);
const value = windows.getenvW(key_w) orelse return false;
return value.len != 0;
} else if (native_os == .wasi and !builtin.link_libc) {
@compileError("hasNonEmptyEnvVarConstant is not supported for WASI without libc");
} else {
const value = posix.getenv(key) orelse return false;
return value.len != 0;
}
}
pub const ParseIntError = std.fmt.ParseIntError || error{EnvironmentVariableNotFound};
/// Parses an environment variable as an integer.
///
/// Since the key is comptime-known, no allocation is needed.
///
/// On Windows, `key` must be valid UTF-8.
pub fn parseInt(comptime key: []const u8, comptime I: type, base: u8) ParseIntError!I {
if (native_os == .windows) {
const key_w = comptime std.unicode.utf8ToUtf16LeStringLiteral(key);
const text = windows.getenvW(key_w) orelse return error.EnvironmentVariableNotFound;
return std.fmt.parseIntWithGenericCharacter(I, u16, text, base);
} else if (native_os == .wasi and !builtin.link_libc) {
@compileError("not supported for WASI without libc");
} else {
const text = posix.getenv(key) orelse return error.EnvironmentVariableNotFound;
return std.fmt.parseInt(I, text, base);
}
}
pub const HasError = error{
OutOfMemory,
/// On Windows, environment variable keys provided by the user must be valid WTF-8.
/// https://simonsapin.github.io/wtf-8/
InvalidWtf8,
};
/// On Windows, if `key` is not valid [WTF-8](https://simonsapin.github.io/wtf-8/),
/// then `error.InvalidWtf8` is returned.
pub fn has(allocator: Allocator, key: []const u8) HasError!bool {
if (native_os == .windows) {
var stack_alloc = std.heap.stackFallback(256 * @sizeOf(u16), allocator);
const stack_allocator = stack_alloc.get();
const key_w = try unicode.wtf8ToWtf16LeAllocZ(stack_allocator, key);
defer stack_allocator.free(key_w);
return windows.getenvW(key_w) != null;
} else if (native_os == .wasi and !builtin.link_libc) {
var m = map(allocator) catch return error.OutOfMemory;
defer m.deinit();
return m.getPtr(key) != null;
} else {
return posix.getenv(key) != null;
}
}
/// On Windows, if `key` is not valid [WTF-8](https://simonsapin.github.io/wtf-8/),
/// then `error.InvalidWtf8` is returned.
pub fn hasNonEmpty(allocator: Allocator, key: []const u8) HasError!bool {
if (native_os == .windows) {
var stack_alloc = std.heap.stackFallback(256 * @sizeOf(u16), allocator);
const stack_allocator = stack_alloc.get();
const key_w = try unicode.wtf8ToWtf16LeAllocZ(stack_allocator, key);
defer stack_allocator.free(key_w);
const value = windows.getenvW(key_w) orelse return false;
return value.len != 0;
} else if (native_os == .wasi and !builtin.link_libc) {
var m = map(allocator) catch return error.OutOfMemory;
defer m.deinit();
const value = m.getPtr(key) orelse return false;
return value.len != 0;
} else {
const value = posix.getenv(key) orelse return false;
return value.len != 0;
}
}
pub const MapError = error{
OutOfMemory,
/// WASI-only. `environ_sizes_get` or `environ_get`
/// failed for an unexpected reason.
Unexpected,
};
/// Returns a snapshot of the environment variables of the current process.
/// Any modifications to the resulting `EnvMap` will not be reflected
/// in the environment, and likewise, any future modifications to the
/// environment will not be reflected in the `EnvMap`.
/// Caller owns resulting `EnvMap` and should call its `deinit` fn when done.
pub fn map(allocator: Allocator) MapError!EnvMap {
var result = EnvMap.init(allocator);
errdefer result.deinit();
if (native_os == .windows) {
const ptr = windows.peb().ProcessParameters.Environment;
var i: usize = 0;
while (ptr[i] != 0) {
const key_start = i;
// There are some special environment variables that start with =,
// so we need a special case to not treat = as a key/value separator
// if it's the first character.
// https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
if (ptr[key_start] == '=') i += 1;
while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
const key_w = ptr[key_start..i];
const key = try unicode.wtf16LeToWtf8Alloc(allocator, key_w);
errdefer allocator.free(key);
if (ptr[i] == '=') i += 1;
const value_start = i;
while (ptr[i] != 0) : (i += 1) {}
const value_w = ptr[value_start..i];
const value = try unicode.wtf16LeToWtf8Alloc(allocator, value_w);
errdefer allocator.free(value);
i += 1; // skip over null byte
try result.putMove(key, value);
}
return result;
} else if (native_os == .wasi and !builtin.link_libc) {
var environ_count: usize = undefined;
var environ_buf_size: usize = undefined;
const environ_sizes_get_ret = std.os.wasi.environ_sizes_get(&environ_count, &environ_buf_size);
if (environ_sizes_get_ret != .SUCCESS) {
return posix.unexpectedErrno(environ_sizes_get_ret);
}
if (environ_count == 0) {
return result;
}
const environ = try allocator.alloc([*:0]u8, environ_count);
defer allocator.free(environ);
const environ_buf = try allocator.alloc(u8, environ_buf_size);
defer allocator.free(environ_buf);
const environ_get_ret = std.os.wasi.environ_get(environ.ptr, environ_buf.ptr);
if (environ_get_ret != .SUCCESS) {
return posix.unexpectedErrno(environ_get_ret);
}
for (environ) |env| {
const pair = mem.sliceTo(env, 0);
var parts = mem.splitScalar(u8, pair, '=');
const key = parts.first();
const value = parts.rest();
try result.put(key, value);
}
return result;
} else if (builtin.link_libc) {
var ptr = std.c.environ;
while (ptr[0]) |line| : (ptr += 1) {
var line_i: usize = 0;
while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
const key = line[0..line_i];
var end_i: usize = line_i;
while (line[end_i] != 0) : (end_i += 1) {}
const value = line[line_i + 1 .. end_i];
try result.put(key, value);
}
return result;
} else {
for (std.os.environ) |line| {
var line_i: usize = 0;
while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
const key = line[0..line_i];
var end_i: usize = line_i;
while (line[end_i] != 0) : (end_i += 1) {}
const value = line[line_i + 1 .. end_i];
try result.put(key, value);
}
return result;
}
}
test map {
var env = try map(testing.allocator);
defer env.deinit();
}
pub const GetOwnedError = error{
OutOfMemory,
EnvironmentVariableNotFound,
/// On Windows, environment variable keys provided by the user must be valid WTF-8.
/// https://simonsapin.github.io/wtf-8/
InvalidWtf8,
};
/// Caller must free returned memory.
/// On Windows, if `key` is not valid [WTF-8](https://simonsapin.github.io/wtf-8/),
/// then `error.InvalidWtf8` is returned.
/// On Windows, the value is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On other platforms, the value is an opaque sequence of bytes with no particular encoding.
pub fn getOwned(allocator: Allocator, key: []const u8) GetOwnedError![]u8 {
if (native_os == .windows) {
const result_w = blk: {
var stack_alloc = std.heap.stackFallback(256 * @sizeOf(u16), allocator);
const stack_allocator = stack_alloc.get();
const key_w = try unicode.wtf8ToWtf16LeAllocZ(stack_allocator, key);
defer stack_allocator.free(key_w);
break :blk windows.getenvW(key_w) orelse return error.EnvironmentVariableNotFound;
};
// wtf16LeToWtf8Alloc can only fail with OutOfMemory
return unicode.wtf16LeToWtf8Alloc(allocator, result_w);
} else if (native_os == .wasi and !builtin.link_libc) {
var m = map(allocator) catch return error.OutOfMemory;
defer m.deinit();
const val = m.get(key) orelse return error.EnvironmentVariableNotFound;
return allocator.dupe(u8, val);
} else {
const result = posix.getenv(key) orelse return error.EnvironmentVariableNotFound;
return allocator.dupe(u8, result);
}
}
test getOwned {
try testing.expectError(
error.EnvironmentVariableNotFound,
getOwned(std.testing.allocator, "BADENV"),
);
}
test hasConstant {
if (native_os == .wasi and !builtin.link_libc) return error.SkipZigTest;
try testing.expect(!hasConstant("BADENV"));
}
test has {
const has_env = try has(std.testing.allocator, "BADENV");
try testing.expect(!has_env);
}
};
pub const Aux = struct {
@ -833,310 +1094,6 @@ test EnvMap {
}
}
pub const GetEnvMapError = error{
OutOfMemory,
/// WASI-only. `environ_sizes_get` or `environ_get`
/// failed for an unexpected reason.
Unexpected,
};
/// Returns a snapshot of the environment variables of the current process.
/// Any modifications to the resulting EnvMap will not be reflected in the environment, and
/// likewise, any future modifications to the environment will not be reflected in the EnvMap.
/// Caller owns resulting `EnvMap` and should call its `deinit` fn when done.
pub fn getEnvMap(allocator: Allocator) GetEnvMapError!EnvMap {
var result = EnvMap.init(allocator);
errdefer result.deinit();
if (native_os == .windows) {
const ptr = windows.peb().ProcessParameters.Environment;
var i: usize = 0;
while (ptr[i] != 0) {
const key_start = i;
// There are some special environment variables that start with =,
// so we need a special case to not treat = as a key/value separator
// if it's the first character.
// https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
if (ptr[key_start] == '=') i += 1;
while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
const key_w = ptr[key_start..i];
const key = try unicode.wtf16LeToWtf8Alloc(allocator, key_w);
errdefer allocator.free(key);
if (ptr[i] == '=') i += 1;
const value_start = i;
while (ptr[i] != 0) : (i += 1) {}
const value_w = ptr[value_start..i];
const value = try unicode.wtf16LeToWtf8Alloc(allocator, value_w);
errdefer allocator.free(value);
i += 1; // skip over null byte
try result.putMove(key, value);
}
return result;
} else if (native_os == .wasi and !builtin.link_libc) {
var environ_count: usize = undefined;
var environ_buf_size: usize = undefined;
const environ_sizes_get_ret = std.os.wasi.environ_sizes_get(&environ_count, &environ_buf_size);
if (environ_sizes_get_ret != .SUCCESS) {
return posix.unexpectedErrno(environ_sizes_get_ret);
}
if (environ_count == 0) {
return result;
}
const environ = try allocator.alloc([*:0]u8, environ_count);
defer allocator.free(environ);
const environ_buf = try allocator.alloc(u8, environ_buf_size);
defer allocator.free(environ_buf);
const environ_get_ret = std.os.wasi.environ_get(environ.ptr, environ_buf.ptr);
if (environ_get_ret != .SUCCESS) {
return posix.unexpectedErrno(environ_get_ret);
}
for (environ) |env| {
const pair = mem.sliceTo(env, 0);
var parts = mem.splitScalar(u8, pair, '=');
const key = parts.first();
const value = parts.rest();
try result.put(key, value);
}
return result;
} else if (builtin.link_libc) {
var ptr = std.c.environ;
while (ptr[0]) |line| : (ptr += 1) {
var line_i: usize = 0;
while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
const key = line[0..line_i];
var end_i: usize = line_i;
while (line[end_i] != 0) : (end_i += 1) {}
const value = line[line_i + 1 .. end_i];
try result.put(key, value);
}
return result;
} else {
for (std.os.environ) |line| {
var line_i: usize = 0;
while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
const key = line[0..line_i];
var end_i: usize = line_i;
while (line[end_i] != 0) : (end_i += 1) {}
const value = line[line_i + 1 .. end_i];
try result.put(key, value);
}
return result;
}
}
test getEnvMap {
var env = try getEnvMap(testing.allocator);
defer env.deinit();
}
pub const GetEnvVarOwnedError = error{
OutOfMemory,
EnvironmentVariableNotFound,
/// On Windows, environment variable keys provided by the user must be valid WTF-8.
/// https://simonsapin.github.io/wtf-8/
InvalidWtf8,
};
/// Caller must free returned memory.
/// On Windows, if `key` is not valid [WTF-8](https://simonsapin.github.io/wtf-8/),
/// then `error.InvalidWtf8` is returned.
/// On Windows, the value is encoded as [WTF-8](https://simonsapin.github.io/wtf-8/).
/// On other platforms, the value is an opaque sequence of bytes with no particular encoding.
pub fn getEnvVarOwned(allocator: Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
if (native_os == .windows) {
const result_w = blk: {
var stack_alloc = std.heap.stackFallback(256 * @sizeOf(u16), allocator);
const stack_allocator = stack_alloc.get();
const key_w = try unicode.wtf8ToWtf16LeAllocZ(stack_allocator, key);
defer stack_allocator.free(key_w);
break :blk getenvW(key_w) orelse return error.EnvironmentVariableNotFound;
};
// wtf16LeToWtf8Alloc can only fail with OutOfMemory
return unicode.wtf16LeToWtf8Alloc(allocator, result_w);
} else if (native_os == .wasi and !builtin.link_libc) {
var envmap = getEnvMap(allocator) catch return error.OutOfMemory;
defer envmap.deinit();
const val = envmap.get(key) orelse return error.EnvironmentVariableNotFound;
return allocator.dupe(u8, val);
} else {
const result = posix.getenv(key) orelse return error.EnvironmentVariableNotFound;
return allocator.dupe(u8, result);
}
}
/// On Windows, `key` must be valid UTF-8.
pub fn hasEnvVarConstant(comptime key: []const u8) bool {
if (native_os == .windows) {
const key_w = comptime unicode.utf8ToUtf16LeStringLiteral(key);
return getenvW(key_w) != null;
} else if (native_os == .wasi and !builtin.link_libc) {
@compileError("hasEnvVarConstant is not supported for WASI without libc");
} else {
return posix.getenv(key) != null;
}
}
/// On Windows, `key` must be valid UTF-8.
pub fn hasNonEmptyEnvVarConstant(comptime key: []const u8) bool {
if (native_os == .windows) {
const key_w = comptime unicode.utf8ToUtf16LeStringLiteral(key);
const value = getenvW(key_w) orelse return false;
return value.len != 0;
} else if (native_os == .wasi and !builtin.link_libc) {
@compileError("hasNonEmptyEnvVarConstant is not supported for WASI without libc");
} else {
const value = posix.getenv(key) orelse return false;
return value.len != 0;
}
}
pub const ParseEnvVarIntError = std.fmt.ParseIntError || error{EnvironmentVariableNotFound};
/// Parses an environment variable as an integer.
///
/// Since the key is comptime-known, no allocation is needed.
///
/// On Windows, `key` must be valid UTF-8.
pub fn parseEnvVarInt(comptime key: []const u8, comptime I: type, base: u8) ParseEnvVarIntError!I {
if (native_os == .windows) {
const key_w = comptime std.unicode.utf8ToUtf16LeStringLiteral(key);
const text = getenvW(key_w) orelse return error.EnvironmentVariableNotFound;
return std.fmt.parseIntWithGenericCharacter(I, u16, text, base);
} else if (native_os == .wasi and !builtin.link_libc) {
@compileError("parseEnvVarInt is not supported for WASI without libc");
} else {
const text = posix.getenv(key) orelse return error.EnvironmentVariableNotFound;
return std.fmt.parseInt(I, text, base);
}
}
pub const HasEnvVarError = error{
OutOfMemory,
/// On Windows, environment variable keys provided by the user must be valid WTF-8.
/// https://simonsapin.github.io/wtf-8/
InvalidWtf8,
};
/// On Windows, if `key` is not valid [WTF-8](https://simonsapin.github.io/wtf-8/),
/// then `error.InvalidWtf8` is returned.
pub fn hasEnvVar(allocator: Allocator, key: []const u8) HasEnvVarError!bool {
if (native_os == .windows) {
var stack_alloc = std.heap.stackFallback(256 * @sizeOf(u16), allocator);
const stack_allocator = stack_alloc.get();
const key_w = try unicode.wtf8ToWtf16LeAllocZ(stack_allocator, key);
defer stack_allocator.free(key_w);
return getenvW(key_w) != null;
} else if (native_os == .wasi and !builtin.link_libc) {
var envmap = getEnvMap(allocator) catch return error.OutOfMemory;
defer envmap.deinit();
return envmap.getPtr(key) != null;
} else {
return posix.getenv(key) != null;
}
}
/// On Windows, if `key` is not valid [WTF-8](https://simonsapin.github.io/wtf-8/),
/// then `error.InvalidWtf8` is returned.
pub fn hasNonEmptyEnvVar(allocator: Allocator, key: []const u8) HasEnvVarError!bool {
if (native_os == .windows) {
var stack_alloc = std.heap.stackFallback(256 * @sizeOf(u16), allocator);
const stack_allocator = stack_alloc.get();
const key_w = try unicode.wtf8ToWtf16LeAllocZ(stack_allocator, key);
defer stack_allocator.free(key_w);
const value = getenvW(key_w) orelse return false;
return value.len != 0;
} else if (native_os == .wasi and !builtin.link_libc) {
var envmap = getEnvMap(allocator) catch return error.OutOfMemory;
defer envmap.deinit();
const value = envmap.getPtr(key) orelse return false;
return value.len != 0;
} else {
const value = posix.getenv(key) orelse return false;
return value.len != 0;
}
}
/// Windows-only. Get an environment variable with a null-terminated, WTF-16 encoded name.
///
/// This function performs a Unicode-aware case-insensitive lookup using RtlEqualUnicodeString.
///
/// See also:
/// * `std.posix.getenv`
/// * `getEnvMap`
/// * `getEnvVarOwned`
/// * `hasEnvVarConstant`
/// * `hasEnvVar`
pub fn getenvW(key: [*:0]const u16) ?[:0]const u16 {
if (native_os != .windows) {
@compileError("Windows-only");
}
const key_slice = mem.sliceTo(key, 0);
const ptr = windows.peb().ProcessParameters.Environment;
var i: usize = 0;
while (ptr[i] != 0) {
const key_start = i;
// There are some special environment variables that start with =,
// so we need a special case to not treat = as a key/value separator
// if it's the first character.
// https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
if (ptr[key_start] == '=') i += 1;
while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
const this_key = ptr[key_start..i];
if (ptr[i] == '=') i += 1;
const value_start = i;
while (ptr[i] != 0) : (i += 1) {}
const this_value = ptr[value_start..i :0];
if (windows.eqlIgnoreCaseWTF16(key_slice, this_key)) {
return this_value;
}
i += 1; // skip over null byte
}
return null;
}
test getEnvVarOwned {
try testing.expectError(
error.EnvironmentVariableNotFound,
getEnvVarOwned(std.testing.allocator, "BADENV"),
);
}
test hasEnvVarConstant {
if (native_os == .wasi and !builtin.link_libc) return error.SkipZigTest;
try testing.expect(!hasEnvVarConstant("BADENV"));
}
test hasEnvVar {
const has_env = try hasEnvVar(std.testing.allocator, "BADENV");
try testing.expect(!has_env);
}
pub const UserInfo = struct {
uid: posix.uid_t,
gid: posix.gid_t,

View File

@ -605,9 +605,6 @@ fn expandStackSize(phdrs: []elf.Phdr) void {
}
inline fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8, aux: std.process.Init.Aux) u8 {
std.os.argv = argv[0..argc]; // To be removed after 0.15.0 is tagged.
std.os.environ = envp; // To be removed after 0.15.0 is tagged.
std.debug.maybeEnableSegfaultHandler();
maybeIgnoreSigpipe();