Patch #684981: Add cleanup capability for argument parsers. Fixes 501716.

This commit is contained in:
Martin v. Löwis 2003-05-03 10:00:22 +00:00
parent 4d28d96afb
commit e6bbb4d16f

View File

@ -17,10 +17,11 @@ int PyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
static int vgetargs1(PyObject *, char *, va_list *, int);
static void seterror(int, char *, int *, char *, char *);
static char *convertitem(PyObject *, char **, va_list *, int *, char *,
size_t);
size_t, PyObject **);
static char *converttuple(PyObject *, char **, va_list *,
int *, char *, size_t, int);
static char *convertsimple(PyObject *, char **, va_list *, char *, size_t);
int *, char *, size_t, int, PyObject **);
static char *convertsimple(PyObject *, char **, va_list *, char *,
size_t, PyObject **);
static int convertbuffer(PyObject *, void **p, char **);
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
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;
int i, len;
char *msg;
PyObject *freelist = NULL;
assert(compat || (args != (PyObject*)NULL));
@ -157,11 +202,11 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
return 0;
}
msg = convertitem(args, &format, p_va, levels, msgbuf,
sizeof(msgbuf));
sizeof(msgbuf), &freelist);
if (msg == NULL)
return 1;
return cleanreturn(1, freelist);
seterror(levels[0], msg, levels+1, fname, message);
return 0;
return cleanreturn(0, freelist);
}
else {
PyErr_SetString(PyExc_SystemError,
@ -200,10 +245,10 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
if (*format == '|')
format++;
msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va,
levels, msgbuf, sizeof(msgbuf));
levels, msgbuf, sizeof(msgbuf), &freelist);
if (msg) {
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 != ';') {
PyErr_Format(PyExc_SystemError,
"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 *
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 n = 0;
@ -327,7 +372,7 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels,
PyObject *item;
item = PySequence_GetItem(arg, i);
msg = convertitem(item, &format, p_va, levels+1, msgbuf,
bufsize);
bufsize, freelist);
/* PySequence_GetItem calls tp->sq_item, which INCREFs */
Py_XDECREF(item);
if (msg != NULL) {
@ -345,7 +390,7 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels,
static char *
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 *format = *p_format;
@ -353,12 +398,13 @@ convertitem(PyObject *arg, char **p_format, va_list *p_va, int *levels,
if (*format == '(' /* ')' */) {
format++;
msg = converttuple(arg, &format, p_va, levels, msgbuf,
bufsize, 0);
bufsize, 0, freelist);
if (msg == NULL)
format++;
}
else {
msg = convertsimple(arg, &format, p_va, msgbuf, bufsize);
msg = convertsimple(arg, &format, p_va, msgbuf, bufsize,
freelist);
if (msg != NULL)
levels[0] = 0;
}
@ -409,7 +455,7 @@ float_argument_error(PyObject *arg)
static char *
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 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 *);
format++;
if (buffer_len == NULL)
if (buffer_len == NULL) {
Py_DECREF(s);
return converterr(
"(buffer_len is NULL)",
arg, msgbuf, bufsize);
}
if (*buffer == NULL) {
*buffer = PyMem_NEW(char, size + 1);
if (*buffer == NULL) {
@ -848,6 +896,12 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf,
"(memory error)",
arg, msgbuf, bufsize);
}
if(addcleanup(*buffer, freelist)) {
Py_DECREF(s);
return converterr(
"(cleanup problem)",
arg, msgbuf, bufsize);
}
} else {
if (size + 1 > *buffer_len) {
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
*/
if ((int)strlen(PyString_AS_STRING(s)) != size)
if ((int)strlen(PyString_AS_STRING(s)) != size) {
Py_DECREF(s);
return converterr(
"(encoded string without NULL bytes)",
arg, msgbuf, bufsize);
}
*buffer = PyMem_NEW(char, size + 1);
if (*buffer == NULL) {
Py_DECREF(s);
return converterr("(memory error)",
arg, msgbuf, bufsize);
}
if(addcleanup(*buffer, freelist)) {
Py_DECREF(s);
return converterr("(cleanup problem)",
arg, msgbuf, bufsize);
}
memcpy(*buffer,
PyString_AS_STRING(s),
size + 1);
@ -1103,6 +1164,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
char *formatsave;
int i, len, nargs, nkeywords;
char *msg, **p;
PyObject *freelist = NULL;
assert(args != NULL && PyTuple_Check(args));
assert(keywords == NULL || PyDict_Check(keywords));
@ -1227,16 +1289,16 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
if (*format == '|')
format++;
msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va,
levels, msgbuf, sizeof(msgbuf));
levels, msgbuf, sizeof(msgbuf), &freelist);
if (msg) {
seterror(i+1, msg, levels, fname, message);
return 0;
return cleanreturn(0, freelist);
}
}
/* handle no keyword parameters in call */
if (nkeywords == 0)
return 1;
return cleanreturn(1, freelist);
/* convert the keyword arguments; this uses the format
string where it was left after processing args */
@ -1248,23 +1310,23 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
if (item != NULL) {
Py_INCREF(item);
msg = convertitem(item, &format, p_va, levels, msgbuf,
sizeof(msgbuf));
sizeof(msgbuf), &freelist);
Py_DECREF(item);
if (msg) {
seterror(i+1, msg, levels, fname, message);
return 0;
return cleanreturn(0, freelist);
}
--nkeywords;
if (nkeywords == 0)
break;
}
else if (PyErr_Occurred())
return 0;
return cleanreturn(0, freelist);
else {
msg = skipitem(&format, p_va);
if (msg) {
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)) {
PyErr_SetString(PyExc_TypeError,
"keywords must be strings");
return 0;
return cleanreturn(0, freelist);
}
ks = PyString_AsString(key);
for (i = 0; i < max; i++) {
@ -1293,12 +1355,12 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
"'%s' is an invalid keyword "
"argument for this function",
ks);
return 0;
return cleanreturn(0, freelist);
}
}
}
return 1;
return cleanreturn(1, freelist);
}