Skip to content

Commit 94b169f

Browse files
[3.5] bpo-30708: Add private C API function _PyUnicode_AsWideCharString(). (GH-2285) (GH-2443) (#2448)
And use it instead of PyUnicode_AsWideCharString() if appropriate. _PyUnicode_AsWideCharString(unicode) is like PyUnicode_AsWideCharString(unicode, NULL), but raises a ValueError if the wchar_t* string contains null characters. (cherry picked from commit e613e6a). (cherry picked from commit 0edffa3)
1 parent eb3c52a commit 94b169f

File tree

10 files changed

+47
-10
lines changed

10 files changed

+47
-10
lines changed

Include/unicodeobject.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,12 @@ PyAPI_FUNC(wchar_t*) PyUnicode_AsWideCharString(
10541054
);
10551055

10561056
#ifndef Py_LIMITED_API
1057+
/* Similar to PyUnicode_AsWideCharString(unicode, NULL), but check if
1058+
the string contains null characters. */
1059+
PyAPI_FUNC(wchar_t*) _PyUnicode_AsWideCharString(
1060+
PyObject *unicode /* Unicode object */
1061+
);
1062+
10571063
PyAPI_FUNC(void*) _PyUnicode_AsKind(PyObject *s, unsigned int kind);
10581064
#endif
10591065

Lib/ctypes/test/test_slicing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ def test_wchar_ptr(self):
134134
dll.my_wcsdup.restype = POINTER(c_wchar)
135135
dll.my_wcsdup.argtypes = POINTER(c_wchar),
136136
dll.my_free.restype = None
137-
res = dll.my_wcsdup(s)
137+
res = dll.my_wcsdup(s[:-1])
138138
self.assertEqual(res[:len(s)], s)
139139
self.assertEqual(res[:len(s):], s)
140140
self.assertEqual(res[len(s)-1:-1:-1], s[::-1])
@@ -153,7 +153,7 @@ def test_wchar_ptr(self):
153153
dll.my_wcsdup.restype = POINTER(c_long)
154154
else:
155155
self.skipTest('Pointers to c_wchar are not supported')
156-
res = dll.my_wcsdup(s)
156+
res = dll.my_wcsdup(s[:-1])
157157
tmpl = list(range(ord("a"), ord("z")+1))
158158
self.assertEqual(res[:len(s)-1], tmpl)
159159
self.assertEqual(res[:len(s)-1:], tmpl)

Modules/_ctypes/callproc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ static int ConvParam(PyObject *obj, Py_ssize_t index, struct argument *pa)
672672
#ifdef CTYPES_UNICODE
673673
if (PyUnicode_Check(obj)) {
674674
pa->ffi_type = &ffi_type_pointer;
675-
pa->value.p = PyUnicode_AsWideCharString(obj, NULL);
675+
pa->value.p = _PyUnicode_AsWideCharString(obj);
676676
if (pa->value.p == NULL)
677677
return -1;
678678
pa->keep = PyCapsule_New(pa->value.p, CTYPES_CAPSULE_NAME_PYMEM, pymem_destructor);

Modules/_ctypes/cfield.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1386,7 +1386,7 @@ Z_set(void *ptr, PyObject *value, Py_ssize_t size)
13861386

13871387
/* We must create a wchar_t* buffer from the unicode object,
13881388
and keep it alive */
1389-
buffer = PyUnicode_AsWideCharString(value, NULL);
1389+
buffer = _PyUnicode_AsWideCharString(value);
13901390
if (!buffer)
13911391
return NULL;
13921392
keep = PyCapsule_New(buffer, CTYPES_CFIELD_CAPSULE_NAME_PYMEM, pymem_destructor);

Modules/_cursesmodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ PyCurses_ConvertToString(PyCursesWindowObject *win, PyObject *obj,
345345
if (PyUnicode_Check(obj)) {
346346
#ifdef HAVE_NCURSESW
347347
assert (wstr != NULL);
348-
*wstr = PyUnicode_AsWideCharString(obj, NULL);
348+
*wstr = _PyUnicode_AsWideCharString(obj);
349349
if (*wstr == NULL)
350350
return 0;
351351
return 2;

Modules/_localemodule.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,10 +215,10 @@ PyLocale_strcoll(PyObject* self, PyObject* args)
215215
if (!PyArg_ParseTuple(args, "UU:strcoll", &os1, &os2))
216216
return NULL;
217217
/* Convert the unicode strings to wchar[]. */
218-
ws1 = PyUnicode_AsWideCharString(os1, NULL);
218+
ws1 = _PyUnicode_AsWideCharString(os1);
219219
if (ws1 == NULL)
220220
goto done;
221-
ws2 = PyUnicode_AsWideCharString(os2, NULL);
221+
ws2 = _PyUnicode_AsWideCharString(os2);
222222
if (ws2 == NULL)
223223
goto done;
224224
/* Collate the strings. */

Modules/_tkinter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3620,7 +3620,7 @@ PyInit__tkinter(void)
36203620
return NULL;
36213621
}
36223622
if (str_path != NULL) {
3623-
wcs_path = PyUnicode_AsWideCharString(str_path, NULL);
3623+
wcs_path = _PyUnicode_AsWideCharString(str_path);
36243624
if (wcs_path == NULL) {
36253625
return NULL;
36263626
}

Modules/overlapped.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1151,7 +1151,7 @@ ConnectPipe(OverlappedObject *self, PyObject *args)
11511151
if (!PyArg_ParseTuple(args, "U", &AddressObj))
11521152
return NULL;
11531153

1154-
Address = PyUnicode_AsWideCharString(AddressObj, NULL);
1154+
Address = _PyUnicode_AsWideCharString(AddressObj);
11551155
if (Address == NULL)
11561156
return NULL;
11571157

Modules/timemodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,7 @@ time_strftime(PyObject *self, PyObject *args)
596596
buf.tm_isdst = 1;
597597

598598
#ifdef HAVE_WCSFTIME
599-
format = PyUnicode_AsWideCharString(format_arg, NULL);
599+
format = _PyUnicode_AsWideCharString(format_arg);
600600
if (format == NULL)
601601
return NULL;
602602
fmt = format;

Objects/unicodeobject.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2839,6 +2839,37 @@ PyUnicode_AsWideCharString(PyObject *unicode,
28392839
return buffer;
28402840
}
28412841

2842+
wchar_t*
2843+
_PyUnicode_AsWideCharString(PyObject *unicode)
2844+
{
2845+
const wchar_t *wstr;
2846+
wchar_t *buffer;
2847+
Py_ssize_t buflen;
2848+
2849+
if (unicode == NULL) {
2850+
PyErr_BadInternalCall();
2851+
return NULL;
2852+
}
2853+
2854+
wstr = PyUnicode_AsUnicodeAndSize(unicode, &buflen);
2855+
if (wstr == NULL) {
2856+
return NULL;
2857+
}
2858+
if (wcslen(wstr) != (size_t)buflen) {
2859+
PyErr_SetString(PyExc_ValueError,
2860+
"embedded null character");
2861+
return NULL;
2862+
}
2863+
2864+
buffer = PyMem_NEW(wchar_t, buflen + 1);
2865+
if (buffer == NULL) {
2866+
PyErr_NoMemory();
2867+
return NULL;
2868+
}
2869+
memcpy(buffer, wstr, (buflen + 1) * sizeof(wchar_t));
2870+
return buffer;
2871+
}
2872+
28422873
#endif /* HAVE_WCHAR_H */
28432874

28442875
PyObject *

0 commit comments

Comments
 (0)