Bug 1152428 - [mozprocess] Fix UnicodeEncodeError when non-ascii characters are in the environment, r=wlach
authorAndrew Halberstadt <ahalberstadt@mozilla.com>
Wed, 16 Mar 2016 11:07:35 -0400
changeset 289365 f1482a4600fc249ff802b31277fe3084089fe33a
parent 289364 0a0cbca83706620c6f012354035906b1b5b8922f
child 289366 fef5ea8968cbf4cc85cf59e5e03c98854fd54ba3
push id73804
push userahalberstadt@mozilla.com
push dateFri, 18 Mar 2016 16:17:36 +0000
treeherdermozilla-inbound@f1482a4600fc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswlach
bugs1152428
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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()