@@ -640,7 +640,7 @@ pub const ChildProcess = struct {
640
640
fn spawnWindows (self : * ChildProcess ) SpawnError ! void {
641
641
const saAttr = windows.SECURITY_ATTRIBUTES {
642
642
.nLength = @sizeOf (windows .SECURITY_ATTRIBUTES ),
643
- .bInheritHandle = windows .TRUE ,
643
+ .bInheritHandle = windows .FALSE ,
644
644
.lpSecurityDescriptor = null ,
645
645
};
646
646
@@ -691,11 +691,24 @@ pub const ChildProcess = struct {
691
691
windowsDestroyPipe (g_hChildStd_IN_Rd , g_hChildStd_IN_Wr );
692
692
};
693
693
694
+ var tmp_hChildStd_Rd : windows.HANDLE = undefined ;
695
+ var tmp_hChildStd_Wr : windows.HANDLE = undefined ;
694
696
var g_hChildStd_OUT_Rd : ? windows.HANDLE = null ;
695
697
var g_hChildStd_OUT_Wr : ? windows.HANDLE = null ;
696
698
switch (self .stdout_behavior ) {
697
699
StdIo .Pipe = > {
698
- try windowsMakeAsyncPipe (& g_hChildStd_OUT_Rd , & g_hChildStd_OUT_Wr , & saAttr );
700
+ try windowsMakeAsyncPipe (
701
+ & tmp_hChildStd_Rd ,
702
+ & tmp_hChildStd_Wr ,
703
+ & saAttr ,
704
+ );
705
+ errdefer {
706
+ os .close (tmp_hChildStd_Rd );
707
+ os .close (tmp_hChildStd_Wr );
708
+ }
709
+ try windows .SetHandleInformation (tmp_hChildStd_Wr , windows .HANDLE_FLAG_INHERIT , 1 );
710
+ g_hChildStd_OUT_Rd = tmp_hChildStd_Rd ;
711
+ g_hChildStd_OUT_Wr = tmp_hChildStd_Wr ;
699
712
},
700
713
StdIo .Ignore = > {
701
714
g_hChildStd_OUT_Wr = nul_handle ;
@@ -715,7 +728,18 @@ pub const ChildProcess = struct {
715
728
var g_hChildStd_ERR_Wr : ? windows.HANDLE = null ;
716
729
switch (self .stderr_behavior ) {
717
730
StdIo .Pipe = > {
718
- try windowsMakeAsyncPipe (& g_hChildStd_ERR_Rd , & g_hChildStd_ERR_Wr , & saAttr );
731
+ try windowsMakeAsyncPipe (
732
+ & tmp_hChildStd_Rd ,
733
+ & tmp_hChildStd_Wr ,
734
+ & saAttr ,
735
+ );
736
+ errdefer {
737
+ os .close (tmp_hChildStd_Rd );
738
+ os .close (tmp_hChildStd_Wr );
739
+ }
740
+ try windows .SetHandleInformation (tmp_hChildStd_Wr , windows .HANDLE_FLAG_INHERIT , 1 );
741
+ g_hChildStd_ERR_Rd = tmp_hChildStd_Rd ;
742
+ g_hChildStd_ERR_Wr = tmp_hChildStd_Wr ;
719
743
},
720
744
StdIo .Ignore = > {
721
745
g_hChildStd_ERR_Wr = nul_handle ;
@@ -913,6 +937,28 @@ pub const ChildProcess = struct {
913
937
}
914
938
};
915
939
940
+ /// Pipe read side
941
+ pub const pipe_rd = 0 ;
942
+ /// Pipe write side
943
+ pub const pipe_wr = 1 ;
944
+ const PortPipeT = if (builtin .os .tag == .windows ) [2 ]windows .HANDLE else [2 ]os .fd_t ;
945
+
946
+ /// Portable pipe creation with disabled inheritance
947
+ pub inline fn portablePipe () ! PortPipeT {
948
+ var pipe_new : PortPipeT = undefined ;
949
+ if (builtin .os .tag == .windows ) {
950
+ const saAttr = windows.SECURITY_ATTRIBUTES {
951
+ .nLength = @sizeOf (windows .SECURITY_ATTRIBUTES ),
952
+ .bInheritHandle = windows .FALSE ,
953
+ .lpSecurityDescriptor = null ,
954
+ };
955
+ try windowsMakeAsyncPipe (& pipe_new [pipe_rd ], & pipe_new [pipe_wr ], & saAttr );
956
+ } else {
957
+ pipe_new = try os .pipe2 (@as (u32 , os .O .CLOEXEC ));
958
+ }
959
+ return pipe_new ;
960
+ }
961
+
916
962
/// Expects `app_buf` to contain exactly the app name, and `dir_buf` to contain exactly the dir path.
917
963
/// After return, `app_buf` will always contain exactly the app name and `dir_buf` will always contain exactly the dir path.
918
964
/// Note: `app_buf` should not contain any leading path separators.
@@ -1143,30 +1189,25 @@ fn windowsCreateProcessPathExt(
1143
1189
}
1144
1190
1145
1191
fn windowsCreateProcess (app_name : [* :0 ]u16 , cmd_line : [* :0 ]u16 , envp_ptr : ? [* ]u16 , cwd_ptr : ? [* :0 ]u16 , lpStartupInfo : * windows.STARTUPINFOW , lpProcessInformation : * windows.PROCESS_INFORMATION ) ! void {
1146
- // TODO the docs for environment pointer say:
1147
- // > A pointer to the environment block for the new process. If this parameter
1148
- // > is NULL, the new process uses the environment of the calling process.
1149
- // > ...
1150
- // > An environment block can contain either Unicode or ANSI characters. If
1151
- // > the environment block pointed to by lpEnvironment contains Unicode
1152
- // > characters, be sure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT.
1153
- // > If this parameter is NULL and the environment block of the parent process
1154
- // > contains Unicode characters, you must also ensure that dwCreationFlags
1155
- // > includes CREATE_UNICODE_ENVIRONMENT.
1156
- // This seems to imply that we have to somehow know whether our process parent passed
1157
- // CREATE_UNICODE_ENVIRONMENT if we want to pass NULL for the environment parameter.
1158
- // Since we do not know this information that would imply that we must not pass NULL
1159
- // for the parameter.
1160
- // However this would imply that programs compiled with -DUNICODE could not pass
1161
- // environment variables to programs that were not, which seems unlikely.
1162
- // More investigation is needed.
1192
+ // See https://stackoverflow.com/a/4207169/9306292
1193
+ // One can manually write in unicode even if one doesn't compile in unicode
1194
+ // (-DUNICODE).
1195
+ // Thus CREATE_UNICODE_ENVIRONMENT, according to how one constructed the
1196
+ // environment block, is necessary, since CreateProcessA and CreateProcessW may
1197
+ // work with either Ansi or Unicode.
1198
+ // * The environment variables can still be inherited from parent process,
1199
+ // if set to NULL
1200
+ // * The OS can for an unspecified environment block not figure out,
1201
+ // if it is Unicode or ANSI.
1202
+ // * Applications may break without specification of the environment variable
1203
+ // due to inability of Windows to check (+translate) the character encodings.
1163
1204
return windows .CreateProcessW (
1164
1205
app_name ,
1165
1206
cmd_line ,
1166
1207
null ,
1167
1208
null ,
1168
1209
windows .TRUE ,
1169
- windows .CREATE_UNICODE_ENVIRONMENT ,
1210
+ @enumToInt ( windows .PROCESS_CREATION_FLAGS . CREATE_UNICODE_ENVIRONMENT ) ,
1170
1211
@ptrCast (? * anyopaque , envp_ptr ),
1171
1212
cwd_ptr ,
1172
1213
lpStartupInfo ,
@@ -1283,14 +1324,22 @@ fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const w
1283
1324
var wr_h : windows.HANDLE = undefined ;
1284
1325
try windows .CreatePipe (& rd_h , & wr_h , sattr );
1285
1326
errdefer windowsDestroyPipe (rd_h , wr_h );
1286
- try windows .SetHandleInformation (wr_h , windows .HANDLE_FLAG_INHERIT , 0 );
1327
+ try windows .SetHandleInformation (rd_h , windows .HANDLE_FLAG_INHERIT , 1 );
1287
1328
rd .* = rd_h ;
1288
1329
wr .* = wr_h ;
1289
1330
}
1290
1331
1291
1332
var pipe_name_counter = std .atomic .Atomic (u32 ).init (1 );
1292
1333
1293
- fn windowsMakeAsyncPipe (rd : * ? windows.HANDLE , wr : * ? windows.HANDLE , sattr : * const windows.SECURITY_ATTRIBUTES ) ! void {
1334
+ /// To enable/disable inheritance parent and child process, use
1335
+ /// os.enableInheritance() and os.disableInheritance() on the handle.
1336
+ /// convention: sattr uses bInheritHandle = windows.FALSE and only used pipe end
1337
+ /// is enabled.
1338
+ pub fn windowsMakeAsyncPipe (
1339
+ rd : * windows.HANDLE ,
1340
+ wr : * windows.HANDLE ,
1341
+ sattr : * const windows.SECURITY_ATTRIBUTES ,
1342
+ ) ! void {
1294
1343
var tmp_bufw : [128 ]u16 = undefined ;
1295
1344
1296
1345
// Anonymous pipes are built upon Named pipes.
@@ -1343,9 +1392,6 @@ fn windowsMakeAsyncPipe(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *cons
1343
1392
else = > | err | return windows .unexpectedError (err ),
1344
1393
}
1345
1394
}
1346
- errdefer os .close (write_handle );
1347
-
1348
- try windows .SetHandleInformation (read_handle , windows .HANDLE_FLAG_INHERIT , 0 );
1349
1395
1350
1396
rd .* = read_handle ;
1351
1397
wr .* = write_handle ;
0 commit comments