Skip to content

Commit 8abd7c7

Browse files
bpo-36387: Refactor getenvironment() in _winapi.c. (GH-12482)
Make it doing less memory allocations and using the modern C API.
1 parent cda139d commit 8abd7c7

File tree

1 file changed

+34
-46
lines changed

1 file changed

+34
-46
lines changed

Modules/_winapi.c

+34-46
Original file line numberDiff line numberDiff line change
@@ -752,12 +752,12 @@ gethandle(PyObject* obj, const char* name)
752752
return ret;
753753
}
754754

755-
static PyObject*
755+
static wchar_t *
756756
getenvironment(PyObject* environment)
757757
{
758758
Py_ssize_t i, envsize, totalsize;
759-
Py_UCS4 *buffer = NULL, *p, *end;
760-
PyObject *keys, *values, *res;
759+
wchar_t *buffer = NULL, *p, *end;
760+
PyObject *keys, *values;
761761

762762
/* convert environment dictionary to windows environment string */
763763
if (! PyMapping_Check(environment)) {
@@ -775,17 +775,18 @@ getenvironment(PyObject* environment)
775775
goto error;
776776
}
777777

778-
envsize = PySequence_Fast_GET_SIZE(keys);
779-
if (PySequence_Fast_GET_SIZE(values) != envsize) {
778+
envsize = PyList_GET_SIZE(keys);
779+
if (PyList_GET_SIZE(values) != envsize) {
780780
PyErr_SetString(PyExc_RuntimeError,
781781
"environment changed size during iteration");
782782
goto error;
783783
}
784784

785785
totalsize = 1; /* trailing null character */
786786
for (i = 0; i < envsize; i++) {
787-
PyObject* key = PySequence_Fast_GET_ITEM(keys, i);
788-
PyObject* value = PySequence_Fast_GET_ITEM(values, i);
787+
PyObject* key = PyList_GET_ITEM(keys, i);
788+
PyObject* value = PyList_GET_ITEM(values, i);
789+
Py_ssize_t size;
789790

790791
if (! PyUnicode_Check(key) || ! PyUnicode_Check(value)) {
791792
PyErr_SetString(PyExc_TypeError,
@@ -806,19 +807,25 @@ getenvironment(PyObject* environment)
806807
PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
807808
goto error;
808809
}
809-
if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(key) - 1) {
810+
811+
size = PyUnicode_AsWideChar(key, NULL, 0);
812+
assert(size > 1);
813+
if (totalsize > PY_SSIZE_T_MAX - size) {
810814
PyErr_SetString(PyExc_OverflowError, "environment too long");
811815
goto error;
812816
}
813-
totalsize += PyUnicode_GET_LENGTH(key) + 1; /* +1 for '=' */
814-
if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(value) - 1) {
817+
totalsize += size; /* including '=' */
818+
819+
size = PyUnicode_AsWideChar(value, NULL, 0);
820+
assert(size > 0);
821+
if (totalsize > PY_SSIZE_T_MAX - size) {
815822
PyErr_SetString(PyExc_OverflowError, "environment too long");
816823
goto error;
817824
}
818-
totalsize += PyUnicode_GET_LENGTH(value) + 1; /* +1 for '\0' */
825+
totalsize += size; /* including trailing '\0' */
819826
}
820827

821-
buffer = PyMem_NEW(Py_UCS4, totalsize);
828+
buffer = PyMem_NEW(wchar_t, totalsize);
822829
if (! buffer) {
823830
PyErr_NoMemory();
824831
goto error;
@@ -827,34 +834,25 @@ getenvironment(PyObject* environment)
827834
end = buffer + totalsize;
828835

829836
for (i = 0; i < envsize; i++) {
830-
PyObject* key = PySequence_Fast_GET_ITEM(keys, i);
831-
PyObject* value = PySequence_Fast_GET_ITEM(values, i);
832-
if (!PyUnicode_AsUCS4(key, p, end - p, 0))
833-
goto error;
834-
p += PyUnicode_GET_LENGTH(key);
835-
*p++ = '=';
836-
if (!PyUnicode_AsUCS4(value, p, end - p, 0))
837-
goto error;
838-
p += PyUnicode_GET_LENGTH(value);
839-
*p++ = '\0';
837+
PyObject* key = PyList_GET_ITEM(keys, i);
838+
PyObject* value = PyList_GET_ITEM(values, i);
839+
Py_ssize_t size = PyUnicode_AsWideChar(key, p, end - p);
840+
assert(1 <= size && size < end - p);
841+
p += size;
842+
*p++ = L'=';
843+
size = PyUnicode_AsWideChar(value, p, end - p);
844+
assert(0 <= size && size < end - p);
845+
p += size + 1;
840846
}
841847

842-
/* add trailing null byte */
843-
*p++ = '\0';
848+
/* add trailing null character */
849+
*p++ = L'\0';
844850
assert(p == end);
845851

846-
Py_XDECREF(keys);
847-
Py_XDECREF(values);
848-
849-
res = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buffer, p - buffer);
850-
PyMem_Free(buffer);
851-
return res;
852-
853852
error:
854-
PyMem_Free(buffer);
855853
Py_XDECREF(keys);
856854
Py_XDECREF(values);
857-
return NULL;
855+
return buffer;
858856
}
859857

860858
static LPHANDLE
@@ -1053,8 +1051,7 @@ _winapi_CreateProcess_impl(PyObject *module,
10531051
BOOL result;
10541052
PROCESS_INFORMATION pi;
10551053
STARTUPINFOEXW si;
1056-
PyObject *environment = NULL;
1057-
wchar_t *wenvironment;
1054+
wchar_t *wenvironment = NULL;
10581055
wchar_t *command_line_copy = NULL;
10591056
AttributeList attribute_list = {0};
10601057

@@ -1071,20 +1068,11 @@ _winapi_CreateProcess_impl(PyObject *module,
10711068
goto cleanup;
10721069

10731070
if (env_mapping != Py_None) {
1074-
environment = getenvironment(env_mapping);
1075-
if (environment == NULL) {
1076-
goto cleanup;
1077-
}
1078-
/* contains embedded null characters */
1079-
wenvironment = PyUnicode_AsUnicode(environment);
1071+
wenvironment = getenvironment(env_mapping);
10801072
if (wenvironment == NULL) {
10811073
goto cleanup;
10821074
}
10831075
}
1084-
else {
1085-
environment = NULL;
1086-
wenvironment = NULL;
1087-
}
10881076

10891077
if (getattributelist(startup_info, "lpAttributeList", &attribute_list) < 0)
10901078
goto cleanup;
@@ -1131,7 +1119,7 @@ _winapi_CreateProcess_impl(PyObject *module,
11311119

11321120
cleanup:
11331121
PyMem_Free(command_line_copy);
1134-
Py_XDECREF(environment);
1122+
PyMem_Free(wenvironment);
11351123
freeattributelist(&attribute_list);
11361124

11371125
return ret;

0 commit comments

Comments
 (0)