]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-30708: Check for null characters in PyUnicode_AsWideCharString(). (#2285)
authorSerhiy Storchaka <storchaka@gmail.com>
Tue, 27 Jun 2017 13:03:14 +0000 (16:03 +0300)
committerGitHub <noreply@github.com>
Tue, 27 Jun 2017 13:03:14 +0000 (16:03 +0300)
Raise a ValueError if the second argument is NULL and the wchar_t\*
string contains null characters.

Doc/c-api/unicode.rst
Doc/whatsnew/3.7.rst
Lib/ctypes/test/test_slicing.py
Misc/NEWS
Modules/_io/winconsoleio.c
Objects/unicodeobject.c

index 84059e46105149361ac8178613741e4641a5b864..45aff1b7e3c9d95fc5636d7f4cb0662fdc94e1f3 100644 (file)
@@ -934,16 +934,22 @@ wchar_t Support
    Convert the Unicode object to a wide character string. The output string
    always ends with a null character. If *size* is not *NULL*, write the number
    of wide characters (excluding the trailing null termination character) into
-   *\*size*.
+   *\*size*. Note that the resulting :c:type:`wchar_t` string might contain
+   null characters, which would cause the string to be truncated when used with
+   most C functions. If *size* is *NULL* and the :c:type:`wchar_t*` string
+   contains null characters a :exc:`ValueError` is raised.
 
    Returns a buffer allocated by :c:func:`PyMem_Alloc` (use
-   :c:func:`PyMem_Free` to free it) on success. On error, returns *NULL*,
-   *\*size* is undefined and raises a :exc:`MemoryError`. Note that the
-   resulting :c:type:`wchar_t` string might contain null characters, which
-   would cause the string to be truncated when used with most C functions.
+   :c:func:`PyMem_Free` to free it) on success. On error, returns *NULL*
+   and *\*size* is undefined. Raises a :exc:`MemoryError` if memory allocation
+   is failed.
 
    .. versionadded:: 3.2
 
+   .. versionchanged:: 3.7
+      Raises a :exc:`ValueError` if *size* is *NULL* and the :c:type:`wchar_t*`
+      string contains null characters.
+
 
 .. _builtincodecs:
 
index 927ae5ba30512af38ee81c32382cdaee261b9d67..e34268e08246821c8e454ce4e4ecd8264e19aca1 100644 (file)
@@ -360,6 +360,10 @@ Changes in the C API
   :c:type:`unsigned long`.
   (Contributed by Serhiy Storchaka in :issue:`6532`.)
 
+- :c:func:`PyUnicode_AsWideCharString` now raises a :exc:`ValueError` if the
+  second argument is *NULL* and the :c:type:`wchar_t*` string contains null
+  characters.  (Contributed by Serhiy Storchaka in :issue:`30708`.)
+
 
 Removed
 =======
index 240dc0cdda2462eb9a980acb02b7594dfd0f19d6..a3932f176728aff0a0bb5a5412ba6a11499a4d5c 100644 (file)
@@ -134,7 +134,7 @@ class SlicesTestCase(unittest.TestCase):
         dll.my_wcsdup.restype = POINTER(c_wchar)
         dll.my_wcsdup.argtypes = POINTER(c_wchar),
         dll.my_free.restype = None
-        res = dll.my_wcsdup(s)
+        res = dll.my_wcsdup(s[:-1])
         self.assertEqual(res[:len(s)], s)
         self.assertEqual(res[:len(s):], s)
         self.assertEqual(res[len(s)-1:-1:-1], s[::-1])
@@ -153,7 +153,7 @@ class SlicesTestCase(unittest.TestCase):
             dll.my_wcsdup.restype = POINTER(c_long)
         else:
             self.skipTest('Pointers to c_wchar are not supported')
-        res = dll.my_wcsdup(s)
+        res = dll.my_wcsdup(s[:-1])
         tmpl = list(range(ord("a"), ord("z")+1))
         self.assertEqual(res[:len(s)-1], tmpl)
         self.assertEqual(res[:len(s)-1:], tmpl)
index 83eb530602e03d4baf311fe931363f99bae03cf0..232fb7547d2153ea7c1c3fafc369a824839b1e8c 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -1245,6 +1245,10 @@ Windows
 C API
 -----
 
+- bpo-30708: PyUnicode_AsWideCharString() now raises a ValueError if the
+  second argument is NULL and the wchar_t\* string contains null
+  characters.
+
 - bpo-16500: Deprecate PyOS_AfterFork() and add PyOS_BeforeFork(),
   PyOS_AfterFork_Parent() and PyOS_AfterFork_Child().
 
index 781518a193c72133aa1182c01eadb8b6ee6d7495..6600fde1942978d1ca281f8fe1ca119c6a3f18d7 100644 (file)
@@ -304,18 +304,11 @@ _io__WindowsConsoleIO___init___impl(winconsoleio *self, PyObject *nameobj,
         if (!d)
             return -1;
 
-        Py_ssize_t length;
-        name = PyUnicode_AsWideCharString(decodedname, &length);
+        name = PyUnicode_AsWideCharString(decodedname, NULL);
         console_type = _PyIO_get_console_type(decodedname);
         Py_CLEAR(decodedname);
         if (name == NULL)
             return -1;
-
-        if (wcslen(name) != length) {
-            PyMem_Free(name);
-            PyErr_SetString(PyExc_ValueError, "embedded null character");
-            return -1;
-        }
     }
 
     s = mode;
index b68042179f0903222254cee885cf161b14b8eefb..646de0e917a0aefc09d8fee13336a0187e138d61 100644 (file)
@@ -2953,8 +2953,7 @@ PyUnicode_FromFormat(const char *format, ...)
 
 #ifdef HAVE_WCHAR_H
 
-/* Helper function for PyUnicode_AsWideChar() and PyUnicode_AsWideCharString():
-   convert a Unicode object to a wide character string.
+/* Convert a Unicode object to a wide character string.
 
    - If w is NULL: return the number of wide characters (including the null
      character) required to convert the unicode object. Ignore size argument.
@@ -2962,14 +2961,18 @@ PyUnicode_FromFormat(const char *format, ...)
    - Otherwise: return the number of wide characters (excluding the null
      character) written into w. Write at most size wide characters (including
      the null character). */
-static Py_ssize_t
-unicode_aswidechar(PyObject *unicode,
-                   wchar_t *w,
-                   Py_ssize_t size)
+Py_ssize_t
+PyUnicode_AsWideChar(PyObject *unicode,
+                     wchar_t *w,
+                     Py_ssize_t size)
 {
     Py_ssize_t res;
     const wchar_t *wstr;
 
+    if (unicode == NULL) {
+        PyErr_BadInternalCall();
+        return -1;
+    }
     wstr = PyUnicode_AsUnicodeAndSize(unicode, &res);
     if (wstr == NULL)
         return -1;
@@ -2986,23 +2989,12 @@ unicode_aswidechar(PyObject *unicode,
         return res + 1;
 }
 
-Py_ssize_t
-PyUnicode_AsWideChar(PyObject *unicode,
-                     wchar_t *w,
-                     Py_ssize_t size)
-{
-    if (unicode == NULL) {
-        PyErr_BadInternalCall();
-        return -1;
-    }
-    return unicode_aswidechar(unicode, w, size);
-}
-
 wchar_t*
 PyUnicode_AsWideCharString(PyObject *unicode,
                            Py_ssize_t *size)
 {
-    wchar_t* buffer;
+    const wchar_t *wstr;
+    wchar_t *buffer;
     Py_ssize_t buflen;
 
     if (unicode == NULL) {
@@ -3010,19 +3002,22 @@ PyUnicode_AsWideCharString(PyObject *unicode,
         return NULL;
     }
 
-    buflen = unicode_aswidechar(unicode, NULL, 0);
-    if (buflen == -1)
+    wstr = PyUnicode_AsUnicodeAndSize(unicode, &buflen);
+    if (wstr == NULL) {
         return NULL;
-    buffer = PyMem_NEW(wchar_t, buflen);
-    if (buffer == NULL) {
-        PyErr_NoMemory();
+    }
+    if (size == NULL && wcslen(wstr) != (size_t)buflen) {
+        PyErr_SetString(PyExc_ValueError,
+                        "embedded null character");
         return NULL;
     }
-    buflen = unicode_aswidechar(unicode, buffer, buflen);
-    if (buflen == -1) {
-        PyMem_FREE(buffer);
+
+    buffer = PyMem_NEW(wchar_t, buflen + 1);
+    if (buffer == NULL) {
+        PyErr_NoMemory();
         return NULL;
     }
+    memcpy(buffer, wstr, (buflen + 1) * sizeof(wchar_t));
     if (size != NULL)
         *size = buflen;
     return buffer;