summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@redhat.com>2018-11-28 09:26:20 (GMT)
committerGitHub <noreply@github.com>2018-11-28 09:26:20 (GMT)
commitbde9d6bbb46ca59bcee5d5060adaa33c3ffee3a6 (patch)
treeef525570f785225ab3da54b867b2ea4cb137fb40
parenta22df4896f6b83c8741203118790ae281716bca5 (diff)
downloadcpython-bde9d6bbb46ca59bcee5d5060adaa33c3ffee3a6.zip
cpython-bde9d6bbb46ca59bcee5d5060adaa33c3ffee3a6.tar.gz
cpython-bde9d6bbb46ca59bcee5d5060adaa33c3ffee3a6.tar.bz2
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
-rw-r--r--Lib/test/test_codecs.py14
-rw-r--r--Misc/NEWS.d/next/C API/2018-11-28-03-20-36.bpo-35322.Qcqsag.rst2
-rw-r--r--Objects/unicodeobject.c12
3 files changed, 19 insertions, 9 deletions
diff --git a/Lib/test/test_codecs.py b/Lib/test/test_codecs.py
index 00b5d31..8c92556 100644
--- a/Lib/test/test_codecs.py
+++ b/Lib/test/test_codecs.py
@@ -3290,9 +3290,9 @@ class LocaleCodecTest(unittest.TestCase):
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 @@ class LocaleCodecTest(unittest.TestCase):
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 @@ class LocaleCodecTest(unittest.TestCase):
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 0000000..f5b4796
--- /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 2b1db91..bc98c44 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);