bpo-36387: Refactor getenvironment() in _winapi.c. (GH-12482)

Make it doing less memory allocations and using the modern C API.
This commit is contained in:
Serhiy Storchaka 2019-03-28 16:01:34 +02:00 committed by GitHub
parent cda139d1de
commit 8abd7c7e37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 34 additions and 46 deletions

View File

@ -752,12 +752,12 @@ gethandle(PyObject* obj, const char* name)
return ret; return ret;
} }
static PyObject* static wchar_t *
getenvironment(PyObject* environment) getenvironment(PyObject* environment)
{ {
Py_ssize_t i, envsize, totalsize; Py_ssize_t i, envsize, totalsize;
Py_UCS4 *buffer = NULL, *p, *end; wchar_t *buffer = NULL, *p, *end;
PyObject *keys, *values, *res; PyObject *keys, *values;
/* convert environment dictionary to windows environment string */ /* convert environment dictionary to windows environment string */
if (! PyMapping_Check(environment)) { if (! PyMapping_Check(environment)) {
@ -775,8 +775,8 @@ getenvironment(PyObject* environment)
goto error; goto error;
} }
envsize = PySequence_Fast_GET_SIZE(keys); envsize = PyList_GET_SIZE(keys);
if (PySequence_Fast_GET_SIZE(values) != envsize) { if (PyList_GET_SIZE(values) != envsize) {
PyErr_SetString(PyExc_RuntimeError, PyErr_SetString(PyExc_RuntimeError,
"environment changed size during iteration"); "environment changed size during iteration");
goto error; goto error;
@ -784,8 +784,9 @@ getenvironment(PyObject* environment)
totalsize = 1; /* trailing null character */ totalsize = 1; /* trailing null character */
for (i = 0; i < envsize; i++) { for (i = 0; i < envsize; i++) {
PyObject* key = PySequence_Fast_GET_ITEM(keys, i); PyObject* key = PyList_GET_ITEM(keys, i);
PyObject* value = PySequence_Fast_GET_ITEM(values, i); PyObject* value = PyList_GET_ITEM(values, i);
Py_ssize_t size;
if (! PyUnicode_Check(key) || ! PyUnicode_Check(value)) { if (! PyUnicode_Check(key) || ! PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
@ -806,19 +807,25 @@ getenvironment(PyObject* environment)
PyErr_SetString(PyExc_ValueError, "illegal environment variable name"); PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
goto error; goto error;
} }
if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(key) - 1) {
size = PyUnicode_AsWideChar(key, NULL, 0);
assert(size > 1);
if (totalsize > PY_SSIZE_T_MAX - size) {
PyErr_SetString(PyExc_OverflowError, "environment too long"); PyErr_SetString(PyExc_OverflowError, "environment too long");
goto error; goto error;
} }
totalsize += PyUnicode_GET_LENGTH(key) + 1; /* +1 for '=' */ totalsize += size; /* including '=' */
if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(value) - 1) {
size = PyUnicode_AsWideChar(value, NULL, 0);
assert(size > 0);
if (totalsize > PY_SSIZE_T_MAX - size) {
PyErr_SetString(PyExc_OverflowError, "environment too long"); PyErr_SetString(PyExc_OverflowError, "environment too long");
goto error; goto error;
} }
totalsize += PyUnicode_GET_LENGTH(value) + 1; /* +1 for '\0' */ totalsize += size; /* including trailing '\0' */
} }
buffer = PyMem_NEW(Py_UCS4, totalsize); buffer = PyMem_NEW(wchar_t, totalsize);
if (! buffer) { if (! buffer) {
PyErr_NoMemory(); PyErr_NoMemory();
goto error; goto error;
@ -827,34 +834,25 @@ getenvironment(PyObject* environment)
end = buffer + totalsize; end = buffer + totalsize;
for (i = 0; i < envsize; i++) { for (i = 0; i < envsize; i++) {
PyObject* key = PySequence_Fast_GET_ITEM(keys, i); PyObject* key = PyList_GET_ITEM(keys, i);
PyObject* value = PySequence_Fast_GET_ITEM(values, i); PyObject* value = PyList_GET_ITEM(values, i);
if (!PyUnicode_AsUCS4(key, p, end - p, 0)) Py_ssize_t size = PyUnicode_AsWideChar(key, p, end - p);
goto error; assert(1 <= size && size < end - p);
p += PyUnicode_GET_LENGTH(key); p += size;
*p++ = '='; *p++ = L'=';
if (!PyUnicode_AsUCS4(value, p, end - p, 0)) size = PyUnicode_AsWideChar(value, p, end - p);
goto error; assert(0 <= size && size < end - p);
p += PyUnicode_GET_LENGTH(value); p += size + 1;
*p++ = '\0';
} }
/* add trailing null byte */ /* add trailing null character */
*p++ = '\0'; *p++ = L'\0';
assert(p == end); assert(p == end);
Py_XDECREF(keys);
Py_XDECREF(values);
res = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buffer, p - buffer);
PyMem_Free(buffer);
return res;
error: error:
PyMem_Free(buffer);
Py_XDECREF(keys); Py_XDECREF(keys);
Py_XDECREF(values); Py_XDECREF(values);
return NULL; return buffer;
} }
static LPHANDLE static LPHANDLE
@ -1053,8 +1051,7 @@ _winapi_CreateProcess_impl(PyObject *module,
BOOL result; BOOL result;
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
STARTUPINFOEXW si; STARTUPINFOEXW si;
PyObject *environment = NULL; wchar_t *wenvironment = NULL;
wchar_t *wenvironment;
wchar_t *command_line_copy = NULL; wchar_t *command_line_copy = NULL;
AttributeList attribute_list = {0}; AttributeList attribute_list = {0};
@ -1071,20 +1068,11 @@ _winapi_CreateProcess_impl(PyObject *module,
goto cleanup; goto cleanup;
if (env_mapping != Py_None) { if (env_mapping != Py_None) {
environment = getenvironment(env_mapping); wenvironment = getenvironment(env_mapping);
if (environment == NULL) {
goto cleanup;
}
/* contains embedded null characters */
wenvironment = PyUnicode_AsUnicode(environment);
if (wenvironment == NULL) { if (wenvironment == NULL) {
goto cleanup; goto cleanup;
} }
} }
else {
environment = NULL;
wenvironment = NULL;
}
if (getattributelist(startup_info, "lpAttributeList", &attribute_list) < 0) if (getattributelist(startup_info, "lpAttributeList", &attribute_list) < 0)
goto cleanup; goto cleanup;
@ -1131,7 +1119,7 @@ _winapi_CreateProcess_impl(PyObject *module,
cleanup: cleanup:
PyMem_Free(command_line_copy); PyMem_Free(command_line_copy);
Py_XDECREF(environment); PyMem_Free(wenvironment);
freeattributelist(&attribute_list); freeattributelist(&attribute_list);
return ret; return ret;