Skip to content

Commit e6bbb4d

Browse files
committed
Patch #684981: Add cleanup capability for argument parsers. Fixes 501716.
1 parent 4d28d96 commit e6bbb4d

1 file changed

Lines changed: 90 additions & 28 deletions

File tree

Python/getargs.c

Lines changed: 90 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ int PyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
1717
static int vgetargs1(PyObject *, char *, va_list *, int);
1818
static void seterror(int, char *, int *, char *, char *);
1919
static char *convertitem(PyObject *, char **, va_list *, int *, char *,
20-
size_t);
20+
size_t, PyObject **);
2121
static char *converttuple(PyObject *, char **, va_list *,
22-
int *, char *, size_t, int);
23-
static char *convertsimple(PyObject *, char **, va_list *, char *, size_t);
22+
int *, char *, size_t, int, PyObject **);
23+
static char *convertsimple(PyObject *, char **, va_list *, char *,
24+
size_t, PyObject **);
2425
static int convertbuffer(PyObject *, void **p, char **);
2526

2627
static int vgetargskeywords(PyObject *, PyObject *,
@@ -72,6 +73,49 @@ PyArg_VaParse(PyObject *args, char *format, va_list va)
7273
}
7374

7475

76+
/* Handle cleanup of allocated memory in case of exception */
77+
78+
static int
79+
addcleanup(void *ptr, PyObject **freelist)
80+
{
81+
PyObject *cobj;
82+
if (!*freelist) {
83+
*freelist = PyList_New(0);
84+
if (!*freelist) {
85+
PyMem_FREE(ptr);
86+
return -1;
87+
}
88+
}
89+
cobj = PyCObject_FromVoidPtr(ptr, NULL);
90+
if (!cobj) {
91+
PyMem_FREE(ptr);
92+
return -1;
93+
}
94+
if(PyList_Append(*freelist, cobj)) {
95+
PyMem_FREE(ptr);
96+
Py_DECREF(cobj);
97+
return -1;
98+
}
99+
Py_DECREF(cobj);
100+
return 0;
101+
}
102+
103+
static int
104+
cleanreturn(int retval, PyObject *freelist)
105+
{
106+
if(freelist) {
107+
if((retval) == 0) {
108+
int len = PyList_GET_SIZE(freelist), i;
109+
for (i = 0; i < len; i++)
110+
PyMem_FREE(PyCObject_AsVoidPtr(
111+
PyList_GET_ITEM(freelist, i)));
112+
}
113+
Py_DECREF(freelist);
114+
}
115+
return retval;
116+
}
117+
118+
75119
static int
76120
vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
77121
{
@@ -86,6 +130,7 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
86130
char *formatsave = format;
87131
int i, len;
88132
char *msg;
133+
PyObject *freelist = NULL;
89134

90135
assert(compat || (args != (PyObject*)NULL));
91136

@@ -157,11 +202,11 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
157202
return 0;
158203
}
159204
msg = convertitem(args, &format, p_va, levels, msgbuf,
160-
sizeof(msgbuf));
205+
sizeof(msgbuf), &freelist);
161206
if (msg == NULL)
162-
return 1;
207+
return cleanreturn(1, freelist);
163208
seterror(levels[0], msg, levels+1, fname, message);
164-
return 0;
209+
return cleanreturn(0, freelist);
165210
}
166211
else {
167212
PyErr_SetString(PyExc_SystemError,
@@ -200,10 +245,10 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
200245
if (*format == '|')
201246
format++;
202247
msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va,
203-
levels, msgbuf, sizeof(msgbuf));
248+
levels, msgbuf, sizeof(msgbuf), &freelist);
204249
if (msg) {
205250
seterror(i+1, msg, levels, fname, message);
206-
return 0;
251+
return cleanreturn(0, freelist);
207252
}
208253
}
209254

@@ -212,10 +257,10 @@ vgetargs1(PyObject *args, char *format, va_list *p_va, int compat)
212257
*format != '|' && *format != ':' && *format != ';') {
213258
PyErr_Format(PyExc_SystemError,
214259
"bad format string: %.200s", formatsave);
215-
return 0;
260+
return cleanreturn(0, freelist);
216261
}
217262

218-
return 1;
263+
return cleanreturn(1, freelist);
219264
}
220265

221266

@@ -277,7 +322,7 @@ seterror(int iarg, char *msg, int *levels, char *fname, char *message)
277322

278323
static char *
279324
converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels,
280-
char *msgbuf, size_t bufsize, int toplevel)
325+
char *msgbuf, size_t bufsize, int toplevel, PyObject **freelist)
281326
{
282327
int level = 0;
283328
int n = 0;
@@ -327,7 +372,7 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels,
327372
PyObject *item;
328373
item = PySequence_GetItem(arg, i);
329374
msg = convertitem(item, &format, p_va, levels+1, msgbuf,
330-
bufsize);
375+
bufsize, freelist);
331376
/* PySequence_GetItem calls tp->sq_item, which INCREFs */
332377
Py_XDECREF(item);
333378
if (msg != NULL) {
@@ -345,20 +390,21 @@ converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels,
345390

346391
static char *
347392
convertitem(PyObject *arg, char **p_format, va_list *p_va, int *levels,
348-
char *msgbuf, size_t bufsize)
393+
char *msgbuf, size_t bufsize, PyObject **freelist)
349394
{
350395
char *msg;
351396
char *format = *p_format;
352397

353398
if (*format == '(' /* ')' */) {
354399
format++;
355400
msg = converttuple(arg, &format, p_va, levels, msgbuf,
356-
bufsize, 0);
401+
bufsize, 0, freelist);
357402
if (msg == NULL)
358403
format++;
359404
}
360405
else {
361-
msg = convertsimple(arg, &format, p_va, msgbuf, bufsize);
406+
msg = convertsimple(arg, &format, p_va, msgbuf, bufsize,
407+
freelist);
362408
if (msg != NULL)
363409
levels[0] = 0;
364410
}
@@ -409,7 +455,7 @@ float_argument_error(PyObject *arg)
409455

410456
static char *
411457
convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf,
412-
size_t bufsize)
458+
size_t bufsize, PyObject **freelist)
413459
{
414460
char *format = *p_format;
415461
char c = *format++;
@@ -836,10 +882,12 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf,
836882
int *buffer_len = va_arg(*p_va, int *);
837883

838884
format++;
839-
if (buffer_len == NULL)
885+
if (buffer_len == NULL) {
886+
Py_DECREF(s);
840887
return converterr(
841888
"(buffer_len is NULL)",
842889
arg, msgbuf, bufsize);
890+
}
843891
if (*buffer == NULL) {
844892
*buffer = PyMem_NEW(char, size + 1);
845893
if (*buffer == NULL) {
@@ -848,6 +896,12 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf,
848896
"(memory error)",
849897
arg, msgbuf, bufsize);
850898
}
899+
if(addcleanup(*buffer, freelist)) {
900+
Py_DECREF(s);
901+
return converterr(
902+
"(cleanup problem)",
903+
arg, msgbuf, bufsize);
904+
}
851905
} else {
852906
if (size + 1 > *buffer_len) {
853907
Py_DECREF(s);
@@ -874,16 +928,23 @@ convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf,
874928
PyMem_Free()ing it after usage
875929
876930
*/
877-
if ((int)strlen(PyString_AS_STRING(s)) != size)
931+
if ((int)strlen(PyString_AS_STRING(s)) != size) {
932+
Py_DECREF(s);
878933
return converterr(
879934
"(encoded string without NULL bytes)",
880935
arg, msgbuf, bufsize);
936+
}
881937
*buffer = PyMem_NEW(char, size + 1);
882938
if (*buffer == NULL) {
883939
Py_DECREF(s);
884940
return converterr("(memory error)",
885941
arg, msgbuf, bufsize);
886942
}
943+
if(addcleanup(*buffer, freelist)) {
944+
Py_DECREF(s);
945+
return converterr("(cleanup problem)",
946+
arg, msgbuf, bufsize);
947+
}
887948
memcpy(*buffer,
888949
PyString_AS_STRING(s),
889950
size + 1);
@@ -1103,6 +1164,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
11031164
char *formatsave;
11041165
int i, len, nargs, nkeywords;
11051166
char *msg, **p;
1167+
PyObject *freelist = NULL;
11061168

11071169
assert(args != NULL && PyTuple_Check(args));
11081170
assert(keywords == NULL || PyDict_Check(keywords));
@@ -1227,16 +1289,16 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
12271289
if (*format == '|')
12281290
format++;
12291291
msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va,
1230-
levels, msgbuf, sizeof(msgbuf));
1292+
levels, msgbuf, sizeof(msgbuf), &freelist);
12311293
if (msg) {
12321294
seterror(i+1, msg, levels, fname, message);
1233-
return 0;
1295+
return cleanreturn(0, freelist);
12341296
}
12351297
}
12361298

12371299
/* handle no keyword parameters in call */
12381300
if (nkeywords == 0)
1239-
return 1;
1301+
return cleanreturn(1, freelist);
12401302

12411303
/* convert the keyword arguments; this uses the format
12421304
string where it was left after processing args */
@@ -1248,23 +1310,23 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
12481310
if (item != NULL) {
12491311
Py_INCREF(item);
12501312
msg = convertitem(item, &format, p_va, levels, msgbuf,
1251-
sizeof(msgbuf));
1313+
sizeof(msgbuf), &freelist);
12521314
Py_DECREF(item);
12531315
if (msg) {
12541316
seterror(i+1, msg, levels, fname, message);
1255-
return 0;
1317+
return cleanreturn(0, freelist);
12561318
}
12571319
--nkeywords;
12581320
if (nkeywords == 0)
12591321
break;
12601322
}
12611323
else if (PyErr_Occurred())
1262-
return 0;
1324+
return cleanreturn(0, freelist);
12631325
else {
12641326
msg = skipitem(&format, p_va);
12651327
if (msg) {
12661328
seterror(i+1, msg, levels, fname, message);
1267-
return 0;
1329+
return cleanreturn(0, freelist);
12681330
}
12691331
}
12701332
}
@@ -1279,7 +1341,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
12791341
if (!PyString_Check(key)) {
12801342
PyErr_SetString(PyExc_TypeError,
12811343
"keywords must be strings");
1282-
return 0;
1344+
return cleanreturn(0, freelist);
12831345
}
12841346
ks = PyString_AsString(key);
12851347
for (i = 0; i < max; i++) {
@@ -1293,12 +1355,12 @@ vgetargskeywords(PyObject *args, PyObject *keywords, char *format,
12931355
"'%s' is an invalid keyword "
12941356
"argument for this function",
12951357
ks);
1296-
return 0;
1358+
return cleanreturn(0, freelist);
12971359
}
12981360
}
12991361
}
13001362

1301-
return 1;
1363+
return cleanreturn(1, freelist);
13021364
}
13031365

13041366

0 commit comments

Comments
 (0)