Skip to content

Commit e9abde4

Browse files
committed
Add _Py_VaBuildStack() function
Issue #28915: Similar to Py_VaBuildValue(), but work on a C array of PyObject*, instead of creating a tuple.
1 parent b551b6c commit e9abde4

2 files changed

Lines changed: 111 additions & 0 deletions

File tree

Include/modsupport.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,16 @@ extern "C" {
2121
#endif /* !Py_LIMITED_API */
2222
#define Py_BuildValue _Py_BuildValue_SizeT
2323
#define Py_VaBuildValue _Py_VaBuildValue_SizeT
24+
#define _Py_VaBuildStack _Py_VaBuildStack_SizeT
2425
#else
2526
#ifndef Py_LIMITED_API
2627
PyAPI_FUNC(PyObject *) _Py_VaBuildValue_SizeT(const char *, va_list);
28+
PyAPI_FUNC(PyObject **) _Py_VaBuildStack_SizeT(
29+
PyObject **small_stack,
30+
Py_ssize_t small_stack_len,
31+
const char *format,
32+
va_list va,
33+
Py_ssize_t *p_nargs);
2734
#endif /* !Py_LIMITED_API */
2835
#endif
2936

@@ -47,6 +54,12 @@ PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *,
4754
const char *, char **, va_list);
4855
#endif
4956
PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list);
57+
PyAPI_FUNC(PyObject **) _Py_VaBuildStack(
58+
PyObject **small_stack,
59+
Py_ssize_t small_stack_len,
60+
const char *format,
61+
va_list va,
62+
Py_ssize_t *p_nargs);
5063

5164
#ifndef Py_LIMITED_API
5265
typedef struct _PyArg_Parser {

Python/modsupport.c

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
typedef double va_double;
88

99
static PyObject *va_build_value(const char *, va_list, int);
10+
static PyObject **va_build_stack(PyObject **small_stack, Py_ssize_t small_stack_len, const char *, va_list, int, Py_ssize_t*);
1011

1112
/* Package context -- the full module name for package imports */
1213
const char *_Py_PackageContext = NULL;
@@ -60,6 +61,7 @@ countformat(const char *format, char endchar)
6061
/* After an original idea and first implementation by Steven Miale */
6162

6263
static PyObject *do_mktuple(const char**, va_list *, char, Py_ssize_t, int);
64+
static int do_mkstack(PyObject **, const char**, va_list *, char, Py_ssize_t, int);
6365
static PyObject *do_mklist(const char**, va_list *, char, Py_ssize_t, int);
6466
static PyObject *do_mkdict(const char**, va_list *, char, Py_ssize_t, int);
6567
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
182184
return v;
183185
}
184186

187+
static int
188+
do_mkstack(PyObject **stack, const char **p_format, va_list *p_va,
189+
char endchar, Py_ssize_t n, int flags)
190+
{
191+
Py_ssize_t i;
192+
193+
if (n < 0) {
194+
return -1;
195+
}
196+
/* Note that we can't bail immediately on error as this will leak
197+
refcounts on any 'N' arguments. */
198+
for (i = 0; i < n; i++) {
199+
PyObject *w = do_mkvalue(p_format, p_va, flags);
200+
if (w == NULL) {
201+
do_ignore(p_format, p_va, endchar, n - i - 1, flags);
202+
goto error;
203+
}
204+
stack[i] = w;
205+
}
206+
if (**p_format != endchar) {
207+
PyErr_SetString(PyExc_SystemError,
208+
"Unmatched paren in format");
209+
goto error;
210+
}
211+
if (endchar) {
212+
++*p_format;
213+
}
214+
return 0;
215+
216+
error:
217+
n = i;
218+
for (i=0; i < n; i++) {
219+
Py_DECREF(stack[i]);
220+
}
221+
return -1;
222+
}
223+
185224
static PyObject *
186225
do_mktuple(const char **p_format, va_list *p_va, char endchar, Py_ssize_t n, int flags)
187226
{
@@ -488,6 +527,65 @@ va_build_value(const char *format, va_list va, int flags)
488527
return retval;
489528
}
490529

530+
PyObject **
531+
_Py_VaBuildStack(PyObject **small_stack, Py_ssize_t small_stack_len,
532+
const char *format, va_list va, Py_ssize_t *p_nargs)
533+
{
534+
return va_build_stack(small_stack, small_stack_len, format, va, 0, p_nargs);
535+
}
536+
537+
PyObject **
538+
_Py_VaBuildStack_SizeT(PyObject **small_stack, Py_ssize_t small_stack_len,
539+
const char *format, va_list va, Py_ssize_t *p_nargs)
540+
{
541+
return va_build_stack(small_stack, small_stack_len, format, va, FLAG_SIZE_T, p_nargs);
542+
}
543+
544+
static PyObject **
545+
va_build_stack(PyObject **small_stack, Py_ssize_t small_stack_len,
546+
const char *format, va_list va, int flags, Py_ssize_t *p_nargs)
547+
{
548+
const char *f;
549+
Py_ssize_t n;
550+
va_list lva;
551+
PyObject **stack;
552+
int res;
553+
554+
n = countformat(format, '\0');
555+
if (n < 0) {
556+
*p_nargs = 0;
557+
return NULL;
558+
}
559+
560+
if (n == 0) {
561+
*p_nargs = 0;
562+
return small_stack;
563+
}
564+
565+
if (n <= small_stack_len) {
566+
stack = small_stack;
567+
}
568+
else {
569+
stack = PyMem_Malloc(n * sizeof(stack[0]));
570+
if (stack == NULL) {
571+
PyErr_NoMemory();
572+
return NULL;
573+
}
574+
}
575+
576+
va_copy(lva, va);
577+
f = format;
578+
res = do_mkstack(stack, &f, &lva, '\0', n, flags);
579+
va_end(lva);
580+
581+
if (res < 0) {
582+
return NULL;
583+
}
584+
585+
*p_nargs = n;
586+
return stack;
587+
}
588+
491589

492590
PyObject *
493591
PyEval_CallFunction(PyObject *callable, const char *format, ...)

0 commit comments

Comments
 (0)