From ffbf24bf0cc297d080d6d68bc809a9c156c49123 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 22 Feb 2011 20:15:44 +0000 Subject: Issue #8914: fix various warnings from the Clang static analyzer v254. --- Python/getargs.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index 600941d9c7..17d5993c8a 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -966,9 +966,10 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, case 'u': /* raw unicode buffer (Py_UNICODE *) */ case 'Z': /* raw unicode buffer or None */ { + Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **); + if (*format == '#') { /* any buffer-like object */ /* "s#" or "Z#" */ - Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **); FETCH_SIZE; if (c == 'Z' && arg == Py_None) { @@ -984,8 +985,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, format++; } else { /* "s" or "Z" */ - Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **); - if (c == 'Z' && arg == Py_None) *p = NULL; else if (PyUnicode_Check(arg)) { -- cgit v1.2.1 From 4f56cb4c86c3b5ea71e14326dd3fe8aa0e447a34 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 2 Mar 2011 01:03:11 +0000 Subject: Remove useless argument of _PyUnicode_AsDefaultEncodedString() --- Python/getargs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index 17d5993c8a..e1cef0cc58 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -551,7 +551,7 @@ convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags, #define UNICODE_DEFAULT_ENCODING(arg) \ - _PyUnicode_AsDefaultEncodedString(arg, NULL) + _PyUnicode_AsDefaultEncodedString(arg) /* Format an error message generated by convertsimple(). */ -- cgit v1.2.1 From 537925e7a1a167720d29146e27275efae5b2f69d Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 21 Mar 2011 18:15:42 +0100 Subject: Issue #10833: Use PyErr_Format() and PyUnicode_FromFormat() instead of PyOS_snprintf() to avoid temporary buffer allocated on the stack and a conversion from bytes to Unicode. --- Python/getargs.c | 48 ++++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index e1cef0cc58..4b57153b88 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -310,20 +310,18 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) if (max == 0) { if (args == NULL) return 1; - PyOS_snprintf(msgbuf, sizeof(msgbuf), - "%.200s%s takes no arguments", - fname==NULL ? "function" : fname, - fname==NULL ? "" : "()"); - PyErr_SetString(PyExc_TypeError, msgbuf); + PyErr_Format(PyExc_TypeError, + "%.200s%s takes no arguments", + fname==NULL ? "function" : fname, + fname==NULL ? "" : "()"); return 0; } else if (min == 1 && max == 1) { if (args == NULL) { - PyOS_snprintf(msgbuf, sizeof(msgbuf), - "%.200s%s takes at least one argument", - fname==NULL ? "function" : fname, - fname==NULL ? "" : "()"); - PyErr_SetString(PyExc_TypeError, msgbuf); + PyErr_Format(PyExc_TypeError, + "%.200s%s takes at least one argument", + fname==NULL ? "function" : fname, + fname==NULL ? "" : "()"); return 0; } msg = convertitem(args, &format, p_va, flags, levels, @@ -349,20 +347,18 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) len = PyTuple_GET_SIZE(args); if (len < min || max < len) { - if (message == NULL) { - PyOS_snprintf(msgbuf, sizeof(msgbuf), - "%.150s%s takes %s %d argument%s " - "(%ld given)", - fname==NULL ? "function" : fname, - fname==NULL ? "" : "()", - min==max ? "exactly" - : len < min ? "at least" : "at most", - len < min ? min : max, - (len < min ? min : max) == 1 ? "" : "s", - Py_SAFE_DOWNCAST(len, Py_ssize_t, long)); - message = msgbuf; - } - PyErr_SetString(PyExc_TypeError, message); + if (message == NULL) + PyErr_Format(PyExc_TypeError, + "%.150s%s takes %s %d argument%s (%ld given)", + fname==NULL ? "function" : fname, + fname==NULL ? "" : "()", + min==max ? "exactly" + : len < min ? "at least" : "at most", + len < min ? min : max, + (len < min ? min : max) == 1 ? "" : "s", + Py_SAFE_DOWNCAST(len, Py_ssize_t, long)); + else + PyErr_SetString(PyExc_TypeError, message); return 0; } @@ -1458,8 +1454,8 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, nargs = PyTuple_GET_SIZE(args); nkeywords = (keywords == NULL) ? 0 : PyDict_Size(keywords); if (nargs + nkeywords > len) { - PyErr_Format(PyExc_TypeError, "%s%s takes at most %d " - "argument%s (%d given)", + PyErr_Format(PyExc_TypeError, + "%s%s takes at most %d argument%s (%d given)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", len, -- cgit v1.2.1 From 9efd2ec8bde1aa42298194474edd5b1c0bdcffbf Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Fri, 29 Jul 2011 07:05:08 +0300 Subject: Issue #12380: PyArg_ParseTuple now accepts a bytearray for the 'c' format. As a side effect, this now allows the rjust, ljust and center methods of bytes and bytearray to accept a bytearray argument. Patch by Petri Lehtinen --- Python/getargs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index 4b57153b88..c3da368604 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -828,6 +828,8 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, char *p = va_arg(*p_va, char *); if (PyBytes_Check(arg) && PyBytes_Size(arg) == 1) *p = PyBytes_AS_STRING(arg)[0]; + else if (PyByteArray_Check(arg) && PyByteArray_Size(arg) == 1) + *p = PyByteArray_AS_STRING(arg)[0]; else return converterr("a byte string of length 1", arg, msgbuf, bufsize); break; -- cgit v1.2.1 From d1d013c01c268d869597b35cbcd8b5d7c5baf2ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20v=2E=20L=C3=B6wis?= Date: Wed, 28 Sep 2011 07:41:54 +0200 Subject: Implement PEP 393. --- Python/getargs.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index c3da368604..0e7d9c4350 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -546,9 +546,6 @@ convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags, -#define UNICODE_DEFAULT_ENCODING(arg) \ - _PyUnicode_AsDefaultEncodedString(arg) - /* Format an error message generated by convertsimple(). */ static char * @@ -611,7 +608,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, const char *format = *p_format; char c = *format++; - PyObject *uarg; + char *sarg; switch (c) { @@ -838,8 +835,11 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, case 'C': {/* unicode char */ int *p = va_arg(*p_va, int *); if (PyUnicode_Check(arg) && - PyUnicode_GET_SIZE(arg) == 1) - *p = PyUnicode_AS_UNICODE(arg)[0]; + PyUnicode_GET_LENGTH(arg) == 1) { + int kind = PyUnicode_KIND(arg); + void *data = PyUnicode_DATA(arg); + *p = PyUnicode_READ(kind, data, 0); + } else return converterr("a unicode character", arg, msgbuf, bufsize); break; @@ -889,13 +889,12 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, if (c == 'z' && arg == Py_None) PyBuffer_FillInfo(p, NULL, NULL, 0, 1, 0); else if (PyUnicode_Check(arg)) { - uarg = UNICODE_DEFAULT_ENCODING(arg); - if (uarg == NULL) + Py_ssize_t len; + sarg = PyUnicode_AsUTF8AndSize(arg, &len); + if (sarg == NULL) return converterr(CONV_UNICODE, arg, msgbuf, bufsize); - PyBuffer_FillInfo(p, arg, - PyBytes_AS_STRING(uarg), PyBytes_GET_SIZE(uarg), - 1, 0); + PyBuffer_FillInfo(p, arg, sarg, len, 1, 0); } else { /* any buffer-like object */ char *buf; @@ -918,12 +917,13 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, STORE_SIZE(0); } else if (PyUnicode_Check(arg)) { - uarg = UNICODE_DEFAULT_ENCODING(arg); - if (uarg == NULL) + Py_ssize_t len; + sarg = PyUnicode_AsUTF8AndSize(arg, &len); + if (sarg == NULL) return converterr(CONV_UNICODE, arg, msgbuf, bufsize); - *p = PyBytes_AS_STRING(uarg); - STORE_SIZE(PyBytes_GET_SIZE(uarg)); + *p = sarg; + STORE_SIZE(len); } else { /* any buffer-like object */ /* XXX Really? */ @@ -937,22 +937,22 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, } else { /* "s" or "z" */ char **p = va_arg(*p_va, char **); - uarg = NULL; + Py_ssize_t len; + sarg = NULL; if (c == 'z' && arg == Py_None) *p = NULL; else if (PyUnicode_Check(arg)) { - uarg = UNICODE_DEFAULT_ENCODING(arg); - if (uarg == NULL) + sarg = PyUnicode_AsUTF8AndSize(arg, &len); + if (sarg == NULL) return converterr(CONV_UNICODE, arg, msgbuf, bufsize); - *p = PyBytes_AS_STRING(uarg); + *p = sarg; } else return converterr(c == 'z' ? "str or None" : "str", arg, msgbuf, bufsize); - if (*p != NULL && uarg != NULL && - (Py_ssize_t) strlen(*p) != PyBytes_GET_SIZE(uarg)) + if (*p != NULL && sarg != NULL && (Py_ssize_t) strlen(*p) != len) return converterr( c == 'z' ? "str without null bytes or None" : "str without null bytes", @@ -976,6 +976,8 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, } else if (PyUnicode_Check(arg)) { *p = PyUnicode_AS_UNICODE(arg); + if (*p == NULL) + RETURN_ERR_OCCURRED; STORE_SIZE(PyUnicode_GET_SIZE(arg)); } else @@ -987,6 +989,8 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, *p = NULL; else if (PyUnicode_Check(arg)) { *p = PyUnicode_AS_UNICODE(arg); + if (*p == NULL) + RETURN_ERR_OCCURRED; if (Py_UNICODE_strlen(*p) != PyUnicode_GET_SIZE(arg)) return converterr( "str without null character or None", -- cgit v1.2.1 From 00c5b764e1936139724dd9970fb509f3c2ab1eb2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 4 Oct 2011 20:53:03 +0200 Subject: Fix usage og PyUnicode_READY() --- Python/getargs.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index 0e7d9c4350..2c2db36193 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -834,14 +834,21 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, case 'C': {/* unicode char */ int *p = va_arg(*p_va, int *); - if (PyUnicode_Check(arg) && - PyUnicode_GET_LENGTH(arg) == 1) { - int kind = PyUnicode_KIND(arg); - void *data = PyUnicode_DATA(arg); - *p = PyUnicode_READ(kind, data, 0); - } - else + int kind; + void *data; + + 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); + + kind = PyUnicode_KIND(arg); + data = PyUnicode_DATA(arg); + *p = PyUnicode_READ(kind, data, 0); break; } -- cgit v1.2.1 From 9fde12ef0a3cbe4260897de13f054ec630456992 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 11 Oct 2011 21:55:01 +0200 Subject: Use PyUnicode_AsUnicodeAndSize() instead of PyUnicode_GET_SIZE() --- Python/getargs.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index 2c2db36193..f2cc9f4509 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -982,10 +982,11 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, STORE_SIZE(0); } else if (PyUnicode_Check(arg)) { - *p = PyUnicode_AS_UNICODE(arg); + Py_ssize_t len; + *p = PyUnicode_AsUnicodeAndSize(arg, &len); if (*p == NULL) RETURN_ERR_OCCURRED; - STORE_SIZE(PyUnicode_GET_SIZE(arg)); + STORE_SIZE(len); } else return converterr("str or None", arg, msgbuf, bufsize); @@ -995,10 +996,11 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, if (c == 'Z' && arg == Py_None) *p = NULL; else if (PyUnicode_Check(arg)) { - *p = PyUnicode_AS_UNICODE(arg); + Py_ssize_t len; + *p = PyUnicode_AsUnicodeAndSize(arg, &len); if (*p == NULL) RETURN_ERR_OCCURRED; - if (Py_UNICODE_strlen(*p) != PyUnicode_GET_SIZE(arg)) + if (Py_UNICODE_strlen(*p) != len) return converterr( "str without null character or None", arg, msgbuf, bufsize); -- cgit v1.2.1 From a337ec1d9c574b5a5d2bca01ceb43cdead37f799 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 13 Oct 2011 23:25:03 +0200 Subject: convertsimple(): "str without bytes" => "str without characters" --- Python/getargs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index f2cc9f4509..77f27bebc9 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -961,8 +961,8 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, arg, msgbuf, bufsize); if (*p != NULL && sarg != NULL && (Py_ssize_t) strlen(*p) != len) return converterr( - c == 'z' ? "str without null bytes or None" - : "str without null bytes", + c == 'z' ? "str without null characters or None" + : "str without null characters", arg, msgbuf, bufsize); } break; @@ -1002,7 +1002,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, RETURN_ERR_OCCURRED; if (Py_UNICODE_strlen(*p) != len) return converterr( - "str without null character or None", + "str without null characters or None", arg, msgbuf, bufsize); } else return converterr(c == 'Z' ? "str or None" : "str", -- cgit v1.2.1 From c1da75edd489027b5dedb45660466a0b4d8d7063 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone Date: Fri, 16 Mar 2012 08:51:42 -0400 Subject: Issue #14325: Stop using python lists, capsules, and the garbage collector to deal with PyArg_Parse* cleanup. --- Python/getargs.c | 205 +++++++++++++++++++++++-------------------------------- 1 file changed, 85 insertions(+), 120 deletions(-) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index 77f27bebc9..37f1898819 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -33,16 +33,33 @@ PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *, PyObject *, #define FLAG_COMPAT 1 #define FLAG_SIZE_T 2 +typedef int (*destr_t)(PyObject *, void *); + + +/* Keep track of "objects" that have been allocated or initialized and + which will need to be deallocated or cleaned up somehow if overall + parsing fails. +*/ +typedef struct { + void *item; + destr_t destructor; +} freelistentry_t; + +typedef struct { + int first_available; + freelistentry_t *entries; +} freelist_t; + /* Forward */ static int vgetargs1(PyObject *, const char *, va_list *, int); static void seterror(int, const char *, int *, const char *, const char *); static char *convertitem(PyObject *, const char **, va_list *, int, int *, - char *, size_t, PyObject **); + char *, size_t, freelist_t *); static char *converttuple(PyObject *, const char **, va_list *, int, - int *, char *, size_t, int, PyObject **); + int *, char *, size_t, int, freelist_t *); static char *convertsimple(PyObject *, const char **, va_list *, int, char *, - size_t, PyObject **); + size_t, freelist_t *); static Py_ssize_t convertbuffer(PyObject *, void **p, char **); static int getbuffer(PyObject *, Py_buffer *, char**); @@ -127,111 +144,54 @@ _PyArg_VaParse_SizeT(PyObject *args, char *format, va_list va) #define GETARGS_CAPSULE_NAME_CLEANUP_BUFFER "getargs.cleanup_buffer" #define GETARGS_CAPSULE_NAME_CLEANUP_CONVERT "getargs.cleanup_convert" -static void -cleanup_ptr(PyObject *self) +static int +cleanup_ptr(PyObject *self, void *ptr) { - void *ptr = PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_PTR); if (ptr) { PyMem_FREE(ptr); } + return 0; } -static void -cleanup_buffer(PyObject *self) +static int +cleanup_buffer(PyObject *self, void *ptr) { - Py_buffer *ptr = (Py_buffer *)PyCapsule_GetPointer(self, GETARGS_CAPSULE_NAME_CLEANUP_BUFFER); - if (ptr) { - PyBuffer_Release(ptr); + Py_buffer *buf = (Py_buffer *)ptr; + if (buf) { + PyBuffer_Release(buf); } + return 0; } static int -addcleanup(void *ptr, PyObject **freelist, int is_buffer) +addcleanup(void *ptr, freelist_t *freelist, destr_t destructor) { - PyObject *cobj; - const char *name; - PyCapsule_Destructor destr; - - if (is_buffer) { - destr = cleanup_buffer; - name = GETARGS_CAPSULE_NAME_CLEANUP_BUFFER; - } else { - destr = cleanup_ptr; - name = GETARGS_CAPSULE_NAME_CLEANUP_PTR; - } - - if (!*freelist) { - *freelist = PyList_New(0); - if (!*freelist) { - destr(ptr); - return -1; - } - } + int index; - cobj = PyCapsule_New(ptr, name, destr); - if (!cobj) { - destr(ptr); - return -1; - } - if (PyList_Append(*freelist, cobj)) { - Py_DECREF(cobj); - return -1; - } - Py_DECREF(cobj); - return 0; -} + index = freelist->first_available; + freelist->first_available += 1; -static void -cleanup_convert(PyObject *self) -{ - typedef int (*destr_t)(PyObject *, void *); - destr_t destr = (destr_t)PyCapsule_GetContext(self); - void *ptr = PyCapsule_GetPointer(self, - GETARGS_CAPSULE_NAME_CLEANUP_CONVERT); - if (ptr && destr) - destr(NULL, ptr); -} + freelist->entries[index].item = ptr; + freelist->entries[index].destructor = destructor; -static int -addcleanup_convert(void *ptr, PyObject **freelist, int (*destr)(PyObject*,void*)) -{ - PyObject *cobj; - if (!*freelist) { - *freelist = PyList_New(0); - if (!*freelist) { - destr(NULL, ptr); - return -1; - } - } - cobj = PyCapsule_New(ptr, GETARGS_CAPSULE_NAME_CLEANUP_CONVERT, - cleanup_convert); - if (!cobj) { - destr(NULL, ptr); - return -1; - } - if (PyCapsule_SetContext(cobj, destr) == -1) { - /* This really should not happen. */ - Py_FatalError("capsule refused setting of context."); - } - if (PyList_Append(*freelist, cobj)) { - Py_DECREF(cobj); /* This will also call destr. */ - return -1; - } - Py_DECREF(cobj); return 0; } static int -cleanreturn(int retval, PyObject *freelist) +cleanreturn(int retval, freelist_t *freelist) { - if (freelist && retval != 0) { - /* We were successful, reset the destructors so that they - don't get called. */ - Py_ssize_t len = PyList_GET_SIZE(freelist), i; - for (i = 0; i < len; i++) - PyCapsule_SetDestructor(PyList_GET_ITEM(freelist, i), NULL); - } - Py_XDECREF(freelist); + int index; + + if (retval == 0) { + /* A failure occurred, therefore execute all of the cleanup + functions. + */ + for (index = 0; index < freelist->first_available; ++index) { + freelist->entries[index].destructor(NULL, + freelist->entries[index].item); + } + } + PyMem_Free(freelist->entries); return retval; } @@ -250,7 +210,7 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) const char *formatsave = format; Py_ssize_t i, len; char *msg; - PyObject *freelist = NULL; + freelist_t freelist = {0, NULL}; int compat = flags & FLAG_COMPAT; assert(compat || (args != (PyObject*)NULL)); @@ -306,6 +266,8 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) format = formatsave; + freelist.entries = PyMem_New(freelistentry_t, max); + if (compat) { if (max == 0) { if (args == NULL) @@ -314,7 +276,7 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) "%.200s%s takes no arguments", fname==NULL ? "function" : fname, fname==NULL ? "" : "()"); - return 0; + return cleanreturn(0, &freelist); } else if (min == 1 && max == 1) { if (args == NULL) { @@ -322,26 +284,26 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) "%.200s%s takes at least one argument", fname==NULL ? "function" : fname, fname==NULL ? "" : "()"); - return 0; + return cleanreturn(0, &freelist); } msg = convertitem(args, &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg == NULL) - return cleanreturn(1, freelist); + return cleanreturn(1, &freelist); seterror(levels[0], msg, levels+1, fname, message); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } else { PyErr_SetString(PyExc_SystemError, "old style getargs format uses new features"); - return 0; + return cleanreturn(0, &freelist); } } if (!PyTuple_Check(args)) { PyErr_SetString(PyExc_SystemError, "new style getargs format but argument is not a tuple"); - return 0; + return cleanreturn(0, &freelist); } len = PyTuple_GET_SIZE(args); @@ -359,7 +321,7 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) Py_SAFE_DOWNCAST(len, Py_ssize_t, long)); else PyErr_SetString(PyExc_TypeError, message); - return 0; + return cleanreturn(0, &freelist); } for (i = 0; i < len; i++) { @@ -370,7 +332,7 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) sizeof(msgbuf), &freelist); if (msg) { seterror(i+1, msg, levels, fname, msg); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } } @@ -379,10 +341,10 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) *format != '|' && *format != ':' && *format != ';') { PyErr_Format(PyExc_SystemError, "bad format string: %.200s", formatsave); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } - return cleanreturn(1, freelist); + return cleanreturn(1, &freelist); } @@ -446,7 +408,7 @@ seterror(int iarg, const char *msg, int *levels, const char *fname, static char * converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, int *levels, char *msgbuf, size_t bufsize, int toplevel, - PyObject **freelist) + freelist_t *freelist) { int level = 0; int n = 0; @@ -521,7 +483,7 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, static char * convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags, - int *levels, char *msgbuf, size_t bufsize, PyObject **freelist) + int *levels, char *msgbuf, size_t bufsize, freelist_t *freelist) { char *msg; const char *format = *p_format; @@ -586,7 +548,7 @@ float_argument_error(PyObject *arg) static char * convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, - char *msgbuf, size_t bufsize, PyObject **freelist) + char *msgbuf, size_t bufsize, freelist_t *freelist) { /* For # codes */ #define FETCH_SIZE int *q=NULL;Py_ssize_t *q2=NULL;\ @@ -863,7 +825,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, if (getbuffer(arg, (Py_buffer*)p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); format++; - if (addcleanup(p, freelist, 1)) { + if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); @@ -908,7 +870,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, if (getbuffer(arg, p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); } - if (addcleanup(p, freelist, 1)) { + if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); @@ -1120,7 +1082,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, PyErr_NoMemory(); RETURN_ERR_OCCURRED; } - if (addcleanup(*buffer, freelist, 0)) { + if (addcleanup(*buffer, freelist, cleanup_ptr)) { Py_DECREF(s); return converterr( "(cleanup problem)", @@ -1162,7 +1124,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, PyErr_NoMemory(); RETURN_ERR_OCCURRED; } - if (addcleanup(*buffer, freelist, 0)) { + if (addcleanup(*buffer, freelist, cleanup_ptr)) { Py_DECREF(s); return converterr("(cleanup problem)", arg, msgbuf, bufsize); @@ -1223,7 +1185,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, return converterr("(unspecified)", arg, msgbuf, bufsize); if (res == Py_CLEANUP_SUPPORTED && - addcleanup_convert(addr, freelist, convert) == -1) + addcleanup(addr, freelist, convert) == -1) return converterr("(cleanup problem)", arg, msgbuf, bufsize); } @@ -1254,7 +1216,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, PyBuffer_Release((Py_buffer*)p); return converterr("contiguous buffer", arg, msgbuf, bufsize); } - if (addcleanup(p, freelist, 1)) { + if (addcleanup(p, freelist, cleanup_buffer)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); @@ -1442,7 +1404,8 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, const char *fname, *msg, *custom_msg, *keyword; int min = INT_MAX; int i, len, nargs, nkeywords; - PyObject *freelist = NULL, *current_arg; + PyObject *current_arg; + freelist_t freelist = {0, NULL}; assert(args != NULL && PyTuple_Check(args)); assert(keywords == NULL || PyDict_Check(keywords)); @@ -1466,6 +1429,8 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, for (len=0; kwlist[len]; len++) continue; + freelist.entries = PyMem_New(freelistentry_t, len); + nargs = PyTuple_GET_SIZE(args); nkeywords = (keywords == NULL) ? 0 : PyDict_Size(keywords); if (nargs + nkeywords > len) { @@ -1490,7 +1455,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, PyErr_Format(PyExc_RuntimeError, "More keyword list entries (%d) than " "format specifiers (%d)", len, i); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } current_arg = NULL; if (nkeywords) { @@ -1504,11 +1469,11 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, "Argument given by name ('%s') " "and position (%d)", keyword, i+1); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } } else if (nkeywords && PyErr_Occurred()) - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); else if (i < nargs) current_arg = PyTuple_GET_ITEM(args, i); @@ -1517,7 +1482,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { seterror(i+1, msg, levels, fname, custom_msg); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } continue; } @@ -1526,14 +1491,14 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, PyErr_Format(PyExc_TypeError, "Required argument " "'%s' (pos %d) not found", keyword, i+1); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } /* current code reports success when all required args * fulfilled and no keyword args left, with no further * validation. XXX Maybe skip this in debug build ? */ if (!nkeywords) - return cleanreturn(1, freelist); + return cleanreturn(1, &freelist); /* We are into optional args, skip thru to any remaining * keyword args */ @@ -1541,7 +1506,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, if (msg) { PyErr_Format(PyExc_RuntimeError, "%s: '%s'", msg, format); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } } @@ -1549,7 +1514,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, PyErr_Format(PyExc_RuntimeError, "more argument specifiers than keyword list entries " "(remaining format:'%s')", format); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } /* make sure there are no extraneous keyword arguments */ @@ -1562,7 +1527,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, if (!PyUnicode_Check(key)) { PyErr_SetString(PyExc_TypeError, "keywords must be strings"); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } /* check that _PyUnicode_AsString() result is not NULL */ ks = _PyUnicode_AsString(key); @@ -1579,12 +1544,12 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, "'%U' is an invalid keyword " "argument for this function", key); - return cleanreturn(0, freelist); + return cleanreturn(0, &freelist); } } } - return cleanreturn(1, freelist); + return cleanreturn(1, &freelist); } -- cgit v1.2.1 From 3c4e2b43f9ad635037e3fa7b1f8470998d713afc Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 16 Mar 2012 12:21:02 -0500 Subject: check result of PyMem_New --- Python/getargs.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index 37f1898819..268a1134ea 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -267,6 +267,10 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) format = formatsave; freelist.entries = PyMem_New(freelistentry_t, max); + if (freelist.entries == NULL) { + PyErr_NoMemory(); + return 0; + } if (compat) { if (max == 0) { @@ -1430,6 +1434,10 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, continue; freelist.entries = PyMem_New(freelistentry_t, len); + if (freelist.entries == NULL) { + PyErr_NoMemory(); + return 0; + } nargs = PyTuple_GET_SIZE(args); nkeywords = (keywords == NULL) ? 0 : PyDict_Size(keywords); -- cgit v1.2.1 From 6e1127bdc88214b10b93a9a608e127f90eadee2f Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 16 Mar 2012 12:23:39 -0500 Subject: use memory macros --- Python/getargs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index 268a1134ea..ba677b49d3 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -191,7 +191,7 @@ cleanreturn(int retval, freelist_t *freelist) freelist->entries[index].item); } } - PyMem_Free(freelist->entries); + PyMem_FREE(freelist->entries); return retval; } @@ -266,7 +266,7 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) format = formatsave; - freelist.entries = PyMem_New(freelistentry_t, max); + freelist.entries = PyMem_NEW(freelistentry_t, max); if (freelist.entries == NULL) { PyErr_NoMemory(); return 0; @@ -1433,7 +1433,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, for (len=0; kwlist[len]; len++) continue; - freelist.entries = PyMem_New(freelistentry_t, len); + freelist.entries = PyMem_NEW(freelistentry_t, len); if (freelist.entries == NULL) { PyErr_NoMemory(); return 0; -- cgit v1.2.1 From 79d07f6f48cf5c60eb5ef3704aa135613f9bae87 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 16 Mar 2012 12:24:01 -0500 Subject: kill capsule names that we don't need anymore --- Python/getargs.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index ba677b49d3..38eec171d1 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -140,10 +140,6 @@ _PyArg_VaParse_SizeT(PyObject *args, char *format, va_list va) /* Handle cleanup of allocated memory in case of exception */ -#define GETARGS_CAPSULE_NAME_CLEANUP_PTR "getargs.cleanup_ptr" -#define GETARGS_CAPSULE_NAME_CLEANUP_BUFFER "getargs.cleanup_buffer" -#define GETARGS_CAPSULE_NAME_CLEANUP_CONVERT "getargs.cleanup_convert" - static int cleanup_ptr(PyObject *self, void *ptr) { -- cgit v1.2.1 From aaecb17871cb7362ca2d54cb6f11b1fce9cacbfd Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 16 Mar 2012 13:25:58 -0500 Subject: plug memory leak (closes #14325) --- Python/getargs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index 38eec171d1..38c9dde6ff 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1445,7 +1445,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, len, (len == 1) ? "" : "s", nargs + nkeywords); - return 0; + return cleanreturn(0, &freelist); } /* convert tuple args and keyword args in same loop, using kwlist to drive process */ -- cgit v1.2.1 From c067da0e5c050df338fdc2f8ab6a01283f92f0ea Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Tue, 20 Mar 2012 20:06:16 +0000 Subject: Issue #14328: Add keyword-only parameters to PyArg_ParseTupleAndKeywords. They're optional-only for now (unlike in pure Python) but that's all I needed. The syntax can easily be relaxed if we want to support required keyword-only arguments for extension types in the future. --- Python/getargs.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index 38c9dde6ff..8ec7110610 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1403,6 +1403,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, int levels[32]; const char *fname, *msg, *custom_msg, *keyword; int min = INT_MAX; + int max = INT_MAX; int i, len, nargs, nkeywords; PyObject *current_arg; freelist_t freelist = {0, NULL}; @@ -1452,8 +1453,39 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, for (i = 0; i < len; i++) { keyword = kwlist[i]; if (*format == '|') { + if (min != INT_MAX) { + PyErr_SetString(PyExc_RuntimeError, + "Invalid format string (| specified twice)"); + return cleanreturn(0, &freelist); + } + min = i; format++; + + if (max != INT_MAX) { + PyErr_SetString(PyExc_RuntimeError, + "Invalid format string ($ before |)"); + return cleanreturn(0, &freelist); + } + } + if (*format == '$') { + if (max != INT_MAX) { + PyErr_SetString(PyExc_RuntimeError, + "Invalid format string ($ specified twice)"); + return cleanreturn(0, &freelist); + } + + max = i; + format++; + + if (max < nargs) { + PyErr_Format(PyExc_TypeError, + "Function takes %s %d positional arguments" + " (%d given)", + (min != INT_MAX) ? "at most" : "exactly", + max, nargs); + return cleanreturn(0, &freelist); + } } if (IS_END_OF_FORMAT(*format)) { PyErr_Format(PyExc_RuntimeError, @@ -1514,7 +1546,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, } } - if (!IS_END_OF_FORMAT(*format) && *format != '|') { + if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) { PyErr_Format(PyExc_RuntimeError, "more argument specifiers than keyword list entries " "(remaining format:'%s')", format); -- cgit v1.2.1 From 61215288bb0aece657bfa1c37d5ad0633c795c27 Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Sat, 5 May 2012 16:54:29 -0700 Subject: Issue #14705: Add 'p' format character to PyArg_ParseTuple* for bool support. --- Python/getargs.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index 8ec7110610..9e9695f4d2 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -814,6 +814,18 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, break; } + case 'p': {/* boolean *p*redicate */ + int *p = va_arg(*p_va, int *); + int val = PyObject_IsTrue(arg); + if (val > 0) + *p = 1; + else if (val == 0) + *p = 0; + else + RETURN_ERR_OCCURRED; + break; + } + /* XXX WAAAAH! 's', 'y', 'z', 'u', 'Z', 'e', 'w' codes all need to be cleaned up! */ -- cgit v1.2.1 From c5113957b71121c8c3bd773c402d725eb21cc649 Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Mon, 7 May 2012 02:44:50 -0700 Subject: Issue #14705: Added support for the new 'p' format unit to skipitem(). --- Python/getargs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index 9e9695f4d2..78b232894c 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1629,6 +1629,7 @@ skipitem(const char **p_format, va_list *p_va, int flags) case 'D': /* complex double */ case 'c': /* char */ case 'C': /* unicode char */ + case 'p': /* boolean predicate */ { (void) va_arg(*p_va, void *); break; -- cgit v1.2.1 From bca3a7bbad8094ef00817dec65f1592701dc6151 Mon Sep 17 00:00:00 2001 From: Larry Hastings Date: Tue, 8 May 2012 23:52:03 -0700 Subject: Issue #14746: Remove redundant paragraphs from skipitem() in Python/getargs.c. --- Python/getargs.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index 5ddf236aa7..17c4ee5955 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1609,8 +1609,10 @@ skipitem(const char **p_format, va_list *p_va, int flags) switch (c) { - /* simple codes - * The individual types (second arg of va_arg) are irrelevant */ + /* + * codes that take a single data pointer as an argument + * (the type of the pointer is irrelevant) + */ case 'b': /* byte -- very short int */ case 'B': /* byte as bitfield */ @@ -1624,23 +1626,21 @@ skipitem(const char **p_format, va_list *p_va, int flags) case 'L': /* PY_LONG_LONG */ case 'K': /* PY_LONG_LONG sized bitfield */ #endif + case 'n': /* Py_ssize_t */ case 'f': /* float */ case 'd': /* double */ case 'D': /* complex double */ case 'c': /* char */ case 'C': /* unicode char */ case 'p': /* boolean predicate */ + case 'S': /* string object */ + case 'Y': /* string object */ + case 'U': /* unicode string object */ { (void) va_arg(*p_va, void *); break; } - case 'n': /* Py_ssize_t */ - { - (void) va_arg(*p_va, Py_ssize_t *); - break; - } - /* string codes */ case 'e': /* string with encoding */ @@ -1673,16 +1673,6 @@ skipitem(const char **p_format, va_list *p_va, int flags) break; } - /* object codes */ - - case 'S': /* string object */ - case 'Y': /* string object */ - case 'U': /* unicode string object */ - { - (void) va_arg(*p_va, PyObject **); - break; - } - case 'O': /* object */ { if (*format == '!') { -- cgit v1.2.1 From feb3a43fc0ee359f33e6657692287a42c14d6fc3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 29 May 2012 12:30:29 +0200 Subject: PyArg_Parse*("U"): ensure that the Unicode string is ready --- Python/getargs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Python/getargs.c') diff --git a/Python/getargs.c b/Python/getargs.c index 17c4ee5955..9f72fa4ebf 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -1167,8 +1167,11 @@ 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_Check(arg)) { + if (PyUnicode_READY(arg) == -1) + RETURN_ERR_OCCURRED; *p = arg; + } else return converterr("str", arg, msgbuf, bufsize); break; -- cgit v1.2.1