diff --git a/Include/modsupport.h b/Include/modsupport.h index 39be12864a3..46f548228e8 100644 --- a/Include/modsupport.h +++ b/Include/modsupport.h @@ -21,9 +21,16 @@ extern "C" { #endif /* !Py_LIMITED_API */ #define Py_BuildValue _Py_BuildValue_SizeT #define Py_VaBuildValue _Py_VaBuildValue_SizeT +#define _Py_VaBuildStack _Py_VaBuildStack_SizeT #else #ifndef Py_LIMITED_API PyAPI_FUNC(PyObject *) _Py_VaBuildValue_SizeT(const char *, va_list); +PyAPI_FUNC(PyObject **) _Py_VaBuildStack_SizeT( + PyObject **small_stack, + Py_ssize_t small_stack_len, + const char *format, + va_list va, + Py_ssize_t *p_nargs); #endif /* !Py_LIMITED_API */ #endif @@ -47,6 +54,12 @@ PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *, const char *, char **, va_list); #endif PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list); +PyAPI_FUNC(PyObject **) _Py_VaBuildStack( + PyObject **small_stack, + Py_ssize_t small_stack_len, + const char *format, + va_list va, + Py_ssize_t *p_nargs); #ifndef Py_LIMITED_API typedef struct _PyArg_Parser { diff --git a/Python/modsupport.c b/Python/modsupport.c index eef79c460fa..01b5dc9dda0 100644 --- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -7,6 +7,7 @@ typedef double va_double; static PyObject *va_build_value(const char *, va_list, int); +static PyObject **va_build_stack(PyObject **small_stack, Py_ssize_t small_stack_len, const char *, va_list, int, Py_ssize_t*); /* Package context -- the full module name for package imports */ const char *_Py_PackageContext = NULL; @@ -60,6 +61,7 @@ countformat(const char *format, char endchar) /* After an original idea and first implementation by Steven Miale */ static PyObject *do_mktuple(const char**, va_list *, char, Py_ssize_t, int); +static int do_mkstack(PyObject **, const char**, va_list *, char, Py_ssize_t, int); static PyObject *do_mklist(const char**, va_list *, char, Py_ssize_t, int); static PyObject *do_mkdict(const char**, va_list *, char, Py_ssize_t, int); static PyObject *do_mkvalue(const char**, va_list *, int); @@ -182,6 +184,43 @@ do_mklist(const char **p_format, va_list *p_va, char endchar, Py_ssize_t n, int return v; } +static int +do_mkstack(PyObject **stack, const char **p_format, va_list *p_va, + char endchar, Py_ssize_t n, int flags) +{ + Py_ssize_t i; + + if (n < 0) { + return -1; + } + /* Note that we can't bail immediately on error as this will leak + refcounts on any 'N' arguments. */ + for (i = 0; i < n; i++) { + PyObject *w = do_mkvalue(p_format, p_va, flags); + if (w == NULL) { + do_ignore(p_format, p_va, endchar, n - i - 1, flags); + goto error; + } + stack[i] = w; + } + if (**p_format != endchar) { + PyErr_SetString(PyExc_SystemError, + "Unmatched paren in format"); + goto error; + } + if (endchar) { + ++*p_format; + } + return 0; + +error: + n = i; + for (i=0; i < n; i++) { + Py_DECREF(stack[i]); + } + return -1; +} + static PyObject * do_mktuple(const char **p_format, va_list *p_va, char endchar, Py_ssize_t n, int flags) { @@ -488,6 +527,65 @@ va_build_value(const char *format, va_list va, int flags) return retval; } +PyObject ** +_Py_VaBuildStack(PyObject **small_stack, Py_ssize_t small_stack_len, + const char *format, va_list va, Py_ssize_t *p_nargs) +{ + return va_build_stack(small_stack, small_stack_len, format, va, 0, p_nargs); +} + +PyObject ** +_Py_VaBuildStack_SizeT(PyObject **small_stack, Py_ssize_t small_stack_len, + const char *format, va_list va, Py_ssize_t *p_nargs) +{ + return va_build_stack(small_stack, small_stack_len, format, va, FLAG_SIZE_T, p_nargs); +} + +static PyObject ** +va_build_stack(PyObject **small_stack, Py_ssize_t small_stack_len, + const char *format, va_list va, int flags, Py_ssize_t *p_nargs) +{ + const char *f; + Py_ssize_t n; + va_list lva; + PyObject **stack; + int res; + + n = countformat(format, '\0'); + if (n < 0) { + *p_nargs = 0; + return NULL; + } + + if (n == 0) { + *p_nargs = 0; + return small_stack; + } + + if (n <= small_stack_len) { + stack = small_stack; + } + else { + stack = PyMem_Malloc(n * sizeof(stack[0])); + if (stack == NULL) { + PyErr_NoMemory(); + return NULL; + } + } + + va_copy(lva, va); + f = format; + res = do_mkstack(stack, &f, &lva, '\0', n, flags); + va_end(lva); + + if (res < 0) { + return NULL; + } + + *p_nargs = n; + return stack; +} + PyObject * PyEval_CallFunction(PyObject *callable, const char *format, ...)