From 7ca871634e7ae8b9c295df5c2154338d2dac1e69 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 26 Jun 2023 08:30:59 +0200 Subject: gh-106084: Remove _PySequence_BytesToCharpArray() function (#106088) Remove private _PySequence_BytesToCharpArray() and _Py_FreeCharPArray() functions from the public C API: move these functions from Objects/abstract.c to Modules/_posixsubprocess.c. --- Include/cpython/abstract.h | 4 --- Modules/_posixsubprocess.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++ Objects/abstract.c | 77 ------------------------------------------- 3 files changed, 82 insertions(+), 81 deletions(-) diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h index abae3e4..5d2d2af 100644 --- a/Include/cpython/abstract.h +++ b/Include/cpython/abstract.h @@ -171,10 +171,6 @@ PyAPI_FUNC(int) _PyObject_RealIsInstance(PyObject *inst, PyObject *cls); PyAPI_FUNC(int) _PyObject_RealIsSubclass(PyObject *derived, PyObject *cls); -PyAPI_FUNC(char *const *) _PySequence_BytesToCharpArray(PyObject* self); - -PyAPI_FUNC(void) _Py_FreeCharPArray(char *const array[]); - /* For internal use by buffer API functions */ PyAPI_FUNC(void) _Py_add_one_to_index_F(int nd, Py_ssize_t *index, const Py_ssize_t *shape); diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index 2d88f5e..52e1d2f 100644 --- a/Modules/_posixsubprocess.c +++ b/Modules/_posixsubprocess.c @@ -182,6 +182,88 @@ _is_fd_in_sorted_fd_sequence(int fd, int *fd_sequence, return 0; } + +// Forward declaration +static void _Py_FreeCharPArray(char *const array[]); + +/* + * Flatten a sequence of bytes() objects into a C array of + * NULL terminated string pointers with a NULL char* terminating the array. + * (ie: an argv or env list) + * + * Memory allocated for the returned list is allocated using PyMem_Malloc() + * and MUST be freed by _Py_FreeCharPArray(). + */ +static char *const * +_PySequence_BytesToCharpArray(PyObject* self) +{ + char **array; + Py_ssize_t i, argc; + PyObject *item = NULL; + Py_ssize_t size; + + argc = PySequence_Size(self); + if (argc == -1) + return NULL; + + assert(argc >= 0); + + if ((size_t)argc > (PY_SSIZE_T_MAX-sizeof(char *)) / sizeof(char *)) { + PyErr_NoMemory(); + return NULL; + } + + array = PyMem_Malloc((argc + 1) * sizeof(char *)); + if (array == NULL) { + PyErr_NoMemory(); + return NULL; + } + for (i = 0; i < argc; ++i) { + char *data; + item = PySequence_GetItem(self, i); + if (item == NULL) { + /* NULL terminate before freeing. */ + array[i] = NULL; + goto fail; + } + /* check for embedded null bytes */ + if (PyBytes_AsStringAndSize(item, &data, NULL) < 0) { + /* NULL terminate before freeing. */ + array[i] = NULL; + goto fail; + } + size = PyBytes_GET_SIZE(item) + 1; + array[i] = PyMem_Malloc(size); + if (!array[i]) { + PyErr_NoMemory(); + goto fail; + } + memcpy(array[i], data, size); + Py_DECREF(item); + } + array[argc] = NULL; + + return array; + +fail: + Py_XDECREF(item); + _Py_FreeCharPArray(array); + return NULL; +} + + +/* Free's a NULL terminated char** array of C strings. */ +static void +_Py_FreeCharPArray(char *const array[]) +{ + Py_ssize_t i; + for (i = 0; array[i] != NULL; ++i) { + PyMem_Free(array[i]); + } + PyMem_Free((void*)array); +} + + /* * Do all the Python C API calls in the parent process to turn the pass_fds * "py_fds_to_keep" tuple into a C array. The caller owns allocation and diff --git a/Objects/abstract.c b/Objects/abstract.c index 00087bd..fecdb4e 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2906,80 +2906,3 @@ PyIter_Send(PyObject *iter, PyObject *arg, PyObject **result) } return PYGEN_ERROR; } - -/* - * Flatten a sequence of bytes() objects into a C array of - * NULL terminated string pointers with a NULL char* terminating the array. - * (ie: an argv or env list) - * - * Memory allocated for the returned list is allocated using PyMem_Malloc() - * and MUST be freed by _Py_FreeCharPArray(). - */ -char *const * -_PySequence_BytesToCharpArray(PyObject* self) -{ - char **array; - Py_ssize_t i, argc; - PyObject *item = NULL; - Py_ssize_t size; - - argc = PySequence_Size(self); - if (argc == -1) - return NULL; - - assert(argc >= 0); - - if ((size_t)argc > (PY_SSIZE_T_MAX-sizeof(char *)) / sizeof(char *)) { - PyErr_NoMemory(); - return NULL; - } - - array = PyMem_Malloc((argc + 1) * sizeof(char *)); - if (array == NULL) { - PyErr_NoMemory(); - return NULL; - } - for (i = 0; i < argc; ++i) { - char *data; - item = PySequence_GetItem(self, i); - if (item == NULL) { - /* NULL terminate before freeing. */ - array[i] = NULL; - goto fail; - } - /* check for embedded null bytes */ - if (PyBytes_AsStringAndSize(item, &data, NULL) < 0) { - /* NULL terminate before freeing. */ - array[i] = NULL; - goto fail; - } - size = PyBytes_GET_SIZE(item) + 1; - array[i] = PyMem_Malloc(size); - if (!array[i]) { - PyErr_NoMemory(); - goto fail; - } - memcpy(array[i], data, size); - Py_DECREF(item); - } - array[argc] = NULL; - - return array; - -fail: - Py_XDECREF(item); - _Py_FreeCharPArray(array); - return NULL; -} - - -/* Free's a NULL terminated char** array of C strings. */ -void -_Py_FreeCharPArray(char *const array[]) -{ - Py_ssize_t i; - for (i = 0; array[i] != NULL; ++i) { - PyMem_Free(array[i]); - } - PyMem_Free((void*)array); -} -- cgit v0.12