Bug 1152428 - [mozprocess] Fix UnicodeEncodeError when non-ascii characters are in the environment, r?wlach draft
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Wed, 16 Mar 2016 11:07:35 -0400
changeset 342193 5f2e57b9445e44127bc6aea2420d246d42ca80bb
parent 341653 3e04659fdf6aef792f7cf9840189c6c38d08d1e8
child 516525 5173971ebd95020c65388fc9b4b805033637b12e
push id13355
push userahalberstadt@mozilla.com
push dateFri, 18 Mar 2016 14:14:34 +0000
reviewerswlach
bugs1152428
milestone48.0a1
Bug 1152428 - [mozprocess] Fix UnicodeEncodeError when non-ascii characters are in the environment, r?wlach MozReview-Commit-ID: 3AG9oLxWexy
testing/mozbase/mozprocess/mozprocess/processhandler.py
testing/mozbase/mozprocess/mozprocess/winprocess.py
testing/mozbase/mozprocess/tests/test_mozprocess_misc.py
--- a/testing/mozbase/mozprocess/mozprocess/processhandler.py
+++ b/testing/mozbase/mozprocess/mozprocess/processhandler.py
@@ -92,26 +92,16 @@ class ProcessHandlerMixin(object):
                 # Set the process group id for linux systems
                 # Sets process group id to the pid of the parent process
                 # NOTE: This prevents you from using preexec_fn and managing
                 #       child processes, TODO: Ideally, find a way around this
                 def setpgidfn():
                     os.setpgid(0, 0)
                 preexec_fn = setpgidfn
 
-            if isinstance(env, dict):
-                tmp_env = {}
-                for k, v in env.iteritems():
-                    if isinstance(k, bytes):
-                        k = k.decode(sys.getfilesystemencoding() or 'utf-8', 'replace')
-                    if isinstance(v, bytes):
-                        v = v.decode(sys.getfilesystemencoding() or 'utf-8', 'replace')
-                    tmp_env[k] = v
-                env = tmp_env
-
             try:
                 subprocess.Popen.__init__(self, args, bufsize, executable,
                                           stdin, stdout, stderr,
                                           preexec_fn, close_fds,
                                           shell, cwd, env,
                                           universal_newlines, startupinfo, creationflags)
             except OSError:
                 print >> sys.stderr, args
--- a/testing/mozbase/mozprocess/mozprocess/winprocess.py
+++ b/testing/mozbase/mozprocess/mozprocess/winprocess.py
@@ -29,17 +29,19 @@
 # THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
 # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
 # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
-from __future__ import absolute_import
+from __future__ import absolute_import, unicode_literals
+
+import sys
 
 from ctypes import c_void_p, POINTER, sizeof, Structure, windll, WinError, WINFUNCTYPE, c_ulong
 from ctypes.wintypes import BOOL, BYTE, DWORD, HANDLE, LPCWSTR, LPWSTR, UINT, WORD
 from .qijo import QueryInformationJobObject
 
 LPVOID = c_void_p
 LPBYTE = POINTER(BYTE)
 LPDWORD = POINTER(DWORD)
@@ -132,22 +134,28 @@ STARTF_FORCEOFFFEEDBACK = 0x80
 STARTF_USESTDHANDLES    = 0x100
 
 # EnvironmentBlock
 
 class EnvironmentBlock:
     """An object which can be passed as the lpEnv parameter of CreateProcess.
     It is initialized with a dictionary."""
 
-    def __init__(self, dict):
-        if not dict:
+    def __init__(self, env):
+        if not env:
             self._as_parameter_ = None
         else:
-            values = ["%s=%s" % (key, value)
-                      for (key, value) in dict.iteritems()]
+            values = []
+            fs_encoding = sys.getfilesystemencoding() or 'mbcs'
+            for k, v in env.iteritems():
+                if isinstance(k, bytes):
+                    k = k.decode(fs_encoding, 'replace')
+                if isinstance(v, bytes):
+                    v = v.decode(fs_encoding, 'replace')
+                values.append("{}={}".format(k, v))
             values.append("")
             self._as_parameter_ = LPCWSTR("\0".join(values))
 
 # Error Messages we need to watch for go here
 # See: http://msdn.microsoft.com/en-us/library/ms681388%28v=vs.85%29.aspx
 ERROR_ABANDONED_WAIT_0 = 735
             
 # GetLastError()
--- a/testing/mozbase/mozprocess/tests/test_mozprocess_misc.py
+++ b/testing/mozbase/mozprocess/tests/test_mozprocess_misc.py
@@ -1,9 +1,10 @@
 #!/usr/bin/env python
+# -*- coding: utf-8 -*-
 
 import os
 import unittest
 import proctest
 from mozprocess import processhandler
 
 here = os.path.dirname(os.path.abspath(__file__))
 
@@ -19,10 +20,21 @@ class ProcTestMisc(proctest.ProcTest):
                                           cwd=here)
 
         p.run()
         p.processOutput(timeout=5)
         p.wait()
 
         self.determine_status(p, False, ())
 
+    def test_unicode_in_environment(self):
+        env = {
+            'FOOBAR': 'ʘ',
+        }
+        p = processhandler.ProcessHandler([self.python, self.proclaunch,
+                                          "process_normal_finish_python.ini"],
+                                          cwd=here, env=env)
+        # passes if no exceptions are raised
+        p.run()
+        p.wait()
+
 if __name__ == '__main__':
     unittest.main()