diff options
Diffstat (limited to 'contrib/tools/python3/Python/getargs.c')
| -rw-r--r-- | contrib/tools/python3/Python/getargs.c | 376 |
1 files changed, 154 insertions, 222 deletions
diff --git a/contrib/tools/python3/Python/getargs.c b/contrib/tools/python3/Python/getargs.c index 0bba8b1d514..13e0ae7c167 100644 --- a/contrib/tools/python3/Python/getargs.c +++ b/contrib/tools/python3/Python/getargs.c @@ -1,56 +1,26 @@ /* New getargs implementation */ +#define PY_CXX_CONST const #include "Python.h" -#include "pycore_tuple.h" // _PyTuple_ITEMS() +#include "pycore_abstract.h" // _PyNumber_Index() +#include "pycore_dict.h" // _PyDict_HasOnlyStringKeys() +#include "pycore_modsupport.h" // export _PyArg_NoKeywords() #include "pycore_pylifecycle.h" // _PyArg_Fini #include "pycore_pystate.h" // _Py_IsMainInterpreter() +#include "pycore_tuple.h" // _PyTuple_ITEMS() +#include "pycore_pyerrors.h" // _Py_CalculateSuggestions() -#include <ctype.h> -#include <float.h> - - -#ifdef __cplusplus -extern "C" { -#endif -int PyArg_Parse(PyObject *, const char *, ...); -int PyArg_ParseTuple(PyObject *, const char *, ...); -int PyArg_VaParse(PyObject *, const char *, va_list); - -int PyArg_ParseTupleAndKeywords(PyObject *, PyObject *, - const char *, char **, ...); -int PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *, - const char *, char **, va_list); - -int _PyArg_ParseTupleAndKeywordsFast(PyObject *, PyObject *, - struct _PyArg_Parser *, ...); -int _PyArg_VaParseTupleAndKeywordsFast(PyObject *, PyObject *, - struct _PyArg_Parser *, va_list); - -#ifdef HAVE_DECLSPEC_DLL -/* Export functions */ +/* Export Stable ABIs (abi only) */ PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, const char *, ...); -PyAPI_FUNC(int) _PyArg_ParseStack_SizeT(PyObject *const *args, Py_ssize_t nargs, - const char *format, ...); -PyAPI_FUNC(int) _PyArg_ParseStackAndKeywords_SizeT(PyObject *const *args, Py_ssize_t nargs, - PyObject *kwnames, - struct _PyArg_Parser *parser, ...); PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, const char *, ...); PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywords_SizeT(PyObject *, PyObject *, - const char *, char **, ...); -PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...); + const char *, const char * const *, ...); PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject *, const char *, va_list); PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *, PyObject *, - const char *, char **, va_list); - -PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywordsFast_SizeT(PyObject *, PyObject *, - struct _PyArg_Parser *, ...); -PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywordsFast_SizeT(PyObject *, PyObject *, - struct _PyArg_Parser *, va_list); -#endif + const char *, const char * const *, va_list); #define FLAG_COMPAT 1 -#define FLAG_SIZE_T 2 typedef int (*destr_t)(PyObject *, void *); @@ -80,14 +50,14 @@ static void seterror(Py_ssize_t, const char *, int *, const char *, const char * static const char *convertitem(PyObject *, const char **, va_list *, int, int *, char *, size_t, freelist_t *); static const char *converttuple(PyObject *, const char **, va_list *, int, - int *, char *, size_t, int, freelist_t *); + int *, char *, size_t, freelist_t *); static const char *convertsimple(PyObject *, const char **, va_list *, int, char *, size_t, freelist_t *); static Py_ssize_t convertbuffer(PyObject *, const void **p, const char **); static int getbuffer(PyObject *, Py_buffer *, const char**); static int vgetargskeywords(PyObject *, PyObject *, - const char *, char **, va_list *, int); + const char *, const char * const *, va_list *, int); static int vgetargskeywordsfast(PyObject *, PyObject *, struct _PyArg_Parser *, va_list *, int); static int vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, @@ -115,7 +85,7 @@ _PyArg_Parse_SizeT(PyObject *args, const char *format, ...) va_list va; va_start(va, format); - retval = vgetargs1(args, format, &va, FLAG_COMPAT|FLAG_SIZE_T); + retval = vgetargs1(args, format, &va, FLAG_COMPAT); va_end(va); return retval; } @@ -133,14 +103,14 @@ PyArg_ParseTuple(PyObject *args, const char *format, ...) return retval; } -PyAPI_FUNC(int) +int _PyArg_ParseTuple_SizeT(PyObject *args, const char *format, ...) { int retval; va_list va; va_start(va, format); - retval = vgetargs1(args, format, &va, FLAG_SIZE_T); + retval = vgetargs1(args, format, &va, 0); va_end(va); return retval; } @@ -158,19 +128,6 @@ _PyArg_ParseStack(PyObject *const *args, Py_ssize_t nargs, const char *format, . return retval; } -PyAPI_FUNC(int) -_PyArg_ParseStack_SizeT(PyObject *const *args, Py_ssize_t nargs, const char *format, ...) -{ - int retval; - va_list va; - - va_start(va, format); - retval = vgetargs1_impl(NULL, args, nargs, format, &va, FLAG_SIZE_T); - va_end(va); - return retval; -} - - int PyArg_VaParse(PyObject *args, const char *format, va_list va) { @@ -184,7 +141,7 @@ PyArg_VaParse(PyObject *args, const char *format, va_list va) return retval; } -PyAPI_FUNC(int) +int _PyArg_VaParse_SizeT(PyObject *args, const char *format, va_list va) { va_list lva; @@ -192,7 +149,7 @@ _PyArg_VaParse_SizeT(PyObject *args, const char *format, va_list va) va_copy(lva, va); - retval = vgetargs1(args, format, &lva, FLAG_SIZE_T); + retval = vgetargs1(args, format, &lva, 0); va_end(lva); return retval; } @@ -500,7 +457,7 @@ seterror(Py_ssize_t iarg, const char *msg, int *levels, const char *fname, static const char * converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, - int *levels, char *msgbuf, size_t bufsize, int toplevel, + int *levels, char *msgbuf, size_t bufsize, freelist_t *freelist) { int level = 0; @@ -530,7 +487,6 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, if (!PySequence_Check(arg) || PyBytes_Check(arg)) { levels[0] = 0; PyOS_snprintf(msgbuf, bufsize, - toplevel ? "expected %d arguments, not %.50s" : "must be %d-item sequence, not %.50s", n, arg == Py_None ? "None" : Py_TYPE(arg)->tp_name); @@ -540,18 +496,9 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, len = PySequence_Size(arg); if (len != n) { levels[0] = 0; - if (toplevel) { - PyOS_snprintf(msgbuf, bufsize, - "expected %d argument%s, not %zd", - n, - n == 1 ? "" : "s", - len); - } - else { - PyOS_snprintf(msgbuf, bufsize, - "must be sequence of length %d, not %zd", - n, len); - } + PyOS_snprintf(msgbuf, bufsize, + "must be sequence of length %d, not %zd", + n, len); return msgbuf; } @@ -594,7 +541,7 @@ convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags, if (*format == '(' /* ')' */) { format++; msg = converttuple(arg, &format, p_va, flags, levels, msgbuf, - bufsize, 0, freelist); + bufsize, freelist); if (msg == NULL) format++; } @@ -658,13 +605,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, char *msgbuf, size_t bufsize, freelist_t *freelist) { #define RETURN_ERR_OCCURRED return msgbuf - /* For # codes */ -#define REQUIRE_PY_SSIZE_T_CLEAN \ - if (!(flags & FLAG_SIZE_T)) { \ - PyErr_SetString(PyExc_SystemError, \ - "PY_SSIZE_T_CLEAN macro must be defined for '#' formats"); \ - RETURN_ERR_OCCURRED; \ - } const char *format = *p_format; char c = *format++; @@ -872,9 +812,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, if (!PyUnicode_Check(arg)) return converterr("a unicode character", arg, msgbuf, bufsize); - if (PyUnicode_READY(arg)) - RETURN_ERR_OCCURRED; - if (PyUnicode_GET_LENGTH(arg) != 1) return converterr("a unicode character", arg, msgbuf, bufsize); @@ -918,7 +855,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, if (count < 0) return converterr(buf, arg, msgbuf, bufsize); if (*format == '#') { - REQUIRE_PY_SSIZE_T_CLEAN; Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*); *psize = count; format++; @@ -962,7 +898,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, } else if (*format == '#') { /* a string or read-only bytes-like object */ /* "s#" or "z#" */ const void **p = (const void **)va_arg(*p_va, const char **); - REQUIRE_PY_SSIZE_T_CLEAN; Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*); if (c == 'z' && arg == Py_None) { @@ -1100,7 +1035,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, trailing 0-byte */ - REQUIRE_PY_SSIZE_T_CLEAN; Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*); format++; @@ -1195,8 +1129,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, case 'U': { /* PyUnicode object */ PyObject **p = va_arg(*p_va, PyObject **); if (PyUnicode_Check(arg)) { - if (PyUnicode_READY(arg) == -1) - RETURN_ERR_OCCURRED; *p = arg; } else @@ -1248,17 +1180,15 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, arg, msgbuf, bufsize); format++; - /* Caller is interested in Py_buffer, and the object - supports it directly. */ + /* Caller is interested in Py_buffer, and the object supports it + directly. The request implicitly asks for PyBUF_SIMPLE, so the + result is C-contiguous with format 'B'. */ if (PyObject_GetBuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) { PyErr_Clear(); return converterr("read-write bytes-like object", arg, msgbuf, bufsize); } - if (!PyBuffer_IsContiguous((Py_buffer*)p, 'C')) { - PyBuffer_Release((Py_buffer*)p); - return converterr("contiguous buffer", arg, msgbuf, bufsize); - } + assert(PyBuffer_IsContiguous((Py_buffer *)p, 'C')); if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", @@ -1275,7 +1205,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, *p_format = format; return NULL; -#undef REQUIRE_PY_SSIZE_T_CLEAN #undef RETURN_ERR_OCCURRED } @@ -1304,15 +1233,12 @@ convertbuffer(PyObject *arg, const void **p, const char **errmsg) static int getbuffer(PyObject *arg, Py_buffer *view, const char **errmsg) { + /* PyBUF_SIMPLE implies C-contiguous */ if (PyObject_GetBuffer(arg, view, PyBUF_SIMPLE) != 0) { *errmsg = "bytes-like object"; return -1; } - if (!PyBuffer_IsContiguous(view, 'C')) { - PyBuffer_Release(view); - *errmsg = "contiguous buffer"; - return -1; - } + assert(PyBuffer_IsContiguous(view, 'C')); return 0; } @@ -1324,7 +1250,7 @@ int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *keywords, const char *format, - char **kwlist, ...) + const char * const *kwlist, ...) { int retval; va_list va; @@ -1344,11 +1270,11 @@ PyArg_ParseTupleAndKeywords(PyObject *args, return retval; } -PyAPI_FUNC(int) +int _PyArg_ParseTupleAndKeywords_SizeT(PyObject *args, PyObject *keywords, const char *format, - char **kwlist, ...) + const char * const *kwlist, ...) { int retval; va_list va; @@ -1364,7 +1290,7 @@ _PyArg_ParseTupleAndKeywords_SizeT(PyObject *args, va_start(va, kwlist); retval = vgetargskeywords(args, keywords, format, - kwlist, &va, FLAG_SIZE_T); + kwlist, &va, 0); va_end(va); return retval; } @@ -1374,7 +1300,7 @@ int PyArg_VaParseTupleAndKeywords(PyObject *args, PyObject *keywords, const char *format, - char **kwlist, va_list va) + const char * const *kwlist, va_list va) { int retval; va_list lva; @@ -1395,11 +1321,11 @@ PyArg_VaParseTupleAndKeywords(PyObject *args, return retval; } -PyAPI_FUNC(int) +int _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args, PyObject *keywords, const char *format, - char **kwlist, va_list va) + const char * const *kwlist, va_list va) { int retval; va_list lva; @@ -1416,7 +1342,7 @@ _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args, va_copy(lva, va); retval = vgetargskeywords(args, keywords, format, - kwlist, &lva, FLAG_SIZE_T); + kwlist, &lva, 0); va_end(lva); return retval; } @@ -1434,7 +1360,7 @@ _PyArg_ParseTupleAndKeywordsFast(PyObject *args, PyObject *keywords, return retval; } -PyAPI_FUNC(int) +int _PyArg_ParseTupleAndKeywordsFast_SizeT(PyObject *args, PyObject *keywords, struct _PyArg_Parser *parser, ...) { @@ -1442,12 +1368,12 @@ _PyArg_ParseTupleAndKeywordsFast_SizeT(PyObject *args, PyObject *keywords, va_list va; va_start(va, parser); - retval = vgetargskeywordsfast(args, keywords, parser, &va, FLAG_SIZE_T); + retval = vgetargskeywordsfast(args, keywords, parser, &va, 0); va_end(va); return retval; } -PyAPI_FUNC(int) +int _PyArg_ParseStackAndKeywords(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames, struct _PyArg_Parser *parser, ...) { @@ -1460,7 +1386,7 @@ _PyArg_ParseStackAndKeywords(PyObject *const *args, Py_ssize_t nargs, PyObject * return retval; } -PyAPI_FUNC(int) +int _PyArg_ParseStackAndKeywords_SizeT(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames, struct _PyArg_Parser *parser, ...) { @@ -1468,40 +1394,12 @@ _PyArg_ParseStackAndKeywords_SizeT(PyObject *const *args, Py_ssize_t nargs, PyOb va_list va; va_start(va, parser); - retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va, FLAG_SIZE_T); + retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va, 0); va_end(va); return retval; } -PyAPI_FUNC(int) -_PyArg_VaParseTupleAndKeywordsFast(PyObject *args, PyObject *keywords, - struct _PyArg_Parser *parser, va_list va) -{ - int retval; - va_list lva; - - va_copy(lva, va); - - retval = vgetargskeywordsfast(args, keywords, parser, &lva, 0); - va_end(lva); - return retval; -} - -PyAPI_FUNC(int) -_PyArg_VaParseTupleAndKeywordsFast_SizeT(PyObject *args, PyObject *keywords, - struct _PyArg_Parser *parser, va_list va) -{ - int retval; - va_list lva; - - va_copy(lva, va); - - retval = vgetargskeywordsfast(args, keywords, parser, &lva, FLAG_SIZE_T); - va_end(lva); - return retval; -} - static void error_unexpected_keyword_arg(PyObject *kwargs, PyObject *kwnames, PyObject *kwtuple, const char *fname) { @@ -1528,12 +1426,31 @@ error_unexpected_keyword_arg(PyObject *kwargs, PyObject *kwnames, PyObject *kwtu int match = PySequence_Contains(kwtuple, keyword); if (match <= 0) { if (!match) { - PyErr_Format(PyExc_TypeError, - "'%S' is an invalid keyword " - "argument for %.200s%s", - keyword, - (fname == NULL) ? "this function" : fname, - (fname == NULL) ? "" : "()"); + PyObject *kwlist = PySequence_List(kwtuple); + if (!kwlist) { + return; + } + PyObject *suggestion_keyword = _Py_CalculateSuggestions(kwlist, keyword); + Py_DECREF(kwlist); + + if (suggestion_keyword) { + PyErr_Format(PyExc_TypeError, + "%.200s%s got an unexpected keyword argument '%S'." + " Did you mean '%S'?", + (fname == NULL) ? "this function" : fname, + (fname == NULL) ? "" : "()", + keyword, + suggestion_keyword); + Py_DECREF(suggestion_keyword); + } + else { + PyErr_Format(PyExc_TypeError, + "%.200s%s got an unexpected keyword argument '%S'", + (fname == NULL) ? "this function" : fname, + (fname == NULL) ? "" : "()", + keyword); + } + } return; } @@ -1561,11 +1478,14 @@ PyArg_ValidateKeywordArguments(PyObject *kwargs) return 1; } +static PyObject * +new_kwtuple(const char * const *keywords, int total, int pos); + #define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':') static int vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, - char **kwlist, va_list *p_va, int flags) + const char * const *kwlist, va_list *p_va, int flags) { char msgbuf[512]; int levels[32]; @@ -1575,7 +1495,6 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, int i, pos, len; int skip = 0; Py_ssize_t nargs, nkwargs; - PyObject *current_arg; freelistentry_t static_entries[STATIC_FREELIST_ENTRIES]; freelist_t freelist; @@ -1705,17 +1624,17 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, return cleanreturn(0, &freelist); } if (!skip) { + PyObject *current_arg; if (i < nargs) { - current_arg = PyTuple_GET_ITEM(args, i); + current_arg = Py_NewRef(PyTuple_GET_ITEM(args, i)); } else if (nkwargs && i >= pos) { - current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]); + if (PyDict_GetItemStringRef(kwargs, kwlist[i], ¤t_arg) < 0) { + return cleanreturn(0, &freelist); + } if (current_arg) { --nkwargs; } - else if (PyErr_Occurred()) { - return cleanreturn(0, &freelist); - } } else { current_arg = NULL; @@ -1724,6 +1643,7 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, if (current_arg) { msg = convertitem(current_arg, &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); + Py_DECREF(current_arg); if (msg) { seterror(i+1, msg, levels, fname, custom_msg); return cleanreturn(0, &freelist); @@ -1794,8 +1714,12 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, Py_ssize_t j; /* make sure there are no arguments given by name and position */ for (i = pos; i < nargs; i++) { - current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]); + PyObject *current_arg; + if (PyDict_GetItemStringRef(kwargs, kwlist[i], ¤t_arg) < 0) { + return cleanreturn(0, &freelist); + } if (current_arg) { + Py_DECREF(current_arg); /* arg present in tuple and in dict */ PyErr_Format(PyExc_TypeError, "argument for %.200s%s given by name ('%s') " @@ -1805,9 +1729,6 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, kwlist[i], i+1); return cleanreturn(0, &freelist); } - else if (PyErr_Occurred()) { - return cleanreturn(0, &freelist); - } } /* make sure there are no extraneous keyword arguments */ j = 0; @@ -1819,18 +1740,41 @@ vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, return cleanreturn(0, &freelist); } for (i = pos; i < len; i++) { - if (_PyUnicode_EqualToASCIIString(key, kwlist[i])) { + if (PyUnicode_EqualToUTF8(key, kwlist[i])) { match = 1; break; } } if (!match) { - PyErr_Format(PyExc_TypeError, - "'%U' is an invalid keyword " - "argument for %.200s%s", - key, - (fname == NULL) ? "this function" : fname, - (fname == NULL) ? "" : "()"); + PyObject *_pykwtuple = new_kwtuple(kwlist, len, pos); + if (!_pykwtuple) { + return cleanreturn(0, &freelist); + } + PyObject *pykwlist = PySequence_List(_pykwtuple); + Py_DECREF(_pykwtuple); + if (!pykwlist) { + return cleanreturn(0, &freelist); + } + PyObject *suggestion_keyword = _Py_CalculateSuggestions(pykwlist, key); + Py_DECREF(pykwlist); + + if (suggestion_keyword) { + PyErr_Format(PyExc_TypeError, + "%.200s%s got an unexpected keyword argument '%S'." + " Did you mean '%S'?", + (fname == NULL) ? "this function" : fname, + (fname == NULL) ? "" : "()", + key, + suggestion_keyword); + Py_DECREF(suggestion_keyword); + } + else { + PyErr_Format(PyExc_TypeError, + "%.200s%s got an unexpected keyword argument '%S'", + (fname == NULL) ? "this function" : fname, + (fname == NULL) ? "" : "()", + key); + } return cleanreturn(0, &freelist); } } @@ -1972,8 +1916,9 @@ new_kwtuple(const char * const *keywords, int total, int pos) } static int -_parser_init(struct _PyArg_Parser *parser) +_parser_init(void *arg) { + struct _PyArg_Parser *parser = (struct _PyArg_Parser *)arg; const char * const *keywords = parser->keywords; assert(keywords != NULL); assert(parser->pos == 0 && @@ -1984,7 +1929,7 @@ _parser_init(struct _PyArg_Parser *parser) int len, pos; if (scan_keywords(keywords, &len, &pos) < 0) { - return 0; + return -1; } const char *fname, *custommsg = NULL; @@ -1993,7 +1938,7 @@ _parser_init(struct _PyArg_Parser *parser) assert(parser->fname == NULL); if (parse_format(parser->format, len, pos, &fname, &custommsg, &min, &max) < 0) { - return 0; + return -1; } } else { @@ -2022,7 +1967,7 @@ _parser_init(struct _PyArg_Parser *parser) PyThreadState_Delete(temp_tstate); } if (kwtuple == NULL) { - return 0; + return -1; } owned = 1; } @@ -2036,40 +1981,27 @@ _parser_init(struct _PyArg_Parser *parser) parser->min = min; parser->max = max; parser->kwtuple = kwtuple; - parser->initialized = owned ? 1 : -1; + parser->is_kwtuple_owned = owned; assert(parser->next == NULL); - parser->next = _PyRuntime.getargs.static_parsers; - _PyRuntime.getargs.static_parsers = parser; - return 1; + parser->next = _Py_atomic_load_ptr(&_PyRuntime.getargs.static_parsers); + do { + // compare-exchange updates parser->next on failure + } while (!_Py_atomic_compare_exchange_ptr(&_PyRuntime.getargs.static_parsers, + &parser->next, parser)); + return 0; } static int parser_init(struct _PyArg_Parser *parser) { - // volatile as it can be modified by other threads - // and should not be optimized or reordered by compiler - if (*((volatile int *)&parser->initialized)) { - assert(parser->kwtuple != NULL); - return 1; - } - PyThread_acquire_lock(_PyRuntime.getargs.mutex, WAIT_LOCK); - // Check again if another thread initialized the parser - // while we were waiting for the lock. - if (*((volatile int *)&parser->initialized)) { - assert(parser->kwtuple != NULL); - PyThread_release_lock(_PyRuntime.getargs.mutex); - return 1; - } - int ret = _parser_init(parser); - PyThread_release_lock(_PyRuntime.getargs.mutex); - return ret; + return _PyOnceFlag_CallOnce(&parser->once, &_parser_init, parser); } static void parser_clear(struct _PyArg_Parser *parser) { - if (parser->initialized == 1) { + if (parser->is_kwtuple_owned) { Py_CLEAR(parser->kwtuple); } @@ -2083,7 +2015,8 @@ parser_clear(struct _PyArg_Parser *parser) parser->pos = 0; parser->min = 0; parser->max = 0; - parser->initialized = 0; + parser->is_kwtuple_owned = 0; + parser->once.v = 0; } static PyObject* @@ -2098,7 +2031,7 @@ find_keyword(PyObject *kwnames, PyObject *const *kwstack, PyObject *key) /* kwname == key will normally find a match in since keyword keys should be interned strings; if not retry below in a new loop. */ if (kwname == key) { - return kwstack[i]; + return Py_NewRef(kwstack[i]); } } @@ -2106,7 +2039,7 @@ find_keyword(PyObject *kwnames, PyObject *const *kwstack, PyObject *key) PyObject *kwname = PyTuple_GET_ITEM(kwnames, i); assert(PyUnicode_Check(kwname)); if (_PyUnicode_EQ(kwname, key)) { - return kwstack[i]; + return Py_NewRef(kwstack[i]); } } return NULL; @@ -2126,7 +2059,6 @@ vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, PyObject *keyword; int i, pos, len; Py_ssize_t nkwargs; - PyObject *current_arg; freelistentry_t static_entries[STATIC_FREELIST_ENTRIES]; freelist_t freelist; PyObject *const *kwstack = NULL; @@ -2149,7 +2081,7 @@ vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, return 0; } - if (!parser_init(parser)) { + if (parser_init(parser) < 0) { return 0; } @@ -2221,14 +2153,14 @@ vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, } assert(!IS_END_OF_FORMAT(*format)); + PyObject *current_arg; if (i < nargs) { - current_arg = args[i]; + current_arg = Py_NewRef(args[i]); } else if (nkwargs && i >= pos) { keyword = PyTuple_GET_ITEM(kwtuple, i - pos); if (kwargs != NULL) { - current_arg = PyDict_GetItemWithError(kwargs, keyword); - if (!current_arg && PyErr_Occurred()) { + if (PyDict_GetItemRef(kwargs, keyword, ¤t_arg) < 0) { return cleanreturn(0, &freelist); } } @@ -2246,6 +2178,7 @@ vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, if (current_arg) { msg = convertitem(current_arg, &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); + Py_DECREF(current_arg); if (msg) { seterror(i+1, msg, levels, parser->fname, parser->custom_msg); return cleanreturn(0, &freelist); @@ -2256,7 +2189,7 @@ vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, if (i < parser->min) { /* Less arguments than required */ if (i < pos) { - Py_ssize_t min = Py_MIN(pos, parser->min); + int min = Py_MIN(pos, parser->min); PyErr_Format(PyExc_TypeError, "%.200s%s takes %s %d positional argument%s" " (%zd given)", @@ -2296,10 +2229,10 @@ vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, if (nkwargs > 0) { /* make sure there are no arguments given by name and position */ for (i = pos; i < nargs; i++) { + PyObject *current_arg; keyword = PyTuple_GET_ITEM(kwtuple, i - pos); if (kwargs != NULL) { - current_arg = PyDict_GetItemWithError(kwargs, keyword); - if (!current_arg && PyErr_Occurred()) { + if (PyDict_GetItemRef(kwargs, keyword, ¤t_arg) < 0) { return cleanreturn(0, &freelist); } } @@ -2307,6 +2240,7 @@ vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs, current_arg = find_keyword(kwnames, kwstack, keyword); } if (current_arg) { + Py_DECREF(current_arg); /* arg present in tuple and in dict */ PyErr_Format(PyExc_TypeError, "argument for %.200s%s given by name ('%U') " @@ -2361,7 +2295,6 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, int i, posonly, minposonly, maxargs; int reqlimit = minkw ? maxpos + minkw : minpos; Py_ssize_t nkwargs; - PyObject *current_arg; PyObject * const *kwstack = NULL; assert(kwargs == NULL || PyDict_Check(kwargs)); @@ -2381,7 +2314,7 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, args = buf; } - if (!parser_init(parser)) { + if (parser_init(parser) < 0) { return NULL; } @@ -2456,11 +2389,11 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, /* copy keyword args using kwtuple to drive process */ for (i = Py_MAX((int)nargs, posonly); i < maxargs; i++) { + PyObject *current_arg; if (nkwargs) { keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); if (kwargs != NULL) { - current_arg = PyDict_GetItemWithError(kwargs, keyword); - if (!current_arg && PyErr_Occurred()) { + if (PyDict_GetItemRef(kwargs, keyword, ¤t_arg) < 0) { return NULL; } } @@ -2478,6 +2411,7 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, buf[i] = current_arg; if (current_arg) { + Py_DECREF(current_arg); --nkwargs; } else if (i < minpos || (maxpos <= i && i < reqlimit)) { @@ -2495,10 +2429,10 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, if (nkwargs > 0) { /* make sure there are no arguments given by name and position */ for (i = posonly; i < nargs; i++) { + PyObject *current_arg; keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); if (kwargs != NULL) { - current_arg = PyDict_GetItemWithError(kwargs, keyword); - if (!current_arg && PyErr_Occurred()) { + if (PyDict_GetItemRef(kwargs, keyword, ¤t_arg) < 0) { return NULL; } } @@ -2506,6 +2440,7 @@ _PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs, current_arg = find_keyword(kwnames, kwstack, keyword); } if (current_arg) { + Py_DECREF(current_arg); /* arg present in tuple and in dict */ PyErr_Format(PyExc_TypeError, "argument for %.200s%s given by name ('%U') " @@ -2537,7 +2472,6 @@ _PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs, int i, posonly, minposonly, maxargs; int reqlimit = minkw ? maxpos + minkw : minpos; Py_ssize_t nkwargs; - PyObject *current_arg; PyObject * const *kwstack = NULL; assert(kwargs == NULL || PyDict_Check(kwargs)); @@ -2557,7 +2491,7 @@ _PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs, args = buf; } - if (!parser_init(parser)) { + if (parser_init(parser) < 0) { return NULL; } @@ -2610,13 +2544,12 @@ _PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs, } /* copy keyword args using kwtuple to drive process */ - for (i = Py_MAX((int)nargs, posonly) - - Py_SAFE_DOWNCAST(varargssize, Py_ssize_t, int); i < maxargs; i++) { + for (i = Py_MAX((int)nargs, posonly) - Py_SAFE_DOWNCAST(varargssize, Py_ssize_t, int); i < maxargs; i++) { + PyObject *current_arg; if (nkwargs) { keyword = PyTuple_GET_ITEM(kwtuple, i - posonly); if (kwargs != NULL) { - current_arg = PyDict_GetItemWithError(kwargs, keyword); - if (!current_arg && PyErr_Occurred()) { + if (PyDict_GetItemRef(kwargs, keyword, ¤t_arg) < 0) { goto exit; } } @@ -2649,6 +2582,7 @@ _PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs, } if (current_arg) { + Py_DECREF(current_arg); --nkwargs; } else if (i < minpos || (maxpos <= i && i < reqlimit)) { @@ -2738,11 +2672,13 @@ skipitem(const char **p_format, va_list *p_va, int flags) if (p_va != NULL) { (void) va_arg(*p_va, char **); } + if (c == 'w' && *format != '*') + { + /* after 'w', only '*' is allowed */ + goto err; + } if (*format == '#') { if (p_va != NULL) { - if (!(flags & FLAG_SIZE_T)) { - return "PY_SSIZE_T_CLEAN macro must be defined for '#' formats"; - } (void) va_arg(*p_va, Py_ssize_t *); } format++; @@ -2984,7 +2920,3 @@ _PyArg_Fini(void) } _PyRuntime.getargs.static_parsers = NULL; } - -#ifdef __cplusplus -}; -#endif |
