Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions Doc/c-api/unicode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
=======
Expand Down
4 changes: 2 additions & 2 deletions Lib/ctypes/test/test_slicing.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def test_wchar_ptr(self):
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])
Expand All @@ -153,7 +153,7 @@ def test_wchar_ptr(self):
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)
Expand Down
4 changes: 4 additions & 0 deletions Misc/NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -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().

Expand Down
9 changes: 1 addition & 8 deletions Modules/_io/winconsoleio.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
49 changes: 22 additions & 27 deletions Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2953,23 +2953,26 @@ 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.

- 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;
Expand All @@ -2986,43 +2989,35 @@ 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) {
PyErr_BadInternalCall();
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;
Expand Down