authorgravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-03-17 17:53:12-07:00
committergravatar for squeek502@hotmail.comRyan Liptak <squeek502@hotmail.com> 2025-03-17 17:53:38-07:00
log423761bb6de68bec9482dbc3b3c21b2b5c74a2b9
tree62b4db263493430c1966e16851c020e558c832f5
parent2a4e06bcb30f71e83b14026bcbade6aac3aece84

createWindowsEnvBlock: Reduce NUL terminator count to only what's required

This code previously added 4 NUL code units, but that was likely due to a misinterpretation of this part of the CreateProcess documentation: > A Unicode environment block is terminated by four zero bytes: two for the last string, two more to terminate the block. (four zero *bytes* means *two* zero code units) Additionally, the second zero code unit is only actually needed when the environment is empty due to a quirk of the CreateProcess implementation. In the case of a non-empty environment, there always ends up being two trailing NUL code units since one will come after the last environment variable in the block.

1 files changed, 10 insertions(+), 7 deletions(-)

lib/std/process.zig+10-7
...@@ -2036,7 +2036,8 @@ test createNullDelimitedEnvMap {...@@ -2036,7 +2036,8 @@ test createNullDelimitedEnvMap {
2036pub fn createWindowsEnvBlock(allocator: mem.Allocator, env_map: *const EnvMap) ![]u16 {2036pub fn createWindowsEnvBlock(allocator: mem.Allocator, env_map: *const EnvMap) ![]u16 {
2037 // count bytes needed2037 // count bytes needed
2038 const max_chars_needed = x: {2038 const max_chars_needed = x: {
2039 var max_chars_needed: usize = 4; // 4 for the final 4 null bytes2039 // Only need 2 trailing NUL code units for an empty environment
2040 var max_chars_needed: usize = if (env_map.count() == 0) 2 else 1;
2040 var it = env_map.iterator();2041 var it = env_map.iterator();
2041 while (it.next()) |pair| {2042 while (it.next()) |pair| {
2042 // +1 for '='2043 // +1 for '='
...@@ -2060,12 +2061,14 @@ pub fn createWindowsEnvBlock(allocator: mem.Allocator, env_map: *const EnvMap) !...@@ -2060,12 +2061,14 @@ pub fn createWindowsEnvBlock(allocator: mem.Allocator, env_map: *const EnvMap) !
2060 }2061 }
2061 result[i] = 0;2062 result[i] = 0;
2062 i += 1;2063 i += 1;
2063 result[i] = 0;2064 // An empty environment is a special case that requires a redundant
2064 i += 1;2065 // NUL terminator. CreateProcess will read the second code unit even
2065 result[i] = 0;2066 // though theoretically the first should be enough to recognize that the
2066 i += 1;2067 // environment is empty (see https://nullprogram.com/blog/2023/08/23/)
2067 result[i] = 0;2068 if (env_map.count() == 0) {
2068 i += 1;2069 result[i] = 0;
2070 i += 1;
2071 }
2069 return try allocator.realloc(result, i);2072 return try allocator.realloc(result, i);
2070}2073}
20712074