# HG changeset patch # User Christian Brabandt # Date 1695233704 -7200 # Node ID 924e9cb09df744e2154bebf8cf35e1b2458b95bf # Parent e93c5a23154b7133a63dd01592a55efd13c25f41 patch 9.0.1917: undefined behaviour with python function pointer Commit: https://github.com/vim/vim/commit/d606fccf6fd716bda43a8e1d11d898f438d28b82 Author: Yee Cheng Chin Date: Wed Sep 20 19:59:47 2023 +0200 patch 9.0.1917: undefined behaviour with python function pointer Problem: undefined behaviour with python function pointer Solution: correctly cast function pointers from void Fix more undefined behaviors in if_python Fix remaining UBSAN errors from Clang 17 in if_python in casting function pointers. Also fix a mistake where `PyMem_Free()` should be returning void, by the dynamic build is mistakenly casting it as a function that returns an int. closes: #13128 Signed-off-by: Christian Brabandt Co-authored-by: Yee Cheng Chin 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 @@ -2079,9 +2079,10 @@ typedef struct } dictiterinfo_T; static PyObject * -DictionaryIterNext(dictiterinfo_T **dii) +DictionaryIterNext(void **arg) { PyObject *ret; + dictiterinfo_T **dii = (dictiterinfo_T**)arg; if (!(*dii)->dii_todo) return NULL; @@ -2123,7 +2124,7 @@ DictionaryIter(DictionaryObject *self) dii->dii_todo = ht->ht_used; return IterNew(dii, - (destructorfun)(void *) PyMem_Free, (nextfun) DictionaryIterNext, + PyMem_Free, DictionaryIterNext, NULL, NULL, (PyObject *)self); } @@ -3081,17 +3082,19 @@ typedef struct } listiterinfo_T; static void -ListIterDestruct(listiterinfo_T *lii) -{ +ListIterDestruct(void *arg) +{ + listiterinfo_T *lii = (listiterinfo_T*)arg; list_rem_watch(lii->list, &lii->lw); list_unref(lii->list); PyMem_Free(lii); } static PyObject * -ListIterNext(listiterinfo_T **lii) +ListIterNext(void **arg) { PyObject *ret; + listiterinfo_T **lii = (listiterinfo_T**)arg; if (!((*lii)->lw.lw_item)) return NULL; @@ -3123,7 +3126,7 @@ ListIter(ListObject *self) ++l->lv_refcount; return IterNew(lii, - (destructorfun) ListIterDestruct, (nextfun) ListIterNext, + ListIterDestruct, ListIterNext, NULL, NULL, (PyObject *)self); } @@ -3747,9 +3750,10 @@ typedef struct } optiterinfo_T; static PyObject * -OptionsIterNext(optiterinfo_T **oii) +OptionsIterNext(void **arg) { char_u *name; + optiterinfo_T **oii = (optiterinfo_T**)arg; if ((name = option_iter_next(&((*oii)->lastoption), (*oii)->opt_type))) return PyString_FromString((char *)name); @@ -3772,7 +3776,7 @@ OptionsIter(OptionsObject *self) oii->lastoption = NULL; return IterNew(oii, - (destructorfun)(void *) PyMem_Free, (nextfun) OptionsIterNext, + PyMem_Free, OptionsIterNext, NULL, NULL, (PyObject *)self); } @@ -4149,6 +4153,12 @@ CheckWindow(WindowObject *self) return 0; } + static int +CheckWindowCb(void *self) +{ + return CheckWindow((WindowObject*)self); +} + static PyObject * WindowNew(win_T *win, tabpage_T *tab) { @@ -4287,7 +4297,7 @@ WindowAttr(WindowObject *self, char *nam else if (strcmp(name, "vars") == 0) return NEW_DICTIONARY(self->win->w_vars); else if (strcmp(name, "options") == 0) - return OptionsNew(SREQ_WIN, self->win, (checkfun) CheckWindow, + return OptionsNew(SREQ_WIN, self->win, CheckWindowCb, (PyObject *) self); else if (strcmp(name, "number") == 0) { @@ -5142,6 +5152,12 @@ CheckBuffer(BufferObject *self) return 0; } + static int +CheckBufferCb(void *self) +{ + return CheckBuffer((BufferObject*)self); +} + static PyObject * RBItem(BufferObject *self, PyInt n, PyInt start, PyInt end) { @@ -5544,7 +5560,7 @@ BufferAttr(BufferObject *self, char *nam else if (strcmp(name, "vars") == 0) return NEW_DICTIONARY(self->buf->b_vars); else if (strcmp(name, "options") == 0) - return OptionsNew(SREQ_BUF, self->buf, (checkfun) CheckBuffer, + return OptionsNew(SREQ_BUF, self->buf, CheckBufferCb, (PyObject *) self); else if (strcmp(name, "__members__") == 0) return ObjectDir(NULL, BufferAttrs); @@ -5742,8 +5758,9 @@ BufMapItem(PyObject *self UNUSED, PyObje } static void -BufMapIterDestruct(PyObject *buffer) -{ +BufMapIterDestruct(void* arg) +{ + PyObject *buffer = (PyObject*)arg; // Iteration was stopped before all buffers were processed if (buffer) { @@ -5752,26 +5769,29 @@ BufMapIterDestruct(PyObject *buffer) } static int -BufMapIterTraverse(PyObject *buffer, visitproc visit, void *arg) -{ +BufMapIterTraverse(void *iter, visitproc visit, void *arg) +{ + PyObject *buffer = (PyObject*)iter; if (buffer) Py_VISIT(buffer); return 0; } static int -BufMapIterClear(PyObject **buffer) -{ +BufMapIterClear(void **iter) +{ + PyObject **buffer = (PyObject**)iter; if (*buffer) Py_CLEAR(*buffer); return 0; } static PyObject * -BufMapIterNext(PyObject **buffer) +BufMapIterNext(void **arg) { PyObject *next; PyObject *ret; + PyObject **buffer = (PyObject**)arg; if (!*buffer) return NULL; @@ -5801,8 +5821,8 @@ BufMapIter(PyObject *self) buffer = BufferNew(firstbuf); return IterNew(buffer, - (destructorfun) BufMapIterDestruct, (nextfun) BufMapIterNext, - (traversefun) BufMapIterTraverse, (clearfun) BufMapIterClear, + BufMapIterDestruct, BufMapIterNext, + BufMapIterTraverse, BufMapIterClear, (PyObject *)self); } @@ -6124,13 +6144,14 @@ out: } static void -run_eval(const char *cmd, typval_T *rettv +run_eval(const char *cmd, void *arg #ifdef PY_CAN_RECURSE , PyGILState_STATE *pygilstate UNUSED #endif ) { PyObject *run_ret; + typval_T *rettv = (typval_T*)arg; run_ret = PyRun_String((char *)cmd, Py_eval_input, globals, globals); if (run_ret == NULL) diff --git a/src/if_python.c b/src/if_python.c --- a/src/if_python.c +++ b/src/if_python.c @@ -317,7 +317,7 @@ struct PyMethodDef { Py_ssize_t a; }; */ static int(*dll_PyArg_Parse)(PyObject *, char *, ...); static int(*dll_PyArg_ParseTuple)(PyObject *, char *, ...); -static int(*dll_PyMem_Free)(void *); +static void(*dll_PyMem_Free)(void *); static void* (*dll_PyMem_Malloc)(size_t); static int(*dll_PyDict_SetItemString)(PyObject *dp, char *key, PyObject *item); static int(*dll_PyErr_BadArgument)(void); diff --git a/src/if_python3.c b/src/if_python3.c --- a/src/if_python3.c +++ b/src/if_python3.c @@ -442,7 +442,7 @@ static void(*py3_PyEval_RestoreThread)(P static PyThreadState*(*py3_PyEval_SaveThread)(void); static int (*py3_PyArg_Parse)(PyObject *, char *, ...); static int (*py3_PyArg_ParseTuple)(PyObject *, char *, ...); -static int (*py3_PyMem_Free)(void *); +static void (*py3_PyMem_Free)(void *); static void* (*py3_PyMem_Malloc)(size_t); static int (*py3_Py_IsInitialized)(void); static void (*py3_PyErr_Clear)(void); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -700,6 +700,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1917, +/**/ 1916, /**/ 1915,