@@ -821,7 +821,7 @@ pub const ChildProcess = struct {
821
821
fn spawnWindows (self : * ChildProcess ) SpawnError ! void {
822
822
const saAttr = windows.SECURITY_ATTRIBUTES {
823
823
.nLength = @sizeOf (windows .SECURITY_ATTRIBUTES ),
824
- .bInheritHandle = windows .TRUE ,
824
+ .bInheritHandle = windows .FALSE ,
825
825
.lpSecurityDescriptor = null ,
826
826
};
827
827
@@ -872,11 +872,24 @@ pub const ChildProcess = struct {
872
872
windowsDestroyPipe (g_hChildStd_IN_Rd , g_hChildStd_IN_Wr );
873
873
};
874
874
875
+ var tmp_hChildStd_Rd : windows.HANDLE = undefined ;
876
+ var tmp_hChildStd_Wr : windows.HANDLE = undefined ;
875
877
var g_hChildStd_OUT_Rd : ? windows.HANDLE = null ;
876
878
var g_hChildStd_OUT_Wr : ? windows.HANDLE = null ;
877
879
switch (self .stdout_behavior ) {
878
880
StdIo .Pipe = > {
879
- try windowsMakeAsyncPipe (& g_hChildStd_OUT_Rd , & g_hChildStd_OUT_Wr , & saAttr );
881
+ try windowsMakeAsyncPipe (
882
+ & tmp_hChildStd_Rd ,
883
+ & tmp_hChildStd_Wr ,
884
+ & saAttr ,
885
+ );
886
+ errdefer {
887
+ os .close (tmp_hChildStd_Rd );
888
+ os .close (tmp_hChildStd_Wr );
889
+ }
890
+ try windows .SetHandleInformation (tmp_hChildStd_Wr , windows .HANDLE_FLAG_INHERIT , 1 );
891
+ g_hChildStd_OUT_Rd = tmp_hChildStd_Rd ;
892
+ g_hChildStd_OUT_Wr = tmp_hChildStd_Wr ;
880
893
},
881
894
StdIo .Ignore = > {
882
895
g_hChildStd_OUT_Wr = nul_handle ;
@@ -896,7 +909,18 @@ pub const ChildProcess = struct {
896
909
var g_hChildStd_ERR_Wr : ? windows.HANDLE = null ;
897
910
switch (self .stderr_behavior ) {
898
911
StdIo .Pipe = > {
899
- try windowsMakeAsyncPipe (& g_hChildStd_ERR_Rd , & g_hChildStd_ERR_Wr , & saAttr );
912
+ try windowsMakeAsyncPipe (
913
+ & tmp_hChildStd_Rd ,
914
+ & tmp_hChildStd_Wr ,
915
+ & saAttr ,
916
+ );
917
+ errdefer {
918
+ os .close (tmp_hChildStd_Rd );
919
+ os .close (tmp_hChildStd_Wr );
920
+ }
921
+ try windows .SetHandleInformation (tmp_hChildStd_Wr , windows .HANDLE_FLAG_INHERIT , 1 );
922
+ g_hChildStd_ERR_Rd = tmp_hChildStd_Rd ;
923
+ g_hChildStd_ERR_Wr = tmp_hChildStd_Wr ;
900
924
},
901
925
StdIo .Ignore = > {
902
926
g_hChildStd_ERR_Wr = nul_handle ;
@@ -1094,6 +1118,28 @@ pub const ChildProcess = struct {
1094
1118
}
1095
1119
};
1096
1120
1121
+ /// Pipe read side
1122
+ pub const pipe_rd = 0 ;
1123
+ /// Pipe write side
1124
+ pub const pipe_wr = 1 ;
1125
+ const PortPipeT = if (builtin .os .tag == .windows ) [2 ]windows .HANDLE else [2 ]os .fd_t ;
1126
+
1127
+ /// Portable pipe creation with disabled inheritance
1128
+ pub inline fn portablePipe () ! PortPipeT {
1129
+ var pipe_new : PortPipeT = undefined ;
1130
+ if (builtin .os .tag == .windows ) {
1131
+ const saAttr = windows.SECURITY_ATTRIBUTES {
1132
+ .nLength = @sizeOf (windows .SECURITY_ATTRIBUTES ),
1133
+ .bInheritHandle = windows .FALSE ,
1134
+ .lpSecurityDescriptor = null ,
1135
+ };
1136
+ try windowsMakeAsyncPipe (& pipe_new [pipe_rd ], & pipe_new [pipe_wr ], & saAttr );
1137
+ } else {
1138
+ pipe_new = try os .pipe2 (@as (u32 , os .O .CLOEXEC ));
1139
+ }
1140
+ return pipe_new ;
1141
+ }
1142
+
1097
1143
/// Expects `app_buf` to contain exactly the app name, and `dir_buf` to contain exactly the dir path.
1098
1144
/// After return, `app_buf` will always contain exactly the app name and `dir_buf` will always contain exactly the dir path.
1099
1145
/// Note: `app_buf` should not contain any leading path separators.
@@ -1324,30 +1370,25 @@ fn windowsCreateProcessPathExt(
1324
1370
}
1325
1371
1326
1372
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 {
1327
- // TODO the docs for environment pointer say:
1328
- // > A pointer to the environment block for the new process. If this parameter
1329
- // > is NULL, the new process uses the environment of the calling process.
1330
- // > ...
1331
- // > An environment block can contain either Unicode or ANSI characters. If
1332
- // > the environment block pointed to by lpEnvironment contains Unicode
1333
- // > characters, be sure that dwCreationFlags includes CREATE_UNICODE_ENVIRONMENT.
1334
- // > If this parameter is NULL and the environment block of the parent process
1335
- // > contains Unicode characters, you must also ensure that dwCreationFlags
1336
- // > includes CREATE_UNICODE_ENVIRONMENT.
1337
- // This seems to imply that we have to somehow know whether our process parent passed
1338
- // CREATE_UNICODE_ENVIRONMENT if we want to pass NULL for the environment parameter.
1339
- // Since we do not know this information that would imply that we must not pass NULL
1340
- // for the parameter.
1341
- // However this would imply that programs compiled with -DUNICODE could not pass
1342
- // environment variables to programs that were not, which seems unlikely.
1343
- // More investigation is needed.
1373
+ // See https://stackoverflow.com/a/4207169/9306292
1374
+ // One can manually write in unicode even if one doesn't compile in unicode
1375
+ // (-DUNICODE).
1376
+ // Thus CREATE_UNICODE_ENVIRONMENT, according to how one constructed the
1377
+ // environment block, is necessary, since CreateProcessA and CreateProcessW may
1378
+ // work with either Ansi or Unicode.
1379
+ // * The environment variables can still be inherited from parent process,
1380
+ // if set to NULL
1381
+ // * The OS can for an unspecified environment block not figure out,
1382
+ // if it is Unicode or ANSI.
1383
+ // * Applications may break without specification of the environment variable
1384
+ // due to inability of Windows to check (+translate) the character encodings.
1344
1385
return windows .CreateProcessW (
1345
1386
app_name ,
1346
1387
cmd_line ,
1347
1388
null ,
1348
1389
null ,
1349
1390
windows .TRUE ,
1350
- windows .CREATE_UNICODE_ENVIRONMENT ,
1391
+ @enumToInt ( windows .PROCESS_CREATION_FLAGS . CREATE_UNICODE_ENVIRONMENT ) ,
1351
1392
@ptrCast (? * anyopaque , envp_ptr ),
1352
1393
cwd_ptr ,
1353
1394
lpStartupInfo ,
@@ -1464,14 +1505,22 @@ fn windowsMakePipeIn(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *const w
1464
1505
var wr_h : windows.HANDLE = undefined ;
1465
1506
try windows .CreatePipe (& rd_h , & wr_h , sattr );
1466
1507
errdefer windowsDestroyPipe (rd_h , wr_h );
1467
- try windows .SetHandleInformation (wr_h , windows .HANDLE_FLAG_INHERIT , 0 );
1508
+ try windows .SetHandleInformation (rd_h , windows .HANDLE_FLAG_INHERIT , 1 );
1468
1509
rd .* = rd_h ;
1469
1510
wr .* = wr_h ;
1470
1511
}
1471
1512
1472
1513
var pipe_name_counter = std .atomic .Atomic (u32 ).init (1 );
1473
1514
1474
- fn windowsMakeAsyncPipe (rd : * ? windows.HANDLE , wr : * ? windows.HANDLE , sattr : * const windows.SECURITY_ATTRIBUTES ) ! void {
1515
+ /// To enable/disable inheritance parent and child process, use
1516
+ /// os.enableInheritance() and os.disableInheritance() on the handle.
1517
+ /// convention: sattr uses bInheritHandle = windows.FALSE and only used pipe end
1518
+ /// is enabled.
1519
+ pub fn windowsMakeAsyncPipe (
1520
+ rd : * windows.HANDLE ,
1521
+ wr : * windows.HANDLE ,
1522
+ sattr : * const windows.SECURITY_ATTRIBUTES ,
1523
+ ) ! void {
1475
1524
var tmp_bufw : [128 ]u16 = undefined ;
1476
1525
1477
1526
// Anonymous pipes are built upon Named pipes.
@@ -1524,9 +1573,6 @@ fn windowsMakeAsyncPipe(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *cons
1524
1573
else = > | err | return windows .unexpectedError (err ),
1525
1574
}
1526
1575
}
1527
- errdefer os .close (write_handle );
1528
-
1529
- try windows .SetHandleInformation (read_handle , windows .HANDLE_FLAG_INHERIT , 0 );
1530
1576
1531
1577
rd .* = read_handle ;
1532
1578
wr .* = write_handle ;
0 commit comments