Mercurial > vim
comparison src/if_py_both.h @ 33303:924e9cb09df7 v9.0.1917
patch 9.0.1917: undefined behaviour with python function pointer
Commit: https://github.com/vim/vim/commit/d606fccf6fd716bda43a8e1d11d898f438d28b82
Author: Yee Cheng Chin <ychin.git@gmail.com>
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 <cb@256bit.org>
Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Wed, 20 Sep 2023 20:15:04 +0200 |
parents | a43861545866 |
children | a9f0f0eae10e |
comparison
equal
deleted
inserted
replaced
33302:e93c5a23154b | 33303:924e9cb09df7 |
---|---|
2077 hashitem_T *dii_hi; | 2077 hashitem_T *dii_hi; |
2078 long_u dii_todo; | 2078 long_u dii_todo; |
2079 } dictiterinfo_T; | 2079 } dictiterinfo_T; |
2080 | 2080 |
2081 static PyObject * | 2081 static PyObject * |
2082 DictionaryIterNext(dictiterinfo_T **dii) | 2082 DictionaryIterNext(void **arg) |
2083 { | 2083 { |
2084 PyObject *ret; | 2084 PyObject *ret; |
2085 dictiterinfo_T **dii = (dictiterinfo_T**)arg; | |
2085 | 2086 |
2086 if (!(*dii)->dii_todo) | 2087 if (!(*dii)->dii_todo) |
2087 return NULL; | 2088 return NULL; |
2088 | 2089 |
2089 if ((*dii)->dii_ht->ht_changed != (*dii)->dii_changed) | 2090 if ((*dii)->dii_ht->ht_changed != (*dii)->dii_changed) |
2121 dii->dii_ht = ht; | 2122 dii->dii_ht = ht; |
2122 dii->dii_hi = ht->ht_array; | 2123 dii->dii_hi = ht->ht_array; |
2123 dii->dii_todo = ht->ht_used; | 2124 dii->dii_todo = ht->ht_used; |
2124 | 2125 |
2125 return IterNew(dii, | 2126 return IterNew(dii, |
2126 (destructorfun)(void *) PyMem_Free, (nextfun) DictionaryIterNext, | 2127 PyMem_Free, DictionaryIterNext, |
2127 NULL, NULL, (PyObject *)self); | 2128 NULL, NULL, (PyObject *)self); |
2128 } | 2129 } |
2129 | 2130 |
2130 static int | 2131 static int |
2131 DictionaryAssItem( | 2132 DictionaryAssItem( |
3079 listwatch_T lw; | 3080 listwatch_T lw; |
3080 list_T *list; | 3081 list_T *list; |
3081 } listiterinfo_T; | 3082 } listiterinfo_T; |
3082 | 3083 |
3083 static void | 3084 static void |
3084 ListIterDestruct(listiterinfo_T *lii) | 3085 ListIterDestruct(void *arg) |
3085 { | 3086 { |
3087 listiterinfo_T *lii = (listiterinfo_T*)arg; | |
3086 list_rem_watch(lii->list, &lii->lw); | 3088 list_rem_watch(lii->list, &lii->lw); |
3087 list_unref(lii->list); | 3089 list_unref(lii->list); |
3088 PyMem_Free(lii); | 3090 PyMem_Free(lii); |
3089 } | 3091 } |
3090 | 3092 |
3091 static PyObject * | 3093 static PyObject * |
3092 ListIterNext(listiterinfo_T **lii) | 3094 ListIterNext(void **arg) |
3093 { | 3095 { |
3094 PyObject *ret; | 3096 PyObject *ret; |
3097 listiterinfo_T **lii = (listiterinfo_T**)arg; | |
3095 | 3098 |
3096 if (!((*lii)->lw.lw_item)) | 3099 if (!((*lii)->lw.lw_item)) |
3097 return NULL; | 3100 return NULL; |
3098 | 3101 |
3099 if (!(ret = ConvertToPyObject(&((*lii)->lw.lw_item->li_tv)))) | 3102 if (!(ret = ConvertToPyObject(&((*lii)->lw.lw_item->li_tv)))) |
3121 lii->lw.lw_item = l->lv_first; | 3124 lii->lw.lw_item = l->lv_first; |
3122 lii->list = l; | 3125 lii->list = l; |
3123 ++l->lv_refcount; | 3126 ++l->lv_refcount; |
3124 | 3127 |
3125 return IterNew(lii, | 3128 return IterNew(lii, |
3126 (destructorfun) ListIterDestruct, (nextfun) ListIterNext, | 3129 ListIterDestruct, ListIterNext, |
3127 NULL, NULL, (PyObject *)self); | 3130 NULL, NULL, (PyObject *)self); |
3128 } | 3131 } |
3129 | 3132 |
3130 static char *ListAttrs[] = { | 3133 static char *ListAttrs[] = { |
3131 "locked", | 3134 "locked", |
3745 void *lastoption; | 3748 void *lastoption; |
3746 int opt_type; | 3749 int opt_type; |
3747 } optiterinfo_T; | 3750 } optiterinfo_T; |
3748 | 3751 |
3749 static PyObject * | 3752 static PyObject * |
3750 OptionsIterNext(optiterinfo_T **oii) | 3753 OptionsIterNext(void **arg) |
3751 { | 3754 { |
3752 char_u *name; | 3755 char_u *name; |
3756 optiterinfo_T **oii = (optiterinfo_T**)arg; | |
3753 | 3757 |
3754 if ((name = option_iter_next(&((*oii)->lastoption), (*oii)->opt_type))) | 3758 if ((name = option_iter_next(&((*oii)->lastoption), (*oii)->opt_type))) |
3755 return PyString_FromString((char *)name); | 3759 return PyString_FromString((char *)name); |
3756 | 3760 |
3757 return NULL; | 3761 return NULL; |
3770 | 3774 |
3771 oii->opt_type = self->opt_type; | 3775 oii->opt_type = self->opt_type; |
3772 oii->lastoption = NULL; | 3776 oii->lastoption = NULL; |
3773 | 3777 |
3774 return IterNew(oii, | 3778 return IterNew(oii, |
3775 (destructorfun)(void *) PyMem_Free, (nextfun) OptionsIterNext, | 3779 PyMem_Free, OptionsIterNext, |
3776 NULL, NULL, (PyObject *)self); | 3780 NULL, NULL, (PyObject *)self); |
3777 } | 3781 } |
3778 | 3782 |
3779 static int | 3783 static int |
3780 set_option_value_err(char_u *key, int numval, char_u *stringval, int opt_flags) | 3784 set_option_value_err(char_u *key, int numval, char_u *stringval, int opt_flags) |
4147 } | 4151 } |
4148 | 4152 |
4149 return 0; | 4153 return 0; |
4150 } | 4154 } |
4151 | 4155 |
4156 static int | |
4157 CheckWindowCb(void *self) | |
4158 { | |
4159 return CheckWindow((WindowObject*)self); | |
4160 } | |
4161 | |
4152 static PyObject * | 4162 static PyObject * |
4153 WindowNew(win_T *win, tabpage_T *tab) | 4163 WindowNew(win_T *win, tabpage_T *tab) |
4154 { | 4164 { |
4155 /* | 4165 /* |
4156 * We need to handle deletion of windows underneath us. | 4166 * We need to handle deletion of windows underneath us. |
4285 else if (strcmp(name, "col") == 0) | 4295 else if (strcmp(name, "col") == 0) |
4286 return PyLong_FromLong((long)(self->win->w_wincol)); | 4296 return PyLong_FromLong((long)(self->win->w_wincol)); |
4287 else if (strcmp(name, "vars") == 0) | 4297 else if (strcmp(name, "vars") == 0) |
4288 return NEW_DICTIONARY(self->win->w_vars); | 4298 return NEW_DICTIONARY(self->win->w_vars); |
4289 else if (strcmp(name, "options") == 0) | 4299 else if (strcmp(name, "options") == 0) |
4290 return OptionsNew(SREQ_WIN, self->win, (checkfun) CheckWindow, | 4300 return OptionsNew(SREQ_WIN, self->win, CheckWindowCb, |
4291 (PyObject *) self); | 4301 (PyObject *) self); |
4292 else if (strcmp(name, "number") == 0) | 4302 else if (strcmp(name, "number") == 0) |
4293 { | 4303 { |
4294 if (CheckTabPage(self->tabObject)) | 4304 if (CheckTabPage(self->tabObject)) |
4295 return NULL; | 4305 return NULL; |
5140 } | 5150 } |
5141 | 5151 |
5142 return 0; | 5152 return 0; |
5143 } | 5153 } |
5144 | 5154 |
5155 static int | |
5156 CheckBufferCb(void *self) | |
5157 { | |
5158 return CheckBuffer((BufferObject*)self); | |
5159 } | |
5160 | |
5145 static PyObject * | 5161 static PyObject * |
5146 RBItem(BufferObject *self, PyInt n, PyInt start, PyInt end) | 5162 RBItem(BufferObject *self, PyInt n, PyInt start, PyInt end) |
5147 { | 5163 { |
5148 if (CheckBuffer(self)) | 5164 if (CheckBuffer(self)) |
5149 return NULL; | 5165 return NULL; |
5542 else if (strcmp(name, "number") == 0) | 5558 else if (strcmp(name, "number") == 0) |
5543 return Py_BuildValue(Py_ssize_t_fmt, self->buf->b_fnum); | 5559 return Py_BuildValue(Py_ssize_t_fmt, self->buf->b_fnum); |
5544 else if (strcmp(name, "vars") == 0) | 5560 else if (strcmp(name, "vars") == 0) |
5545 return NEW_DICTIONARY(self->buf->b_vars); | 5561 return NEW_DICTIONARY(self->buf->b_vars); |
5546 else if (strcmp(name, "options") == 0) | 5562 else if (strcmp(name, "options") == 0) |
5547 return OptionsNew(SREQ_BUF, self->buf, (checkfun) CheckBuffer, | 5563 return OptionsNew(SREQ_BUF, self->buf, CheckBufferCb, |
5548 (PyObject *) self); | 5564 (PyObject *) self); |
5549 else if (strcmp(name, "__members__") == 0) | 5565 else if (strcmp(name, "__members__") == 0) |
5550 return ObjectDir(NULL, BufferAttrs); | 5566 return ObjectDir(NULL, BufferAttrs); |
5551 else | 5567 else |
5552 return NULL; | 5568 return NULL; |
5740 return NULL; | 5756 return NULL; |
5741 } | 5757 } |
5742 } | 5758 } |
5743 | 5759 |
5744 static void | 5760 static void |
5745 BufMapIterDestruct(PyObject *buffer) | 5761 BufMapIterDestruct(void* arg) |
5746 { | 5762 { |
5763 PyObject *buffer = (PyObject*)arg; | |
5747 // Iteration was stopped before all buffers were processed | 5764 // Iteration was stopped before all buffers were processed |
5748 if (buffer) | 5765 if (buffer) |
5749 { | 5766 { |
5750 Py_DECREF(buffer); | 5767 Py_DECREF(buffer); |
5751 } | 5768 } |
5752 } | 5769 } |
5753 | 5770 |
5754 static int | 5771 static int |
5755 BufMapIterTraverse(PyObject *buffer, visitproc visit, void *arg) | 5772 BufMapIterTraverse(void *iter, visitproc visit, void *arg) |
5756 { | 5773 { |
5774 PyObject *buffer = (PyObject*)iter; | |
5757 if (buffer) | 5775 if (buffer) |
5758 Py_VISIT(buffer); | 5776 Py_VISIT(buffer); |
5759 return 0; | 5777 return 0; |
5760 } | 5778 } |
5761 | 5779 |
5762 static int | 5780 static int |
5763 BufMapIterClear(PyObject **buffer) | 5781 BufMapIterClear(void **iter) |
5764 { | 5782 { |
5783 PyObject **buffer = (PyObject**)iter; | |
5765 if (*buffer) | 5784 if (*buffer) |
5766 Py_CLEAR(*buffer); | 5785 Py_CLEAR(*buffer); |
5767 return 0; | 5786 return 0; |
5768 } | 5787 } |
5769 | 5788 |
5770 static PyObject * | 5789 static PyObject * |
5771 BufMapIterNext(PyObject **buffer) | 5790 BufMapIterNext(void **arg) |
5772 { | 5791 { |
5773 PyObject *next; | 5792 PyObject *next; |
5774 PyObject *ret; | 5793 PyObject *ret; |
5794 PyObject **buffer = (PyObject**)arg; | |
5775 | 5795 |
5776 if (!*buffer) | 5796 if (!*buffer) |
5777 return NULL; | 5797 return NULL; |
5778 | 5798 |
5779 ret = *buffer; | 5799 ret = *buffer; |
5799 { | 5819 { |
5800 PyObject *buffer; | 5820 PyObject *buffer; |
5801 | 5821 |
5802 buffer = BufferNew(firstbuf); | 5822 buffer = BufferNew(firstbuf); |
5803 return IterNew(buffer, | 5823 return IterNew(buffer, |
5804 (destructorfun) BufMapIterDestruct, (nextfun) BufMapIterNext, | 5824 BufMapIterDestruct, BufMapIterNext, |
5805 (traversefun) BufMapIterTraverse, (clearfun) BufMapIterClear, | 5825 BufMapIterTraverse, BufMapIterClear, |
5806 (PyObject *)self); | 5826 (PyObject *)self); |
5807 } | 5827 } |
5808 | 5828 |
5809 static PyMappingMethods BufMapAsMapping = { | 5829 static PyMappingMethods BufMapAsMapping = { |
5810 (lenfunc) BufMapLength, | 5830 (lenfunc) BufMapLength, |
6122 check_cursor(); | 6142 check_cursor(); |
6123 update_curbuf(UPD_NOT_VALID); | 6143 update_curbuf(UPD_NOT_VALID); |
6124 } | 6144 } |
6125 | 6145 |
6126 static void | 6146 static void |
6127 run_eval(const char *cmd, typval_T *rettv | 6147 run_eval(const char *cmd, void *arg |
6128 #ifdef PY_CAN_RECURSE | 6148 #ifdef PY_CAN_RECURSE |
6129 , PyGILState_STATE *pygilstate UNUSED | 6149 , PyGILState_STATE *pygilstate UNUSED |
6130 #endif | 6150 #endif |
6131 ) | 6151 ) |
6132 { | 6152 { |
6133 PyObject *run_ret; | 6153 PyObject *run_ret; |
6154 typval_T *rettv = (typval_T*)arg; | |
6134 | 6155 |
6135 run_ret = PyRun_String((char *)cmd, Py_eval_input, globals, globals); | 6156 run_ret = PyRun_String((char *)cmd, Py_eval_input, globals, globals); |
6136 if (run_ret == NULL) | 6157 if (run_ret == NULL) |
6137 { | 6158 { |
6138 if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit)) | 6159 if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit)) |