From b4b5abd17a3357561a3b7b9f7f7916778a719d93 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Tue, 14 Aug 2018 15:00:29 -0600 Subject: Redo fix for file closing in SCons.Action._subproc When the _subproc wrapper is called, a keyword dictionary is used to hold open file objects if any were indicated as being redirected to os.devull. These objects just go missing when SCons.Action._subproc is done. A previous iteration registered the close method of the object with atexit, which made Python 3 happy the open file resources were not leaking, but has some unexpected side effects. Apparently Action cannot import either atexit or the SCons equivalent, SCons.exitfuncs without triggering these effects. As an alternative, close the objects in the parent's kw dictionary that have close methods after the subprocess.Popen object has been created. Signed-off-by: Mats Wichmann --- src/engine/SCons/Action.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py index 249363f..32ceaa9 100644 --- a/src/engine/SCons/Action.py +++ b/src/engine/SCons/Action.py @@ -107,7 +107,6 @@ import sys import subprocess import itertools import inspect -import atexit import SCons.Debug from SCons.Debug import logInstanceCreation @@ -116,8 +115,7 @@ import SCons.Util import SCons.Subst # we use these a lot, so try to optimize them -is_String = SCons.Util.is_String -is_List = SCons.Util.is_List +from SCons.Util import is_String, is_List class _null(object): pass @@ -773,15 +771,12 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw): io = kw.get('stdin') if is_String(io) and io == 'devnull': kw['stdin'] = open(os.devnull) - atexit.register(kw['stdin'].close) io = kw.get('stdout') if is_String(io) and io == 'devnull': kw['stdout'] = open(os.devnull, 'w') - atexit.register(kw['stdout'].close) io = kw.get('stderr') if is_String(io) and io == 'devnull': kw['stderr'] = open(os.devnull, 'w') - atexit.register(kw['stderr'].close) # Figure out what shell environment to use ENV = kw.get('env', None) @@ -807,7 +802,7 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw): kw['env'] = new_env try: - return subprocess.Popen(cmd, **kw) + pobj = subprocess.Popen(cmd, **kw) except EnvironmentError as e: if error == 'raise': raise # return a dummy Popen instance that only returns error @@ -821,7 +816,14 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw): def readline(self): return '' def __iter__(self): return iter(()) stdout = stderr = f() - return dummyPopen(e) + pobj = dummyPopen(e) + finally: + # clean up open file handles stored in parent's kw + import io + for k, v in kw.items(): + if hasattr(v, 'close'): + v.close() + return pobj class CommandAction(_ActionAction): -- cgit v0.12