Kaydet (Commit) da6242c8 authored tarafından Michael W. Hudson's avatar Michael W. Hudson

Fixes for

[ 1166660 ] The readline module can cause python to segfault

It seems to me that the code I'm rewriting here attempted to call any
user-supplied hook functions using the thread state of the thread that
called the hook-setting function, as opposed to that of the thread
that is currently executing.  This doesn't work, in general.

Fix this by using the PyGILState API (It wouldn't be that hard to
define a dummy version of said API when #ifndef WITH_THREAD, would
it?).

Also, check the conversion to integer of the return value of a hook
function for errors (this problem was mentioned in the ipython bug
report linked to in the above bug).
üst 9a8c3142
...@@ -159,8 +159,7 @@ the history file."); ...@@ -159,8 +159,7 @@ the history file.");
/* Generic hook function setter */ /* Generic hook function setter */
static PyObject * static PyObject *
set_hook(const char *funcname, PyObject **hook_var, set_hook(const char *funcname, PyObject **hook_var, PyObject *args)
PyThreadState **tstate, PyObject *args)
{ {
PyObject *function = Py_None; PyObject *function = Py_None;
char buf[80]; char buf[80];
...@@ -170,14 +169,12 @@ set_hook(const char *funcname, PyObject **hook_var, ...@@ -170,14 +169,12 @@ set_hook(const char *funcname, PyObject **hook_var,
if (function == Py_None) { if (function == Py_None) {
Py_XDECREF(*hook_var); Py_XDECREF(*hook_var);
*hook_var = NULL; *hook_var = NULL;
*tstate = NULL;
} }
else if (PyCallable_Check(function)) { else if (PyCallable_Check(function)) {
PyObject *tmp = *hook_var; PyObject *tmp = *hook_var;
Py_INCREF(function); Py_INCREF(function);
*hook_var = function; *hook_var = function;
Py_XDECREF(tmp); Py_XDECREF(tmp);
*tstate = PyThreadState_GET();
} }
else { else {
PyOS_snprintf(buf, sizeof(buf), PyOS_snprintf(buf, sizeof(buf),
...@@ -194,18 +191,15 @@ set_hook(const char *funcname, PyObject **hook_var, ...@@ -194,18 +191,15 @@ set_hook(const char *funcname, PyObject **hook_var,
/* Exported functions to specify hook functions in Python */ /* Exported functions to specify hook functions in Python */
static PyObject *startup_hook = NULL; static PyObject *startup_hook = NULL;
static PyThreadState *startup_hook_tstate = NULL;
#ifdef HAVE_RL_PRE_INPUT_HOOK #ifdef HAVE_RL_PRE_INPUT_HOOK
static PyObject *pre_input_hook = NULL; static PyObject *pre_input_hook = NULL;
static PyThreadState *pre_input_hook_tstate = NULL;
#endif #endif
static PyObject * static PyObject *
set_startup_hook(PyObject *self, PyObject *args) set_startup_hook(PyObject *self, PyObject *args)
{ {
return set_hook("startup_hook", &startup_hook, return set_hook("startup_hook", &startup_hook, args);
&startup_hook_tstate, args);
} }
PyDoc_STRVAR(doc_set_startup_hook, PyDoc_STRVAR(doc_set_startup_hook,
...@@ -222,8 +216,7 @@ before readline prints the first prompt."); ...@@ -222,8 +216,7 @@ before readline prints the first prompt.");
static PyObject * static PyObject *
set_pre_input_hook(PyObject *self, PyObject *args) set_pre_input_hook(PyObject *self, PyObject *args)
{ {
return set_hook("pre_input_hook", &pre_input_hook, return set_hook("pre_input_hook", &pre_input_hook, args);
&pre_input_hook_tstate, args);
} }
PyDoc_STRVAR(doc_set_pre_input_hook, PyDoc_STRVAR(doc_set_pre_input_hook,
...@@ -239,7 +232,6 @@ characters."); ...@@ -239,7 +232,6 @@ characters.");
/* Exported function to specify a word completer in Python */ /* Exported function to specify a word completer in Python */
static PyObject *completer = NULL; static PyObject *completer = NULL;
static PyThreadState *completer_tstate = NULL;
static PyObject *begidx = NULL; static PyObject *begidx = NULL;
static PyObject *endidx = NULL; static PyObject *endidx = NULL;
...@@ -403,7 +395,7 @@ get the readline word delimiters for tab-completion"); ...@@ -403,7 +395,7 @@ get the readline word delimiters for tab-completion");
static PyObject * static PyObject *
set_completer(PyObject *self, PyObject *args) set_completer(PyObject *self, PyObject *args)
{ {
return set_hook("completer", &completer, &completer_tstate, args); return set_hook("completer", &completer, args);
} }
PyDoc_STRVAR(doc_set_completer, PyDoc_STRVAR(doc_set_completer,
...@@ -584,28 +576,33 @@ static struct PyMethodDef readline_methods[] = ...@@ -584,28 +576,33 @@ static struct PyMethodDef readline_methods[] =
/* C function to call the Python hooks. */ /* C function to call the Python hooks. */
static int static int
on_hook(PyObject *func, PyThreadState **tstate) on_hook(PyObject *func)
{ {
int result = 0; int result = 0;
if (func != NULL) { if (func != NULL) {
PyObject *r; PyObject *r;
/* Note that readline is called with the interpreter #ifdef WITH_THREAD
lock released! */ PyGILState_STATE gilstate = PyGILState_Ensure();
PyEval_RestoreThread(*tstate); #endif
r = PyObject_CallFunction(func, NULL); r = PyObject_CallFunction(func, NULL);
if (r == NULL) if (r == NULL)
goto error; goto error;
if (r == Py_None) if (r == Py_None)
result = 0; result = 0;
else else {
result = PyInt_AsLong(r); result = PyInt_AsLong(r);
if (result == -1 && PyErr_Occurred())
goto error;
}
Py_DECREF(r); Py_DECREF(r);
goto done; goto done;
error: error:
PyErr_Clear(); PyErr_Clear();
Py_XDECREF(r); Py_XDECREF(r);
done: done:
*tstate = PyEval_SaveThread(); #ifdef WITH_THREAD
PyGILState_Release(gilstate);
#endif
} }
return result; return result;
} }
...@@ -613,14 +610,14 @@ on_hook(PyObject *func, PyThreadState **tstate) ...@@ -613,14 +610,14 @@ on_hook(PyObject *func, PyThreadState **tstate)
static int static int
on_startup_hook(void) on_startup_hook(void)
{ {
return on_hook(startup_hook, &startup_hook_tstate); return on_hook(startup_hook);
} }
#ifdef HAVE_RL_PRE_INPUT_HOOK #ifdef HAVE_RL_PRE_INPUT_HOOK
static int static int
on_pre_input_hook(void) on_pre_input_hook(void)
{ {
return on_hook(pre_input_hook, &pre_input_hook_tstate); return on_hook(pre_input_hook);
} }
#endif #endif
...@@ -633,11 +630,9 @@ on_completion(char *text, int state) ...@@ -633,11 +630,9 @@ on_completion(char *text, int state)
char *result = NULL; char *result = NULL;
if (completer != NULL) { if (completer != NULL) {
PyObject *r; PyObject *r;
/* Note that readline is called with the interpreter #ifdef WITH_THREAD
lock released! */ PyGILState_STATE gilstate = PyGILState_Ensure();
PyEval_RestoreThread(completer_tstate); #endif
/* Don't use the default filename completion if we
* have a custom completion function... */
rl_attempted_completion_over = 1; rl_attempted_completion_over = 1;
r = PyObject_CallFunction(completer, "si", text, state); r = PyObject_CallFunction(completer, "si", text, state);
if (r == NULL) if (r == NULL)
...@@ -657,7 +652,9 @@ on_completion(char *text, int state) ...@@ -657,7 +652,9 @@ on_completion(char *text, int state)
PyErr_Clear(); PyErr_Clear();
Py_XDECREF(r); Py_XDECREF(r);
done: done:
completer_tstate = PyEval_SaveThread(); #ifdef WITH_THREAD
PyGILState_Release(gilstate);
#endif
} }
return result; return result;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment