Skip to content

Commit d878349

Browse files
bpo-36346: Do not use legacy Unicode C API in ctypes. (#21429)
1 parent 0f9aa47 commit d878349

File tree

3 files changed

+21
-29
lines changed

3 files changed

+21
-29
lines changed

Modules/_ctypes/_ctypes.c

+14-19
Original file line numberDiff line numberDiff line change
@@ -1366,8 +1366,6 @@ WCharArray_get_value(CDataObject *self, void *Py_UNUSED(ignored))
13661366
static int
13671367
WCharArray_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored))
13681368
{
1369-
Py_ssize_t result = 0;
1370-
13711369
if (value == NULL) {
13721370
PyErr_SetString(PyExc_TypeError,
13731371
"can't delete attribute");
@@ -1378,29 +1376,24 @@ WCharArray_set_value(CDataObject *self, PyObject *value, void *Py_UNUSED(ignored
13781376
"unicode string expected instead of %s instance",
13791377
Py_TYPE(value)->tp_name);
13801378
return -1;
1381-
} else
1382-
Py_INCREF(value);
1379+
}
13831380

1381+
Py_ssize_t size = self->b_size / sizeof(wchar_t);
13841382
Py_ssize_t len = PyUnicode_AsWideChar(value, NULL, 0);
13851383
if (len < 0) {
13861384
return -1;
13871385
}
13881386
// PyUnicode_AsWideChar() returns number of wchars including trailing null byte,
13891387
// when it is called with NULL.
1390-
if (((size_t)len-1) > self->b_size/sizeof(wchar_t)) {
1388+
assert(len > 0);
1389+
if (len - 1 > size) {
13911390
PyErr_SetString(PyExc_ValueError, "string too long");
1392-
result = -1;
1393-
goto done;
1394-
}
1395-
result = PyUnicode_AsWideChar(value,
1396-
(wchar_t *)self->b_ptr,
1397-
self->b_size/sizeof(wchar_t));
1398-
if (result >= 0 && (size_t)result < self->b_size/sizeof(wchar_t))
1399-
((wchar_t *)self->b_ptr)[result] = (wchar_t)0;
1400-
done:
1401-
Py_DECREF(value);
1402-
1403-
return result >= 0 ? 0 : -1;
1391+
return -1;
1392+
}
1393+
if (PyUnicode_AsWideChar(value, (wchar_t *)self->b_ptr, size) < 0) {
1394+
return -1;
1395+
}
1396+
return 0;
14041397
}
14051398

14061399
static PyGetSetDef WCharArray_getsets[] = {
@@ -3484,10 +3477,12 @@ _validate_paramflags(PyTypeObject *type, PyObject *paramflags)
34843477
for (i = 0; i < len; ++i) {
34853478
PyObject *item = PyTuple_GET_ITEM(paramflags, i);
34863479
int flag;
3487-
char *name;
3480+
PyObject *name = Py_None;
34883481
PyObject *defval;
34893482
PyObject *typ;
3490-
if (!PyArg_ParseTuple(item, "i|ZO", &flag, &name, &defval)) {
3483+
if (!PyArg_ParseTuple(item, "i|OO", &flag, &name, &defval) ||
3484+
!(name == Py_None || PyUnicode_Check(name)))
3485+
{
34913486
PyErr_SetString(PyExc_TypeError,
34923487
"paramflags must be a sequence of (int [,string [,value]]) tuples");
34933488
return 0;

Modules/_ctypes/callproc.c

+5-5
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,6 @@ module. load_flags are as defined for LoadLibraryEx in the\n\
13001300
Windows API.\n";
13011301
static PyObject *load_library(PyObject *self, PyObject *args)
13021302
{
1303-
const WCHAR *name;
13041303
PyObject *nameobj;
13051304
int load_flags = 0;
13061305
HMODULE hMod;
@@ -1309,14 +1308,14 @@ static PyObject *load_library(PyObject *self, PyObject *args)
13091308
if (!PyArg_ParseTuple(args, "U|i:LoadLibrary", &nameobj, &load_flags))
13101309
return NULL;
13111310

1312-
name = _PyUnicode_AsUnicode(nameobj);
1313-
if (!name)
1314-
return NULL;
1315-
13161311
if (PySys_Audit("ctypes.dlopen", "O", nameobj) < 0) {
13171312
return NULL;
13181313
}
13191314

1315+
WCHAR *name = PyUnicode_AsWideCharString(nameobj, NULL);
1316+
if (!name)
1317+
return NULL;
1318+
13201319
Py_BEGIN_ALLOW_THREADS
13211320
/* bpo-36085: Limit DLL search directories to avoid pre-loading
13221321
* attacks and enable use of the AddDllDirectory function.
@@ -1325,6 +1324,7 @@ static PyObject *load_library(PyObject *self, PyObject *args)
13251324
err = hMod ? 0 : GetLastError();
13261325
Py_END_ALLOW_THREADS
13271326

1327+
PyMem_Free(name);
13281328
if (err == ERROR_MOD_NOT_FOUND) {
13291329
PyErr_Format(PyExc_FileNotFoundError,
13301330
("Could not find module '%.500S' (or one of its "

Modules/_ctypes/cfield.c

+2-5
Original file line numberDiff line numberDiff line change
@@ -1220,11 +1220,8 @@ U_set(void *ptr, PyObject *value, Py_ssize_t length)
12201220
"string too long (%zd, maximum length %zd)",
12211221
size, length);
12221222
return NULL;
1223-
} else if (size < length-1)
1224-
/* copy terminating NUL character if there is space */
1225-
size += 1;
1226-
1227-
if (PyUnicode_AsWideChar(value, (wchar_t *)ptr, size) == -1) {
1223+
}
1224+
if (PyUnicode_AsWideChar(value, (wchar_t *)ptr, length) == -1) {
12281225
return NULL;
12291226
}
12301227

0 commit comments

Comments
 (0)