[Python-checkins] bpo-34523, bpo-35322: Fix unicode_encode_locale() (GH-10759)

Victor Stinner webhook-mailer at python.org
Wed Nov 28 04:26:24 EST 2018


https://github.com/python/cpython/commit/bde9d6bbb46ca59bcee5d5060adaa33c3ffee3a6
commit: bde9d6bbb46ca59bcee5d5060adaa33c3ffee3a6
branch: master
author: Victor Stinner <vstinner at redhat.com>
committer: GitHub <noreply at github.com>
date: 2018-11-28T10:26:20+01:00
summary:

bpo-34523, bpo-35322: Fix unicode_encode_locale() (GH-10759)

Fix memory leak in PyUnicode_EncodeLocale() and
PyUnicode_EncodeFSDefault() on error handling.

Changes:

* Fix unicode_encode_locale() error handling
* Fix test_codecs.LocaleCodecTest

files:
A Misc/NEWS.d/next/C API/2018-11-28-03-20-36.bpo-35322.Qcqsag.rst
M Lib/test/test_codecs.py
M Objects/unicodeobject.c

diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py
index 00b5d317c401..8c92556e8429 100644
--- a/Lib/test/test_codecs.py
+++ b/Lib/test/test_codecs.py
@@ -3290,9 +3290,9 @@ def check_encode_strings(self, errors):
                     expected = text.encode(self.ENCODING, errors)
                 except UnicodeEncodeError:
                     with self.assertRaises(RuntimeError) as cm:
-                        self.encode(self.SURROGATES)
+                        self.encode(text, errors)
                     errmsg = str(cm.exception)
-                    self.assertTrue(errmsg.startswith("encode error: pos=0, reason="), errmsg)
+                    self.assertRegex(errmsg, r"encode error: pos=[0-9]+, reason=")
                 else:
                     encoded = self.encode(text, errors)
                     self.assertEqual(encoded, expected)
@@ -3315,6 +3315,11 @@ def test_encode_surrogatepass(self):
 
         self.check_encode_strings("surrogatepass")
 
+    def test_encode_unsupported_error_handler(self):
+        with self.assertRaises(ValueError) as cm:
+            self.encode('', 'backslashreplace')
+        self.assertEqual(str(cm.exception), 'unsupported error handler')
+
     def decode(self, encoded, errors="strict"):
         return _testcapi.DecodeLocaleEx(encoded, 0, errors)
 
@@ -3370,6 +3375,11 @@ def test_decode_surrogatepass(self):
 
         self.check_decode_strings("surrogatepass")
 
+    def test_decode_unsupported_error_handler(self):
+        with self.assertRaises(ValueError) as cm:
+            self.decode(b'', 'backslashreplace')
+        self.assertEqual(str(cm.exception), 'unsupported error handler')
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS.d/next/C API/2018-11-28-03-20-36.bpo-35322.Qcqsag.rst b/Misc/NEWS.d/next/C API/2018-11-28-03-20-36.bpo-35322.Qcqsag.rst
new file mode 100644
index 000000000000..f5b4796307f7
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2018-11-28-03-20-36.bpo-35322.Qcqsag.rst	
@@ -0,0 +1,2 @@
+Fix memory leak in :c:func:`PyUnicode_EncodeLocale` and
+:c:func:`PyUnicode_EncodeFSDefault` on error handling.
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 2b1db918a154..bc98c44c7407 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -3449,10 +3449,9 @@ unicode_encode_locale(PyObject *unicode, const char *errors,
         return NULL;
     }
 
-    Py_ssize_t wlen2 = wcslen(wstr);
-    if (wlen2 != wlen) {
-        PyMem_Free(wstr);
+    if ((size_t)wlen != wcslen(wstr)) {
         PyErr_SetString(PyExc_ValueError, "embedded null character");
+        PyMem_Free(wstr);
         return NULL;
     }
 
@@ -3461,6 +3460,8 @@ unicode_encode_locale(PyObject *unicode, const char *errors,
     const char *reason;
     int res = _Py_EncodeLocaleEx(wstr, &str, &error_pos, &reason,
                                  current_locale, error_handler);
+    PyMem_Free(wstr);
+
     if (res != 0) {
         if (res == -2) {
             PyObject *exc;
@@ -3473,18 +3474,15 @@ unicode_encode_locale(PyObject *unicode, const char *errors,
                 PyCodec_StrictErrors(exc);
                 Py_DECREF(exc);
             }
-            return NULL;
         }
         else if (res == -3) {
             PyErr_SetString(PyExc_ValueError, "unsupported error handler");
         }
         else {
             PyErr_NoMemory();
-            PyMem_Free(wstr);
-            return NULL;
         }
+        return NULL;
     }
-    PyMem_Free(wstr);
 
     PyObject *bytes = PyBytes_FromString(str);
     PyMem_RawFree(str);



More information about the Python-checkins mailing list