# HG changeset patch # User Bram Moolenaar # Date 1372708984 -7200 # Node ID 34c629c3b4bab5fc755e83869d929f8cb322bfcd # Parent 0f6ca569356bd2ef6d027870c1c5810d124c8178 updated for version 7.3.1287 Problem: Python SystemExit exception is not handled properly. Solution: Catch the exception and give an error. (Yasuhiro Matsumoto, Ken Takata) diff --git a/runtime/doc/if_pyth.txt b/runtime/doc/if_pyth.txt --- a/runtime/doc/if_pyth.txt +++ b/runtime/doc/if_pyth.txt @@ -740,6 +740,11 @@ 2. Vim is recompiled for only one Python 3. You undefine PY_NO_RTLD_GLOBAL in auto/config.h after configuration. This may crash Vim though. + *E880* +Raising SystemExit exception in python isn't endorsed way to quit vim, use: > + :py vim.command("qall!") +< + *has-python* You can test what Python version is available with: > if has('python') 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 @@ -13,6 +13,8 @@ * Common code for if_python.c and if_python3.c. */ +static char_u e_py_systemexit[] = "E880: Can't handle SystemExit of %s exception in vim"; + #if PY_VERSION_HEX < 0x02050000 typedef int Py_ssize_t; /* Python 2.4 and earlier don't have this type. */ #endif @@ -275,7 +277,7 @@ ObjectDir(PyObject *self, char **attribu if (self) for (method = self->ob_type->tp_methods ; method->ml_name != NULL ; ++method) - if (add_string(ret, (char *) method->ml_name)) + if (add_string(ret, (char *)method->ml_name)) { Py_DECREF(ret); return NULL; @@ -549,8 +551,9 @@ VimTryStart(void) VimTryEnd(void) { --trylevel; - /* Without this it stops processing all subsequent VimL commands and - * generates strange error messages if I e.g. try calling Test() in a cycle */ + /* Without this it stops processing all subsequent VimL commands and + * generates strange error messages if I e.g. try calling Test() in a + * cycle */ did_emsg = FALSE; /* Keyboard interrupt should be preferred over anything else */ if (got_int) @@ -570,7 +573,7 @@ VimTryEnd(void) /* Finally transform VimL exception to python one */ else { - PyErr_SetVim((char *) current_exception->value); + PyErr_SetVim((char *)current_exception->value); discard_current_exception(); return -1; } @@ -667,7 +670,7 @@ VimToPython(typval_T *our_tv, int depth, /* For backwards compatibility numbers are stored as strings. */ sprintf(buf, "%ld", (long)our_tv->vval.v_number); - ret = PyString_FromString((char *) buf); + ret = PyString_FromString((char *)buf); } # ifdef FEAT_FLOAT else if (our_tv->v_type == VAR_FLOAT) @@ -675,7 +678,7 @@ VimToPython(typval_T *our_tv, int depth, char buf[NUMBUFLEN]; sprintf(buf, "%f", our_tv->vval.v_float); - ret = PyString_FromString((char *) buf); + ret = PyString_FromString((char *)buf); } # endif else if (our_tv->v_type == VAR_LIST) @@ -955,7 +958,7 @@ map_rtp_callback(char_u *path, void *_da PyObject *pathObject; map_rtp_data *mr_data = *((map_rtp_data **) data); - if (!(pathObject = PyString_FromString((char *) path))) + if (!(pathObject = PyString_FromString((char *)path))) { *data = NULL; return; @@ -1124,7 +1127,7 @@ find_module(char *fullname, char *tail, PyObject *module; char *dot; - if ((dot = (char *) vim_strchr((char_u *) tail, '.'))) + if ((dot = (char *)vim_strchr((char_u *) tail, '.'))) { /* * There is a dot in the name: call find_module recursively without the @@ -1658,7 +1661,7 @@ DictionaryIterNext(dictiterinfo_T **dii) --((*dii)->todo); - if (!(ret = PyBytes_FromString((char *) (*dii)->hi->hi_key))) + if (!(ret = PyBytes_FromString((char *)(*dii)->hi->hi_key))) return NULL; return ret; @@ -2680,12 +2683,12 @@ FunctionCall(FunctionObject *self, PyObj FunctionRepr(FunctionObject *self) { #ifdef Py_TRACE_REFS - /* For unknown reason self->name may be NULL after calling + /* For unknown reason self->name may be NULL after calling * Finalize */ return PyString_FromFormat("", - (self->name == NULL ? "" : (char *) self->name)); + (self->name == NULL ? "" : (char *)self->name)); #else - return PyString_FromFormat("", (char *) self->name); + return PyString_FromFormat("", (char *)self->name); #endif } @@ -2809,7 +2812,7 @@ OptionsItem(OptionsObject *self, PyObjec { if (stringval) { - PyObject *ret = PyBytes_FromString((char *) stringval); + PyObject *ret = PyBytes_FromString((char *)stringval); vim_free(stringval); return ret; } @@ -4525,7 +4528,7 @@ BufferAttr(BufferObject *self, char *nam { if (strcmp(name, "name") == 0) return PyString_FromString((self->buf->b_ffname == NULL - ? "" : (char *) self->buf->b_ffname)); + ? "" : (char *)self->buf->b_ffname)); else if (strcmp(name, "number") == 0) return Py_BuildValue(Py_ssize_t_fmt, self->buf->b_fnum); else if (strcmp(name, "vars") == 0) @@ -4961,7 +4964,19 @@ run_cmd(const char *cmd, void *arg UNUSE #endif ) { - PyRun_SimpleString((char *) cmd); + PyObject *run_ret; + run_ret = PyRun_String((char *)cmd, Py_file_input, globals, globals); + if (run_ret != NULL) + { + Py_DECREF(run_ret); + } + else if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit)) + { + EMSG2(_(e_py_systemexit), "python"); + PyErr_Clear(); + } + else + PyErr_PrintEx(1); } static const char *code_hdr = "def " DOPY_FUNC "(line, linenr):\n "; @@ -4979,6 +4994,7 @@ run_do(const char *cmd, void *arg UNUSED char *code; int status; PyObject *pyfunc, *pymain; + PyObject *run_ret; if (u_save((linenr_T)RangeStart - 1, (linenr_T)RangeEnd + 1) != OK) { @@ -4990,7 +5006,23 @@ run_do(const char *cmd, void *arg UNUSED code = PyMem_New(char, len + 1); memcpy(code, code_hdr, code_hdr_len); STRCPY(code + code_hdr_len, cmd); - status = PyRun_SimpleString(code); + run_ret = PyRun_String(code, Py_file_input, globals, globals); + status = -1; + if (run_ret != NULL) + { + status = 0; + Py_DECREF(run_ret); + } + else if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_SystemExit)) + { + PyMem_Free(code); + EMSG2(_(e_py_systemexit), "python"); + PyErr_Clear(); + return; + } + else + PyErr_PrintEx(1); + PyMem_Free(code); if (status) @@ -5068,9 +5100,14 @@ run_eval(const char *cmd, typval_T *rett { PyObject *run_ret; - run_ret = PyRun_String((char *) cmd, Py_eval_input, globals, globals); + run_ret = PyRun_String((char *)cmd, Py_eval_input, globals, globals); if (run_ret == NULL) { + if (PyErr_ExceptionMatches(PyExc_SystemExit)) + { + EMSG2(_(e_py_systemexit), "python"); + PyErr_Clear(); + } if (PyErr_Occurred() && !msg_silent) PyErr_PrintEx(0); EMSG(_("E858: Eval did not return a valid python object")); diff --git a/src/if_python.c b/src/if_python.c --- a/src/if_python.c +++ b/src/if_python.c @@ -444,6 +444,7 @@ static PyObject *imp_PyExc_KeyError; static PyObject *imp_PyExc_KeyboardInterrupt; static PyObject *imp_PyExc_TypeError; static PyObject *imp_PyExc_ValueError; +static PyObject *imp_PyExc_SystemExit; static PyObject *imp_PyExc_RuntimeError; static PyObject *imp_PyExc_ImportError; static PyObject *imp_PyExc_OverflowError; @@ -454,6 +455,7 @@ static PyObject *imp_PyExc_OverflowError # define PyExc_KeyboardInterrupt imp_PyExc_KeyboardInterrupt # define PyExc_TypeError imp_PyExc_TypeError # define PyExc_ValueError imp_PyExc_ValueError +# define PyExc_SystemExit imp_PyExc_SystemExit # define PyExc_RuntimeError imp_PyExc_RuntimeError # define PyExc_ImportError imp_PyExc_ImportError # define PyExc_OverflowError imp_PyExc_OverflowError @@ -731,6 +733,7 @@ get_exceptions(void) imp_PyExc_KeyboardInterrupt = PyDict_GetItemString(exdict, "KeyboardInterrupt"); imp_PyExc_TypeError = PyDict_GetItemString(exdict, "TypeError"); imp_PyExc_ValueError = PyDict_GetItemString(exdict, "ValueError"); + imp_PyExc_SystemExit = PyDict_GetItemString(exdict, "SystemExit"); imp_PyExc_RuntimeError = PyDict_GetItemString(exdict, "RuntimeError"); imp_PyExc_ImportError = PyDict_GetItemString(exdict, "ImportError"); imp_PyExc_OverflowError = PyDict_GetItemString(exdict, "OverflowError"); @@ -740,6 +743,7 @@ get_exceptions(void) Py_XINCREF(imp_PyExc_KeyboardInterrupt); Py_XINCREF(imp_PyExc_TypeError); Py_XINCREF(imp_PyExc_ValueError); + Py_XINCREF(imp_PyExc_SystemExit); Py_XINCREF(imp_PyExc_RuntimeError); Py_XINCREF(imp_PyExc_ImportError); Py_XINCREF(imp_PyExc_OverflowError); diff --git a/src/if_python3.c b/src/if_python3.c --- a/src/if_python3.c +++ b/src/if_python3.c @@ -126,7 +126,6 @@ # define PyErr_PrintEx py3_PyErr_PrintEx # define PyErr_NoMemory py3_PyErr_NoMemory # define PyErr_Occurred py3_PyErr_Occurred -# define PyErr_PrintEx py3_PyErr_PrintEx # define PyErr_SetNone py3_PyErr_SetNone # define PyErr_SetString py3_PyErr_SetString # define PyErr_SetObject py3_PyErr_SetObject @@ -403,6 +402,7 @@ static PyObject *p3imp_PyExc_KeyError; static PyObject *p3imp_PyExc_KeyboardInterrupt; static PyObject *p3imp_PyExc_TypeError; static PyObject *p3imp_PyExc_ValueError; +static PyObject *p3imp_PyExc_SystemExit; static PyObject *p3imp_PyExc_RuntimeError; static PyObject *p3imp_PyExc_ImportError; static PyObject *p3imp_PyExc_OverflowError; @@ -413,6 +413,7 @@ static PyObject *p3imp_PyExc_OverflowErr # define PyExc_KeyboardInterrupt p3imp_PyExc_KeyboardInterrupt # define PyExc_TypeError p3imp_PyExc_TypeError # define PyExc_ValueError p3imp_PyExc_ValueError +# define PyExc_SystemExit p3imp_PyExc_SystemExit # define PyExc_RuntimeError p3imp_PyExc_RuntimeError # define PyExc_ImportError p3imp_PyExc_ImportError # define PyExc_OverflowError p3imp_PyExc_OverflowError @@ -681,6 +682,7 @@ get_py3_exceptions() p3imp_PyExc_KeyboardInterrupt = PyDict_GetItemString(exdict, "KeyboardInterrupt"); p3imp_PyExc_TypeError = PyDict_GetItemString(exdict, "TypeError"); p3imp_PyExc_ValueError = PyDict_GetItemString(exdict, "ValueError"); + p3imp_PyExc_SystemExit = PyDict_GetItemString(exdict, "SystemExit"); p3imp_PyExc_RuntimeError = PyDict_GetItemString(exdict, "RuntimeError"); p3imp_PyExc_ImportError = PyDict_GetItemString(exdict, "ImportError"); p3imp_PyExc_OverflowError = PyDict_GetItemString(exdict, "OverflowError"); @@ -690,6 +692,7 @@ get_py3_exceptions() Py_XINCREF(p3imp_PyExc_KeyboardInterrupt); Py_XINCREF(p3imp_PyExc_TypeError); Py_XINCREF(p3imp_PyExc_ValueError); + Py_XINCREF(p3imp_PyExc_SystemExit); Py_XINCREF(p3imp_PyExc_RuntimeError); Py_XINCREF(p3imp_PyExc_ImportError); Py_XINCREF(p3imp_PyExc_OverflowError); 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 */ /**/ + 1287, +/**/ 1286, /**/ 1285,