@@ -365,6 +365,26 @@ fn waitForPidStatus(pid: PopenPid) c_int {
365365 }
366366}
367367
368+ fn drainWindowsPipeStream (stream : * c.FILE ) void {
369+ if (comptime builtin .os .tag != .windows ) return ;
370+ const fd = fileno (stream );
371+ if (fd < 0 ) return ;
372+ const status_flags = winfd .getStatusFlags (fd ) orelse return ;
373+ if ((status_flags & 0x3 ) != c .O_RDONLY ) return ;
374+
375+ var buf : [256 ]u8 = undefined ;
376+ while (true ) {
377+ var amt_read : u32 = 0 ;
378+ if (std .os .windows .kernel32 .ReadFile (stream .fd .? , & buf , buf .len , & amt_read , null ) == 0 ) {
379+ switch (std .os .windows .kernel32 .GetLastError ()) {
380+ .BROKEN_PIPE , .HANDLE_EOF = > break ,
381+ else = > break ,
382+ }
383+ }
384+ if (amt_read == 0 ) break ;
385+ }
386+ }
387+
368388fn populateLinuxExecEnviron (buf : []u8 , ptrs : [* :null ]? [* :0 ]u8 , ptr_cap : usize ) bool {
369389 if (comptime builtin .os .tag != .linux ) return false ;
370390 var file = std .fs .openFileAbsolute ("/proc/self/environ" , .{}) catch return false ;
@@ -1138,6 +1158,13 @@ export fn pclose(stream: *c.FILE) callconv(.c) c_int {
11381158 c .errno = c .EINVAL ;
11391159 return -1 ;
11401160 };
1161+ if (builtin .os .tag == .windows ) {
1162+ // Native Windows shells can surface a broken-pipe exit status if the
1163+ // parent closes the read end before draining the child's final writes.
1164+ // Drain any unread pipe data first so `_pclose`-style callers get the
1165+ // child exit code rather than an artifact of our teardown ordering.
1166+ drainWindowsPipeStream (stream );
1167+ }
11411168 const close_rc = c .fclose (stream );
11421169 const wait_rc = waitForPidStatus (pid );
11431170 if (wait_rc == -1 ) return -1 ;
0 commit comments