@@ -830,7 +830,7 @@ pub const ChildProcess = struct {
830
830
fn spawnWindows (self : * ChildProcess ) SpawnError ! void {
831
831
const saAttr = windows.SECURITY_ATTRIBUTES {
832
832
.nLength = @sizeOf (windows .SECURITY_ATTRIBUTES ),
833
- .bInheritHandle = windows .TRUE ,
833
+ .bInheritHandle = windows .FALSE ,
834
834
.lpSecurityDescriptor = null ,
835
835
};
836
836
@@ -881,11 +881,24 @@ pub const ChildProcess = struct {
881
881
windowsDestroyPipe (g_hChildStd_IN_Rd , g_hChildStd_IN_Wr );
882
882
};
883
883
884
+ var tmp_hChildStd_Rd : windows.HANDLE = undefined ;
885
+ var tmp_hChildStd_Wr : windows.HANDLE = undefined ;
884
886
var g_hChildStd_OUT_Rd : ? windows.HANDLE = null ;
885
887
var g_hChildStd_OUT_Wr : ? windows.HANDLE = null ;
886
888
switch (self .stdout_behavior ) {
887
889
StdIo .Pipe = > {
888
- try windowsMakeAsyncPipe (& g_hChildStd_OUT_Rd , & g_hChildStd_OUT_Wr , & saAttr );
890
+ try windowsMakeAsyncPipe (
891
+ & tmp_hChildStd_Rd ,
892
+ & tmp_hChildStd_Wr ,
893
+ & saAttr ,
894
+ );
895
+ errdefer {
896
+ os .close (tmp_hChildStd_Rd );
897
+ os .close (tmp_hChildStd_Wr );
898
+ }
899
+ try windows .SetHandleInformation (tmp_hChildStd_Wr , windows .HANDLE_FLAG_INHERIT , 1 );
900
+ g_hChildStd_OUT_Rd = tmp_hChildStd_Rd ;
901
+ g_hChildStd_OUT_Wr = tmp_hChildStd_Wr ;
889
902
},
890
903
StdIo .Ignore = > {
891
904
g_hChildStd_OUT_Wr = nul_handle ;
@@ -905,7 +918,18 @@ pub const ChildProcess = struct {
905
918
var g_hChildStd_ERR_Wr : ? windows.HANDLE = null ;
906
919
switch (self .stderr_behavior ) {
907
920
StdIo .Pipe = > {
908
- try windowsMakeAsyncPipe (& g_hChildStd_ERR_Rd , & g_hChildStd_ERR_Wr , & saAttr );
921
+ try windowsMakeAsyncPipe (
922
+ & tmp_hChildStd_Rd ,
923
+ & tmp_hChildStd_Wr ,
924
+ & saAttr ,
925
+ );
926
+ errdefer {
927
+ os .close (tmp_hChildStd_Rd );
928
+ os .close (tmp_hChildStd_Wr );
929
+ }
930
+ try windows .SetHandleInformation (tmp_hChildStd_Wr , windows .HANDLE_FLAG_INHERIT , 1 );
931
+ g_hChildStd_ERR_Rd = tmp_hChildStd_Rd ;
932
+ g_hChildStd_ERR_Wr = tmp_hChildStd_Wr ;
909
933
},
910
934
StdIo .Ignore = > {
911
935
g_hChildStd_ERR_Wr = nul_handle ;
@@ -1103,6 +1127,28 @@ pub const ChildProcess = struct {
1103
1127
}
1104
1128
};
1105
1129
1130
+ /// Pipe read side
1131
+ pub const pipe_rd = 0 ;
1132
+ /// Pipe write side
1133
+ pub const pipe_wr = 1 ;
1134
+ const PortPipeT = if (builtin .os .tag == .windows ) [2 ]windows .HANDLE else [2 ]os .fd_t ;
1135
+
1136
+ /// Portable pipe creation with disabled inheritance
1137
+ pub inline fn portablePipe () ! PortPipeT {
1138
+ var pipe_new : PortPipeT = undefined ;
1139
+ if (builtin .os .tag == .windows ) {
1140
+ const saAttr = windows.SECURITY_ATTRIBUTES {
1141
+ .nLength = @sizeOf (windows .SECURITY_ATTRIBUTES ),
1142
+ .bInheritHandle = windows .FALSE ,
1143
+ .lpSecurityDescriptor = null ,
1144
+ };
1145
+ try windowsMakeAsyncPipe (& pipe_new [pipe_rd ], & pipe_new [pipe_wr ], & saAttr );
1146
+ } else {
1147
+ pipe_new = try os .pipe2 (@as (u32 , os .O .CLOEXEC ));
1148
+ }
1149
+ return pipe_new ;
1150
+ }
1151
+
1106
1152
/// Expects `app_buf` to contain exactly the app name, and `dir_buf` to contain exactly the dir path.
1107
1153
/// After return, `app_buf` will always contain exactly the app name and `dir_buf` will always contain exactly the dir path.
1108
1154
/// Note: `app_buf` should not contain any leading path separators.
@@ -1333,30 +1379,25 @@ fn windowsCreateProcessPathExt(
1333
1379
}
1334
1380
1335
1381
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 {
1336
- // TODO the docs for environment pointer say:
1337
- // > A pointer to the environment block for the new process. If this parameter
1338
- // > is NULL, the new process uses the environment of the calling process.
1339
- // > ...
1340
- // > An environment block can contain either Unicode or ANSI characters. If
1341
- // > the environment block pointed to by lpEnvironment contains Unicode
1342
- // > characters, be sure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT.
1343
- // > If this parameter is NULL and the environment block of the parent process
1344
- // > contains Unicode characters, you must also ensure that dwCreationFlags
1345
- // > includes CREATE_UNICODE_ENVIRONMENT.
1346
- // This seems to imply that we have to somehow know whether our process parent passed
1347
- // CREATE_UNICODE_ENVIRONMENT if we want to pass NULL for the environment parameter.
1348
- // Since we do not know this information that would imply that we must not pass NULL
1349
- // for the parameter.
1350
- // However this would imply that programs compiled with -DUNICODE could not pass
1351
- // environment variables to programs that were not, which seems unlikely.
1352
- // More investigation is needed.
1382
+ // See https://stackoverflow.com/a/4207169/9306292
1383
+ // One can manually write in unicode even if one doesn't compile in unicode
1384
+ // (-DUNICODE).
1385
+ // Thus CREATE_UNICODE_ENVIRONMENT, according to how one constructed the
1386
+ // environment block, is necessary, since CreateProcessA and CreateProcessW may
1387
+ // work with either Ansi or Unicode.
1388
+ // * The environment variables can still be inherited from parent process,
1389
+ // if set to NULL
1390
+ // * The OS can for an unspecified environment block not figure out,
1391
+ // if it is Unicode or ANSI.
1392
+ // * Applications may break without specification of the environment variable
1393
+ // due to inability of Windows to check (+translate) the character encodings.
1353
1394
return windows .CreateProcessW (
1354
1395
app_name ,
1355
1396
cmd_line ,
1356
1397
null ,
1357
1398
null ,
1358
1399
windows .TRUE ,
1359
- windows .CREATE_UNICODE_ENVIRONMENT ,
1400
+ @enumToInt ( windows .PROCESS_CREATION_FLAGS . CREATE_UNICODE_ENVIRONMENT ) ,
1360
1401
@ptrCast (? * anyopaque , envp_ptr ),
1361
1402
cwd_ptr ,
1362
1403
lpStartupInfo ,
@@ -1473,14 +1514,22 @@ fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const w
1473
1514
var wr_h : windows.HANDLE = undefined ;
1474
1515
try windows .CreatePipe (& rd_h , & wr_h , sattr );
1475
1516
errdefer windowsDestroyPipe (rd_h , wr_h );
1476
- try windows .SetHandleInformation (wr_h , windows .HANDLE_FLAG_INHERIT , 0 );
1517
+ try windows .SetHandleInformation (rd_h , windows .HANDLE_FLAG_INHERIT , 1 );
1477
1518
rd .* = rd_h ;
1478
1519
wr .* = wr_h ;
1479
1520
}
1480
1521
1481
1522
var pipe_name_counter = std .atomic .Atomic (u32 ).init (1 );
1482
1523
1483
- fn windowsMakeAsyncPipe (rd : * ? windows.HANDLE , wr : * ? windows.HANDLE , sattr : * const windows.SECURITY_ATTRIBUTES ) ! void {
1524
+ /// To enable/disable inheritance parent and child process, use
1525
+ /// os.enableInheritance() and os.disableInheritance() on the handle.
1526
+ /// convention: sattr uses bInheritHandle = windows.FALSE and only used pipe end
1527
+ /// is enabled.
1528
+ pub fn windowsMakeAsyncPipe (
1529
+ rd : * windows.HANDLE ,
1530
+ wr : * windows.HANDLE ,
1531
+ sattr : * const windows.SECURITY_ATTRIBUTES ,
1532
+ ) ! void {
1484
1533
var tmp_bufw : [128 ]u16 = undefined ;
1485
1534
1486
1535
// Anonymous pipes are built upon Named pipes.
@@ -1533,9 +1582,6 @@ fn windowsMakeAsyncPipe(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *cons
1533
1582
else = > | err | return windows .unexpectedError (err ),
1534
1583
}
1535
1584
}
1536
- errdefer os .close (write_handle );
1537
-
1538
- try windows .SetHandleInformation (read_handle , windows .HANDLE_FLAG_INHERIT , 0 );
1539
1585
1540
1586
rd .* = read_handle ;
1541
1587
wr .* = write_handle ;
0 commit comments