summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/Python/getargs.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tools/python3/Python/getargs.c')
-rw-r--r--contrib/tools/python3/Python/getargs.c376
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], &current_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], &current_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, &current_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, &current_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, &current_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, &current_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, &current_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