[PATCH] pwclient: Fix silent crash on python 2

Robin Jarry robin.jarry at 6wind.com
Tue Mar 28 20:26:24 AEDT 2017


Replacing sys.stdout and sys.stderr can cause obscure crashes when
trying to write non unicode data. The interpreter is terminated with
SIGINT without any specific error writen on the console.

  rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f964820e8d0},
  {0x559f50, [], SA_RESTORER, 0x7f964820e8d0}, 8) = 0

This happens easily when there is an untrapped exception which should
lead to printing a traceback on stderr.

To fix this, the only way is to make sure that the PYTHONIOENCODING env
variable is set *before* starting the interpreter as the initialization
is made very early on and the encoding cannot be set or modified after.

On python 3, the default IO encoding is already properly set according
to locale.

Fixes: 046419a3bf8f ("pwclient: Fix encoding problems")
Signed-off-by: Robin Jarry <robin.jarry at 6wind.com>
---
 patchwork/bin/pwclient | 33 +++++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/patchwork/bin/pwclient b/patchwork/bin/pwclient
index ed0351bf5288..7a5c32fd66eb 100755
--- a/patchwork/bin/pwclient
+++ b/patchwork/bin/pwclient
@@ -43,14 +43,6 @@ import re
 import io
 import locale
 
-if sys.version_info.major == 2:
-    # hack to make writing unicode to standard output/error work on Python 2
-    OUT_ENCODING = (sys.stdout.encoding or locale.getpreferredencoding() or
-                    os.getenv('PYTHONIOENCODING', 'utf-8'))
-    sys.stdout = io.open(sys.stdout.fileno(), mode='w',
-                         encoding=OUT_ENCODING, errors='replace')
-    sys.stderr = io.open(sys.stderr.fileno(), mode='w',
-                         encoding=OUT_ENCODING, errors='replace')
 
 # Default Patchwork remote XML-RPC server URL
 # This script will check the PW_XMLRPC_URL environment variable
@@ -821,5 +813,30 @@ def main():
         sys.exit(1)
 
 
+def force_io_encoding():
+    """
+    Force python IO (stdout/err) encoding to something else than ASCII to
+    support printing unicode strings.
+
+    The only way to do it is via an environment variable *before* starting the
+    interpreter.
+
+    If PYTHONIOENCODING is not set, initialize it from locale or set default
+    value. Then re-execute the program so that IO encoding is properly
+    initialized.
+
+    The ":replace" suffix is to make python not crash on encoding errors but
+    replace them by printable characters.
+    """
+    if 'PYTHONIOENCODING' in os.environ or sys.version_info.major > 2:
+        return
+
+    encoding = locale.getpreferredencoding() or 'utf-8'
+
+    os.environ['PYTHONIOENCODING'] = encoding + ':replace'
+    os.execvp(sys.executable, [sys.executable] + sys.argv)  # no return
+
+
 if __name__ == "__main__":
+    force_io_encoding()
     main()
-- 
2.11.0.193.g1d1bdafd6426



More information about the Patchwork mailing list