Patch #684981: Add cleanup capability for argument parsers. Fixes 501716.
This commit is contained in:
parent
4d28d96afb
commit
e6bbb4d16f
118
Python/getargs.c
118
Python/getargs.c
|
@ -17,10 +17,11 @@ int PyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
|
||||||
static int vgetargs1(PyObject *, char *, va_list *, int);
|
static int vgetargs1(PyObject *, char *, va_list *, int);
|
||||||
static void seterror(int, char *, int *, char *, char *);
|
static void seterror(int, char *, int *, char *, char *);
|
||||||
static char *convertitem(PyObject *, char **, va_list *, int *, char *,
|
static char *convertitem(PyObject *, char **, va_list *, int *, char *,
|
||||||
size_t);
|
size_t, PyObject **);
|
||||||
static char *converttuple(PyObject *, char **, va_list *,
|
static char *converttuple(PyObject *, char **, va_list *,
|
||||||
int *, char *, size_t, int);
|
int *, char *, size_t, int, PyObject **);
|
||||||
static char *convertsimple(PyObject *, char **, va_list *, char *, size_t);
|
static char *convertsimple(PyObject *, char **, va_list *, char *,
|
||||||
|
size_t, PyObject **);
|
||||||
static int convertbuffer(PyObject *, void **p, char **);
|
static int convertbuffer(PyObject *, void **p, char **);
|
||||||
|
|
||||||
static int vgetargskeywords(PyObject *, PyObject *,
|
static int vgetargskeywords(PyObject *, PyObject *,
|
||||||
|
@ -72,6 +73,49 @@ PyArg_VaParse(PyObject *args, char *format, va_list va)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Handle cleanup of allocated memory in case of exception */
|
||||||
|
|
||||||
|
static int
|
||||||
|
addcleanup(void *ptr, PyObject **freelist)
|
||||||
|
{
|
||||||
|
PyObject *cobj;
|
||||||
|
if (!*freelist) {
|
||||||
|
*freelist = PyList_New(0);
|
||||||
|
if (!*freelist) {
|
||||||
|
PyMem_FREE(ptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cobj = PyCObject_FromVoidPtr(ptr, NULL);
|
||||||
|
if (!cobj) {
|
||||||
|
PyMem_FREE(ptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(PyList_Append(*freelist, cobj)) {
|
||||||
|
PyMem_FREE(ptr);
|
||||||
|
Py_DECREF(cobj);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Py_DECREF(cobj);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cleanreturn(int retval, PyObject *freelist)
|
||||||
|
{
|
||||||
|
if(freelist) {
|
||||||
|
if((retval) == 0) {
|
||||||
|
int len = PyList_GET_SIZE(freelist), i;
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
PyMem_FREE(PyCObject_AsVoidPtr(
|
||||||
|
PyList_GET_ITEM(freelist, i)));
|
||||||
|
}
|
||||||
|
Py_DECREF(freelist);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
|
vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
|
||||||
{
|
{
|
||||||
|
@ -86,6 +130,7 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
|
||||||
char *formatsave = format;
|
char *formatsave = format;
|
||||||
int i, len;
|
int i, len;
|
||||||
char *msg;
|
char *msg;
|
||||||
|
PyObject *freelist = NULL;
|
||||||
|
|
||||||
assert(compat || (args != (PyObject*)NULL));
|
assert(compat || (args != (PyObject*)NULL));
|
||||||
|
|
||||||
|
@ -157,11 +202,11 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
msg = convertitem(args, &format, p_va, levels, msgbuf,
|
msg = convertitem(args, &format, p_va, levels, msgbuf,
|
||||||
sizeof(msgbuf));
|
sizeof(msgbuf), &freelist);
|
||||||
if (msg == NULL)
|
if (msg == NULL)
|
||||||
return 1;
|
return cleanreturn(1, freelist);
|
||||||
seterror(levels[0], msg, levels+1, fname, message);
|
seterror(levels[0], msg, levels+1, fname, message);
|
||||||
return 0;
|
return cleanreturn(0, freelist);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyErr_SetString(PyExc_SystemError,
|
PyErr_SetString(PyExc_SystemError,
|
||||||
|
@ -200,10 +245,10 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
|
||||||
if (*format == '|')
|
if (*format == '|')
|
||||||
format++;
|
format++;
|
||||||
msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va,
|
msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va,
|
||||||
levels, msgbuf, sizeof(msgbuf));
|
levels, msgbuf, sizeof(msgbuf), &freelist);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
seterror(i+1, msg, levels, fname, message);
|
seterror(i+1, msg, levels, fname, message);
|
||||||
return 0;
|
return cleanreturn(0, freelist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,10 +257,10 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
|
||||||
*format != '|' && *format != ':' && *format != ';') {
|
*format != '|' && *format != ':' && *format != ';') {
|
||||||
PyErr_Format(PyExc_SystemError,
|
PyErr_Format(PyExc_SystemError,
|
||||||
"bad format string: %.200s", formatsave);
|
"bad format string: %.200s", formatsave);
|
||||||
return 0;
|
return cleanreturn(0, freelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return cleanreturn(1, freelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -277,7 +322,7 @@ seterror(int iarg, char *msg, int *levels, char *fname, char *message)
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels,
|
converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels,
|
||||||
char *msgbuf, size_t bufsize, int toplevel)
|
char *msgbuf, size_t bufsize, int toplevel, PyObject **freelist)
|
||||||
{
|
{
|
||||||
int level = 0;
|
int level = 0;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
@ -327,7 +372,7 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels,
|
||||||
PyObject *item;
|
PyObject *item;
|
||||||
item = PySequence_GetItem(arg, i);
|
item = PySequence_GetItem(arg, i);
|
||||||
msg = convertitem(item, &format, p_va, levels+1, msgbuf,
|
msg = convertitem(item, &format, p_va, levels+1, msgbuf,
|
||||||
bufsize);
|
bufsize, freelist);
|
||||||
/* PySequence_GetItem calls tp->sq_item, which INCREFs */
|
/* PySequence_GetItem calls tp->sq_item, which INCREFs */
|
||||||
Py_XDECREF(item);
|
Py_XDECREF(item);
|
||||||
if (msg != NULL) {
|
if (msg != NULL) {
|
||||||
|
@ -345,7 +390,7 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels,
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
convertitem(PyObject *arg, char **p_format, va_list *p_va, int *levels,
|
convertitem(PyObject *arg, char **p_format, va_list *p_va, int *levels,
|
||||||
char *msgbuf, size_t bufsize)
|
char *msgbuf, size_t bufsize, PyObject **freelist)
|
||||||
{
|
{
|
||||||
char *msg;
|
char *msg;
|
||||||
char *format = *p_format;
|
char *format = *p_format;
|
||||||
|
@ -353,12 +398,13 @@ convertitem(PyObject *arg, char **p_format, va_list *p_va, int *levels,
|
||||||
if (*format == '(' /* ')' */) {
|
if (*format == '(' /* ')' */) {
|
||||||
format++;
|
format++;
|
||||||
msg = converttuple(arg, &format, p_va, levels, msgbuf,
|
msg = converttuple(arg, &format, p_va, levels, msgbuf,
|
||||||
bufsize, 0);
|
bufsize, 0, freelist);
|
||||||
if (msg == NULL)
|
if (msg == NULL)
|
||||||
format++;
|
format++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
msg = convertsimple(arg, &format, p_va, msgbuf, bufsize);
|
msg = convertsimple(arg, &format, p_va, msgbuf, bufsize,
|
||||||
|
freelist);
|
||||||
if (msg != NULL)
|
if (msg != NULL)
|
||||||
levels[0] = 0;
|
levels[0] = 0;
|
||||||
}
|
}
|
||||||
|
@ -409,7 +455,7 @@ float_argument_error(PyObject *arg)
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf,
|
convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf,
|
||||||
size_t bufsize)
|
size_t bufsize, PyObject **freelist)
|
||||||
{
|
{
|
||||||
char *format = *p_format;
|
char *format = *p_format;
|
||||||
char c = *format++;
|
char c = *format++;
|
||||||
|
@ -836,10 +882,12 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf,
|
||||||
int *buffer_len = va_arg(*p_va, int *);
|
int *buffer_len = va_arg(*p_va, int *);
|
||||||
|
|
||||||
format++;
|
format++;
|
||||||
if (buffer_len == NULL)
|
if (buffer_len == NULL) {
|
||||||
|
Py_DECREF(s);
|
||||||
return converterr(
|
return converterr(
|
||||||
"(buffer_len is NULL)",
|
"(buffer_len is NULL)",
|
||||||
arg, msgbuf, bufsize);
|
arg, msgbuf, bufsize);
|
||||||
|
}
|
||||||
if (*buffer == NULL) {
|
if (*buffer == NULL) {
|
||||||
*buffer = PyMem_NEW(char, size + 1);
|
*buffer = PyMem_NEW(char, size + 1);
|
||||||
if (*buffer == NULL) {
|
if (*buffer == NULL) {
|
||||||
|
@ -848,6 +896,12 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf,
|
||||||
"(memory error)",
|
"(memory error)",
|
||||||
arg, msgbuf, bufsize);
|
arg, msgbuf, bufsize);
|
||||||
}
|
}
|
||||||
|
if(addcleanup(*buffer, freelist)) {
|
||||||
|
Py_DECREF(s);
|
||||||
|
return converterr(
|
||||||
|
"(cleanup problem)",
|
||||||
|
arg, msgbuf, bufsize);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (size + 1 > *buffer_len) {
|
if (size + 1 > *buffer_len) {
|
||||||
Py_DECREF(s);
|
Py_DECREF(s);
|
||||||
|
@ -874,16 +928,23 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf,
|
||||||
PyMem_Free()ing it after usage
|
PyMem_Free()ing it after usage
|
||||||
|
|
||||||
*/
|
*/
|
||||||
if ((int)strlen(PyString_AS_STRING(s)) != size)
|
if ((int)strlen(PyString_AS_STRING(s)) != size) {
|
||||||
|
Py_DECREF(s);
|
||||||
return converterr(
|
return converterr(
|
||||||
"(encoded string without NULL bytes)",
|
"(encoded string without NULL bytes)",
|
||||||
arg, msgbuf, bufsize);
|
arg, msgbuf, bufsize);
|
||||||
|
}
|
||||||
*buffer = PyMem_NEW(char, size + 1);
|
*buffer = PyMem_NEW(char, size + 1);
|
||||||
if (*buffer == NULL) {
|
if (*buffer == NULL) {
|
||||||
Py_DECREF(s);
|
Py_DECREF(s);
|
||||||
return converterr("(memory error)",
|
return converterr("(memory error)",
|
||||||
arg, msgbuf, bufsize);
|
arg, msgbuf, bufsize);
|
||||||
}
|
}
|
||||||
|
if(addcleanup(*buffer, freelist)) {
|
||||||
|
Py_DECREF(s);
|
||||||
|
return converterr("(cleanup problem)",
|
||||||
|
arg, msgbuf, bufsize);
|
||||||
|
}
|
||||||
memcpy(*buffer,
|
memcpy(*buffer,
|
||||||
PyString_AS_STRING(s),
|
PyString_AS_STRING(s),
|
||||||
size + 1);
|
size + 1);
|
||||||
|
@ -1103,6 +1164,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
|
||||||
char *formatsave;
|
char *formatsave;
|
||||||
int i, len, nargs, nkeywords;
|
int i, len, nargs, nkeywords;
|
||||||
char *msg, **p;
|
char *msg, **p;
|
||||||
|
PyObject *freelist = NULL;
|
||||||
|
|
||||||
assert(args != NULL && PyTuple_Check(args));
|
assert(args != NULL && PyTuple_Check(args));
|
||||||
assert(keywords == NULL || PyDict_Check(keywords));
|
assert(keywords == NULL || PyDict_Check(keywords));
|
||||||
|
@ -1227,16 +1289,16 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
|
||||||
if (*format == '|')
|
if (*format == '|')
|
||||||
format++;
|
format++;
|
||||||
msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va,
|
msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va,
|
||||||
levels, msgbuf, sizeof(msgbuf));
|
levels, msgbuf, sizeof(msgbuf), &freelist);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
seterror(i+1, msg, levels, fname, message);
|
seterror(i+1, msg, levels, fname, message);
|
||||||
return 0;
|
return cleanreturn(0, freelist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* handle no keyword parameters in call */
|
/* handle no keyword parameters in call */
|
||||||
if (nkeywords == 0)
|
if (nkeywords == 0)
|
||||||
return 1;
|
return cleanreturn(1, freelist);
|
||||||
|
|
||||||
/* convert the keyword arguments; this uses the format
|
/* convert the keyword arguments; this uses the format
|
||||||
string where it was left after processing args */
|
string where it was left after processing args */
|
||||||
|
@ -1248,23 +1310,23 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
|
||||||
if (item != NULL) {
|
if (item != NULL) {
|
||||||
Py_INCREF(item);
|
Py_INCREF(item);
|
||||||
msg = convertitem(item, &format, p_va, levels, msgbuf,
|
msg = convertitem(item, &format, p_va, levels, msgbuf,
|
||||||
sizeof(msgbuf));
|
sizeof(msgbuf), &freelist);
|
||||||
Py_DECREF(item);
|
Py_DECREF(item);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
seterror(i+1, msg, levels, fname, message);
|
seterror(i+1, msg, levels, fname, message);
|
||||||
return 0;
|
return cleanreturn(0, freelist);
|
||||||
}
|
}
|
||||||
--nkeywords;
|
--nkeywords;
|
||||||
if (nkeywords == 0)
|
if (nkeywords == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (PyErr_Occurred())
|
else if (PyErr_Occurred())
|
||||||
return 0;
|
return cleanreturn(0, freelist);
|
||||||
else {
|
else {
|
||||||
msg = skipitem(&format, p_va);
|
msg = skipitem(&format, p_va);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
seterror(i+1, msg, levels, fname, message);
|
seterror(i+1, msg, levels, fname, message);
|
||||||
return 0;
|
return cleanreturn(0, freelist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1279,7 +1341,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
|
||||||
if (!PyString_Check(key)) {
|
if (!PyString_Check(key)) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"keywords must be strings");
|
"keywords must be strings");
|
||||||
return 0;
|
return cleanreturn(0, freelist);
|
||||||
}
|
}
|
||||||
ks = PyString_AsString(key);
|
ks = PyString_AsString(key);
|
||||||
for (i = 0; i < max; i++) {
|
for (i = 0; i < max; i++) {
|
||||||
|
@ -1293,12 +1355,12 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
|
||||||
"'%s' is an invalid keyword "
|
"'%s' is an invalid keyword "
|
||||||
"argument for this function",
|
"argument for this function",
|
||||||
ks);
|
ks);
|
||||||
return 0;
|
return cleanreturn(0, freelist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return cleanreturn(1, freelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue