Skip to content

Commit 6187600

Browse files
committed
GNATCOLL.OS.Process: Ensure Stderr is not closed in child process
Part of V316-026 Change-Id: I3d6a09974547f10665151e381bea61952aaf9755
1 parent b683099 commit 6187600

File tree

3 files changed

+90
-30
lines changed

3 files changed

+90
-30
lines changed

src/os/gnatcoll-os-process-internal_spawn__unix.adb

Lines changed: 61 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
------------------------------------------------------------------------------
22
-- G N A T C O L L --
33
-- --
4-
-- Copyright (C) 2021, AdaCore --
4+
-- Copyright (C) 2021-2022, AdaCore --
55
-- --
66
-- This library is free software; you can redistribute it and/or modify it --
77
-- under terms of the GNU General Public License as published by the Free --
@@ -45,50 +45,81 @@ is
4545
use type FS.File_Descriptor;
4646
use type System.Address;
4747
use type Interfaces.C.size_t;
48-
Pid : Process_Id := 0;
49-
Posix_Prio : GNATCOLL.OS.Libc.Priority;
50-
FA : constant File_Actions := Init;
51-
C_Cwd : Static_String_Builder (Cwd'Length + 1);
52-
Old_Cwd : aliased Static_String_Builder (4096 + 1);
53-
Status : Integer with Unreferenced;
54-
C_Status : Libc_Status;
55-
Spawn_Status : Integer;
48+
Pid : Process_Id := 0;
49+
Posix_Prio : GNATCOLL.OS.Libc.Priority;
50+
FA : constant File_Actions := Init;
51+
C_Cwd : Static_String_Builder (Cwd'Length + 1);
52+
Old_Cwd : aliased Static_String_Builder (4096 + 1);
53+
Status : Integer with Unreferenced;
54+
C_Status : Libc_Status;
55+
Spawn_Status : Integer;
56+
57+
-- FD to close after dup2 calls. It's important to call the close
58+
-- otherwise some pipe might not be closed leading to hanging processes.
59+
60+
FD_To_Close : array (1 .. 3) of FS.File_Descriptor :=
61+
(others => FS.Invalid_FD);
62+
63+
procedure Add_Potential_Close (FD : FS.File_Descriptor);
64+
pragma Inline (Add_Potential_Close);
65+
-- If necessary add a FD to the list of fd to close after the calls to
66+
-- dup2.
67+
68+
-------------------------
69+
-- Add_Potential_Close --
70+
-------------------------
71+
72+
procedure Add_Potential_Close (FD : FS.File_Descriptor) is
73+
begin
74+
if FD = FS.Standin
75+
or else FD = FS.Standout
76+
or else FD = FS.Standerr
77+
then
78+
-- Never close standard descriptors
79+
return;
80+
end if;
81+
82+
for Index in FD_To_Close'Range loop
83+
if FD = FD_To_Close (Index) then
84+
return;
85+
elsif FD_To_Close (Index) = FS.Invalid_FD then
86+
FD_To_Close (Index) := FD;
87+
return;
88+
end if;
89+
end loop;
90+
end Add_Potential_Close;
91+
5692
begin
57-
-- Create file descriptors
93+
-- Internal_Spawn assume we have valid file descriptors passed as input
94+
-- (see gnatcoll-os-process.adb). Stdin, Stdout, Stderr cannot be
95+
-- Invalid_FD, To_Stdout or Null_FD (special values have been resolved
96+
-- by the caller). Nevertheless Stdin, Stdout and Stderr values might not
97+
-- all be distincts.
5898

5999
-- ??? Should we ignore the contents of Status below?
100+
60101
-- First issue dup2 directives
61102
if Stdin /= FS.Standin then
62103
Status := Add_Dup2 (FA, Stdin, FS.Standin);
104+
Add_Potential_Close (Stdin);
63105
end if;
64106

65107
if Stdout /= FS.Standout then
66108
Status := Add_Dup2 (FA, Stdout, FS.Standout);
109+
Add_Potential_Close (Stdout);
67110
end if;
68111

69112
if Stderr /= FS.Standerr then
70-
if Stderr = FS.To_Stdout then
71-
Status := Add_Dup2 (FA, Stdout, FS.Standerr);
72-
else
73-
Status := Add_Dup2 (FA, Stderr, FS.Standerr);
74-
end if;
75-
end if;
76-
77-
-- Then the close ones
78-
if Stdin /= FS.Standin then
79-
Status := Add_Close (FA, Stdin);
113+
Status := Add_Dup2 (FA, Stderr, FS.Standerr);
114+
Add_Potential_Close (Stderr);
80115
end if;
81116

82-
if Stdout /= FS.Standout and then Stdout /= FS.Standin then
83-
Status := Add_Close (FA, Stdout);
84-
end if;
85-
86-
if Stderr /= FS.Standout
87-
and then Stderr /= FS.Standout
88-
and then Stderr /= FS.Standin
89-
then
90-
Status := Add_Close (FA, Stderr);
91-
end if;
117+
-- Then the close directives
118+
for Index in FD_To_Close'Range loop
119+
if FD_To_Close (Index) /= FS.Invalid_FD then
120+
Status := Add_Close (FA, FD_To_Close (Index));
121+
end if;
122+
end loop;
92123

93124
-- Compute final priority
94125
case Priority is
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
with GNATCOLL.OS.Process;
2+
with Test_Assert;
3+
with Test_Python;
4+
with GNAT.IO;
5+
6+
function Test return Integer is
7+
8+
package A renames Test_Assert;
9+
package IO renames GNAT.IO;
10+
package OS renames GNATCOLL.OS;
11+
12+
begin
13+
IO.Put_Line ("GNATCOLL.OS.Process stderr test");
14+
15+
declare
16+
Args : OS.Process.Argument_List;
17+
Status : Integer;
18+
begin
19+
Args.Append (Test_Python.Python_Executable);
20+
Args.Append ("-c");
21+
Args.Append ("import sys; sys.stderr.write('one error')");
22+
23+
Status := OS.Process.Run (Args);
24+
A.Assert
25+
(Status, 0, "a status different from 0 means stderr write failed");
26+
end;
27+
return A.Report;
28+
end Test;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
title: GNATCOLL.OS.Process Check that we can write on stderr in the child process

0 commit comments

Comments
 (0)