@@ -182,6 +182,88 @@ _is_fd_in_sorted_fd_sequence(int fd, int *fd_sequence,
182182 return 0 ;
183183}
184184
185+
186+ // Forward declaration
187+ static void _Py_FreeCharPArray (char * const array []);
188+
189+ /*
190+ * Flatten a sequence of bytes() objects into a C array of
191+ * NULL terminated string pointers with a NULL char* terminating the array.
192+ * (ie: an argv or env list)
193+ *
194+ * Memory allocated for the returned list is allocated using PyMem_Malloc()
195+ * and MUST be freed by _Py_FreeCharPArray().
196+ */
197+ static char * const *
198+ _PySequence_BytesToCharpArray (PyObject * self )
199+ {
200+ char * * array ;
201+ Py_ssize_t i , argc ;
202+ PyObject * item = NULL ;
203+ Py_ssize_t size ;
204+
205+ argc = PySequence_Size (self );
206+ if (argc == -1 )
207+ return NULL ;
208+
209+ assert (argc >= 0 );
210+
211+ if ((size_t )argc > (PY_SSIZE_T_MAX - sizeof (char * )) / sizeof (char * )) {
212+ PyErr_NoMemory ();
213+ return NULL ;
214+ }
215+
216+ array = PyMem_Malloc ((argc + 1 ) * sizeof (char * ));
217+ if (array == NULL ) {
218+ PyErr_NoMemory ();
219+ return NULL ;
220+ }
221+ for (i = 0 ; i < argc ; ++ i ) {
222+ char * data ;
223+ item = PySequence_GetItem (self , i );
224+ if (item == NULL ) {
225+ /* NULL terminate before freeing. */
226+ array [i ] = NULL ;
227+ goto fail ;
228+ }
229+ /* check for embedded null bytes */
230+ if (PyBytes_AsStringAndSize (item , & data , NULL ) < 0 ) {
231+ /* NULL terminate before freeing. */
232+ array [i ] = NULL ;
233+ goto fail ;
234+ }
235+ size = PyBytes_GET_SIZE (item ) + 1 ;
236+ array [i ] = PyMem_Malloc (size );
237+ if (!array [i ]) {
238+ PyErr_NoMemory ();
239+ goto fail ;
240+ }
241+ memcpy (array [i ], data , size );
242+ Py_DECREF (item );
243+ }
244+ array [argc ] = NULL ;
245+
246+ return array ;
247+
248+ fail :
249+ Py_XDECREF (item );
250+ _Py_FreeCharPArray (array );
251+ return NULL ;
252+ }
253+
254+
255+ /* Free's a NULL terminated char** array of C strings. */
256+ static void
257+ _Py_FreeCharPArray (char * const array [])
258+ {
259+ Py_ssize_t i ;
260+ for (i = 0 ; array [i ] != NULL ; ++ i ) {
261+ PyMem_Free (array [i ]);
262+ }
263+ PyMem_Free ((void * )array );
264+ }
265+
266+
185267/*
186268 * Do all the Python C API calls in the parent process to turn the pass_fds
187269 * "py_fds_to_keep" tuple into a C array. The caller owns allocation and
0 commit comments