# HG changeset patch # User Bram Moolenaar # Date 1369908889 -7200 # Node ID 21a99611149b0f1c200e001ec26b8b07c6e28c45 # Parent e8bc429ce5fc53a911600d414ca16c39d5c3ad5d updated for version 7.3.1056 Problem: Python: possible memory leaks. Solution: Python patch 15. (ZyX) Fix will follow later. diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -412,7 +412,6 @@ static int get_string_tv __ARGS((char_u static int get_lit_string_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate)); static int get_list_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate)); static int rettv_list_alloc __ARGS((typval_T *rettv)); -static void listitem_free __ARGS((listitem_T *item)); static long list_len __ARGS((list_T *l)); static int list_equal __ARGS((list_T *l1, list_T *l2, int ic, int recursive)); static int dict_equal __ARGS((dict_T *d1, dict_T *d2, int ic, int recursive)); @@ -428,7 +427,6 @@ static int list_join_inner __ARGS((garra static int list_join __ARGS((garray_T *gap, list_T *l, char_u *sep, int echo, int copyID)); static int free_unref_items __ARGS((int copyID)); static int rettv_dict_alloc __ARGS((typval_T *rettv)); -static void dict_free __ARGS((dict_T *d, int recurse)); static dictitem_T *dictitem_copy __ARGS((dictitem_T *org)); static void dictitem_remove __ARGS((dict_T *dict, dictitem_T *item)); static dict_T *dict_copy __ARGS((dict_T *orig, int deep, int copyID)); @@ -5955,7 +5953,7 @@ listitem_alloc() /* * Free a list item. Also clears the value. Does not notify watchers. */ - static void + void listitem_free(item) listitem_T *item; { @@ -7031,7 +7029,7 @@ dict_unref(d) * Free a Dictionary, including all items it contains. * Ignores the reference count. */ - static void + void dict_free(d, recurse) dict_T *d; int recurse; /* Free Lists and Dictionaries recursively. */ @@ -8353,7 +8351,7 @@ get_func_tv(name, len, rettv, arg, first /* * Call a function with its resolved parameters - * Return OK when the function can't be called, FAIL otherwise. + * Return FAIL when the function can't be called, OK otherwise. * Also returns OK when an error was encountered while executing the function. */ static int diff --git a/src/if_py_both.h b/src/if_py_both.h --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -32,8 +32,15 @@ typedef int Py_ssize_t; /* Python 2.4 a #define DICTKEY_DECL \ PyObject *dictkey_todecref; +#define DICTKEY_CHECK_EMPTY(err) \ + if (*key == NUL) \ + { \ + PyErr_SetString(PyExc_ValueError, _("empty keys are not allowed")); \ + return err; \ + } +#define DICTKEY_SET_KEY (key = StringToChars(keyObject, &dictkey_todecref)) #define DICTKEY_GET(err, decref) \ - if (!(key = StringToChars(keyObject, &dictkey_todecref))) \ + if (!DICTKEY_SET_KEY) \ { \ if (decref) \ { \ @@ -43,11 +50,7 @@ typedef int Py_ssize_t; /* Python 2.4 a } \ if (decref && !dictkey_todecref) \ dictkey_todecref = keyObject; \ - if (*key == NUL) \ - { \ - PyErr_SetString(PyExc_ValueError, _("empty keys are not allowed")); \ - return err; \ - } + DICTKEY_CHECK_EMPTY(err) #define DICTKEY_UNREF \ Py_XDECREF(dictkey_todecref); @@ -651,9 +654,13 @@ VimEval(PyObject *self UNUSED, PyObject /* Convert the Vim type into a Python type. Create a dictionary that's * used to check for recursive loops. */ - lookup_dict = PyDict_New(); - result = VimToPython(our_tv, 1, lookup_dict); - Py_DECREF(lookup_dict); + if (!(lookup_dict = PyDict_New())) + result = NULL; + else + { + result = VimToPython(our_tv, 1, lookup_dict); + Py_DECREF(lookup_dict); + } Py_BEGIN_ALLOW_THREADS @@ -1401,7 +1408,9 @@ ListConcatInPlace(ListObject *self, PyOb return NULL; } - lookup_dict = PyDict_New(); + if (!(lookup_dict = PyDict_New())) + return NULL; + if (list_py_concat(l, obj, lookup_dict) == -1) { Py_DECREF(lookup_dict); @@ -4023,12 +4032,8 @@ pydict_to_tv(PyObject *obj, typval_T *tv PyObject *valObject; Py_ssize_t iter = 0; - dict = dict_alloc(); - if (dict == NULL) - { - PyErr_NoMemory(); + if (!(dict = dict_alloc())) return -1; - } tv->v_type = VAR_DICT; tv->vval.v_dict = dict; @@ -4038,9 +4043,17 @@ pydict_to_tv(PyObject *obj, typval_T *tv DICTKEY_DECL if (keyObject == NULL || valObject == NULL) + { + dict_unref(dict); return -1; - - DICTKEY_GET(-1, 0) + } + + if (!DICTKEY_SET_KEY) + { + dict_unref(dict); + return -1; + } + DICTKEY_CHECK_EMPTY(-1) di = dictitem_alloc(key); @@ -4049,6 +4062,7 @@ pydict_to_tv(PyObject *obj, typval_T *tv if (di == NULL) { PyErr_NoMemory(); + dict_unref(dict); return -1; } di->di_tv.v_lock = 0; @@ -4056,6 +4070,7 @@ pydict_to_tv(PyObject *obj, typval_T *tv if (_ConvertFromPyObject(valObject, &di->di_tv, lookup_dict) == -1) { vim_free(di); + dict_unref(dict); return -1; } @@ -4063,10 +4078,13 @@ pydict_to_tv(PyObject *obj, typval_T *tv { clear_tv(&di->di_tv); vim_free(di); + dict_unref(dict); PyErr_SetVim(_("failed to add key to dictionary")); return -1; } } + + --dict->dv_refcount; return 0; } @@ -4082,19 +4100,18 @@ pymap_to_tv(PyObject *obj, typval_T *tv, PyObject *valObject; Py_ssize_t lsize; - dict = dict_alloc(); - if (dict == NULL) - { - PyErr_NoMemory(); + if (!(dict = dict_alloc())) return -1; - } tv->v_type = VAR_DICT; tv->vval.v_dict = dict; list = PyMapping_Items(obj); if (list == NULL) + { + dict_unref(dict); return -1; + } lsize = PyList_Size(list); while (lsize--) { @@ -4104,6 +4121,7 @@ pymap_to_tv(PyObject *obj, typval_T *tv, if (litem == NULL) { Py_DECREF(list); + dict_unref(dict); return -1; } @@ -4111,15 +4129,25 @@ pymap_to_tv(PyObject *obj, typval_T *tv, { Py_DECREF(list); Py_DECREF(litem); + dict_unref(dict); return -1; } - DICTKEY_GET(-1, 1) + if (!DICTKEY_SET_KEY) + { + dict_unref(dict); + Py_DECREF(list); + Py_DECREF(litem); + DICTKEY_UNREF + return -1; + } + DICTKEY_CHECK_EMPTY(-1) if (!(valObject = PyTuple_GetItem(litem, 1))) { Py_DECREF(list); Py_DECREF(litem); + dict_unref(dict); DICTKEY_UNREF return -1; } @@ -4133,7 +4161,7 @@ pymap_to_tv(PyObject *obj, typval_T *tv, if (di == NULL) { Py_DECREF(list); - Py_DECREF(valObject); + dict_unref(dict); PyErr_NoMemory(); return -1; } @@ -4142,75 +4170,87 @@ pymap_to_tv(PyObject *obj, typval_T *tv, if (_ConvertFromPyObject(valObject, &di->di_tv, lookup_dict) == -1) { vim_free(di); + dict_unref(dict); Py_DECREF(list); - Py_DECREF(valObject); return -1; } - Py_DECREF(valObject); - if (dict_add(dict, di) == FAIL) { - clear_tv(&di->di_tv); - vim_free(di); + dictitem_free(di); + dict_unref(dict); Py_DECREF(list); PyErr_SetVim(_("failed to add key to dictionary")); return -1; } } + --dict->dv_refcount; Py_DECREF(list); return 0; } + static list_T * +py_list_alloc() +{ + list_T *r; + + if (!(r = list_alloc())) + { + PyErr_NoMemory(); + return NULL; + } + ++r->lv_refcount; + + return r; +} + static int pyseq_to_tv(PyObject *obj, typval_T *tv, PyObject *lookup_dict) { list_T *l; - l = list_alloc(); - if (l == NULL) - { - PyErr_NoMemory(); + if (!(l = py_list_alloc())) return -1; - } tv->v_type = VAR_LIST; tv->vval.v_list = l; if (list_py_concat(l, obj, lookup_dict) == -1) + { + list_unref(l); return -1; - + } + + --l->lv_refcount; return 0; } static int pyiter_to_tv(PyObject *obj, typval_T *tv, PyObject *lookup_dict) { - PyObject *iterator = PyObject_GetIter(obj); + PyObject *iterator; PyObject *item; list_T *l; listitem_T *li; - l = list_alloc(); - - if (l == NULL) - { - PyErr_NoMemory(); + if (!(l = py_list_alloc())) return -1; - } tv->vval.v_list = l; tv->v_type = VAR_LIST; - - if (iterator == NULL) + if (!(iterator = PyObject_GetIter(obj))) + { + list_unref(l); return -1; + } while ((item = PyIter_Next(iterator))) { li = listitem_alloc(); if (li == NULL) { + list_unref(l); Py_DECREF(iterator); PyErr_NoMemory(); return -1; @@ -4219,6 +4259,8 @@ pyiter_to_tv(PyObject *obj, typval_T *tv if (_ConvertFromPyObject(item, &li->li_tv, lookup_dict) == -1) { + list_unref(l); + listitem_free(li); Py_DECREF(item); Py_DECREF(iterator); return -1; @@ -4230,6 +4272,15 @@ pyiter_to_tv(PyObject *obj, typval_T *tv } Py_DECREF(iterator); + + /* Iterator may have finished due to an exception */ + if (PyErr_Occurred()) + { + list_unref(l); + return -1; + } + + --l->lv_refcount; return 0; } @@ -4295,7 +4346,8 @@ ConvertFromPyObject(PyObject *obj, typva PyObject *lookup_dict; int r; - lookup_dict = PyDict_New(); + if (!(lookup_dict = PyDict_New())) + return -1; r = _ConvertFromPyObject(obj, tv, lookup_dict); Py_DECREF(lookup_dict); return r; diff --git a/src/proto/eval.pro b/src/proto/eval.pro --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -49,6 +49,7 @@ list_T *list_alloc __ARGS((void)); void list_unref __ARGS((list_T *l)); void list_free __ARGS((list_T *l, int recurse)); listitem_T *listitem_alloc __ARGS((void)); +void listitem_free __ARGS((listitem_T *item)); void listitem_remove __ARGS((list_T *l, listitem_T *item)); dictitem_T *dict_lookup __ARGS((hashitem_T *hi)); listitem_T *list_find __ARGS((list_T *l, long n)); @@ -65,6 +66,7 @@ void set_ref_in_list __ARGS((list_T *l, void set_ref_in_item __ARGS((typval_T *tv, int copyID)); dict_T *dict_alloc __ARGS((void)); void dict_unref __ARGS((dict_T *d)); +void dict_free __ARGS((dict_T *d, int recurse)); dictitem_T *dictitem_alloc __ARGS((char_u *key)); void dictitem_free __ARGS((dictitem_T *item)); int dict_add __ARGS((dict_T *d, dictitem_T *item)); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1056, +/**/ 1055, /**/ 1054,