commit:     ce1173fe24f8466a23c502a52af38cdab42353a2
Author:     Brian Harring <ferringb <AT> gmail <DOT> com>
AuthorDate: Sat Dec 24 22:23:54 2022 +0000
Commit:     Arthur Zamarin <arthurzam <AT> gentoo <DOT> org>
CommitDate: Sun Dec 25 17:40:11 2022 +0000
URL:        
https://gitweb.gentoo.org/proj/pkgcore/pkgcore.git/commit/?id=ce1173fe

Fix secondary exception from when an EBD fails to start.

Further in this __init__, self.pid is initialized to the process
that is started.  If that fails- an exception is thrown- then
self.pid doesn't exist, which in turn breaks the assumptions of
`shutdown_processor()` and `.is_alive` (both of which are
designed to work if an init partially failed).

Finally, add protections to ensure a failed spawn doesn't leak
file descriptors.  Python won't reap raw FD's, so we need to
handle this gracefully.

This secondary exception is visible in pkgcore/pkgcore#296

Signed-off-by: Brian Harring <ferringb <AT> gmail.com>
Closes: https://github.com/pkgcore/pkgcore/pull/383
Signed-off-by: Arthur Zamarin <arthurzam <AT> gentoo.org>

 src/pkgcore/ebuild/processor.py | 49 ++++++++++++++++++++++++++---------------
 1 file changed, 31 insertions(+), 18 deletions(-)

diff --git a/src/pkgcore/ebuild/processor.py b/src/pkgcore/ebuild/processor.py
index 6157ad692..8e9bf13cd 100644
--- a/src/pkgcore/ebuild/processor.py
+++ b/src/pkgcore/ebuild/processor.py
@@ -324,6 +324,7 @@ class EbuildProcessor:
         self._eclass_caching = False
         self._outstanding_expects = []
         self._metadata_paths = None
+        self.pid = None
 
         spawn_opts = {'umask': 0o002}
         if self.userpriv:
@@ -371,25 +372,37 @@ class EbuildProcessor:
             "PKGCORE_EBD_WRITE_FD": str(max_fd - 3),
         })
 
+        cread = cwrite = dread = dwrite = None
         # open pipes used for communication
-        cread, cwrite = os.pipe()
-        dread, dwrite = os.pipe()
-
-        # allow pipe overrides except ebd-related
-        ebd_pipes = {0: 0, 1: 1, 2: 2}
-        if fd_pipes:
-            ebd_pipes.update(fd_pipes)
-        ebd_pipes[max_fd - 4] = cread
-        ebd_pipes[max_fd - 3] = dwrite
-
-        # force each ebd instance to be a process group leader so everything
-        # can be easily terminated
-        self.pid = spawn_func(
-            [spawn.BASH_BINARY, self.ebd, "daemonize"],
-            fd_pipes=ebd_pipes, returnpid=True, env=env, pgid=0, 
**spawn_opts)[0]
-
-        os.close(cread)
-        os.close(dwrite)
+        try:
+            cread, cwrite = os.pipe()
+            dread, dwrite = os.pipe()
+
+            # allow pipe overrides except ebd-related
+            ebd_pipes = {0: 0, 1: 1, 2: 2}
+            if fd_pipes:
+                ebd_pipes.update(fd_pipes)
+            ebd_pipes[max_fd - 4] = cread
+            ebd_pipes[max_fd - 3] = dwrite
+
+            self.pid = spawn_func(
+                [spawn.BASH_BINARY, self.ebd, "daemonize"],
+                fd_pipes=ebd_pipes, returnpid=True, env=env,
+                # force each ebd instance to be a process group leader so 
everything
+                # can be easily terminated
+                pgid=0,
+                **spawn_opts)[0]
+        except:
+                if cwrite is not None:
+                    os.close(cwrite)
+                if dread is not None:
+                    os.close(dread)
+                raise
+        finally:
+            if cread is not None:
+                os.close(cread)
+            if dwrite is not None:
+                os.close(dwrite)
         self.ebd_write = os.fdopen(cwrite, "w")
         self.ebd_read = os.fdopen(dread, "r")
 

Reply via email to