Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 154f099

Browse files
authored
gh-112292 : Catch import error conditions with readline hooks (gh-112313)
Prevents a segmentation fault in registered hooks for the readline library, but only when the readline module is loaded inside an isolated sub interpreter. The module is single-phase init so loading it fails, but not until the module init function has already run, where the readline hooks get registered. The readlinestate_global macro was error-prone to PyImport_FindModule returning NULL and crashing in about 18 places. I could reproduce 1 easily, but this PR replaces the macro with a function and adds error conditions to the other functions.
1 parent 2e632fa commit 154f099

File tree

2 files changed

+71
-22
lines changed

2 files changed

+71
-22
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a crash in :mod:`readline` when imported from a sub interpreter. Patch
2+
by Anthony Shaw

Modules/readline.c

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,19 @@ readline_free(void *m)
147147

148148
static PyModuleDef readlinemodule;
149149

150-
#define readlinestate_global ((readlinestate *)PyModule_GetState(PyState_FindModule(&readlinemodule)))
151-
150+
static inline readlinestate*
151+
get_hook_module_state(void)
152+
{
153+
PyObject *mod = PyState_FindModule(&readlinemodule);
154+
if (mod == NULL){
155+
PyErr_Clear();
156+
return NULL;
157+
}
158+
Py_INCREF(mod);
159+
readlinestate *state = get_readline_state(mod);
160+
Py_DECREF(mod);
161+
return state;
162+
}
152163

153164
/* Convert to/from multibyte C strings */
154165

@@ -438,14 +449,15 @@ readline_set_completion_display_matches_hook_impl(PyObject *module,
438449
PyObject *function)
439450
/*[clinic end generated code: output=516e5cb8db75a328 input=4f0bfd5ab0179a26]*/
440451
{
452+
readlinestate *state = get_readline_state(module);
441453
PyObject *result = set_hook("completion_display_matches_hook",
442-
&readlinestate_global->completion_display_matches_hook,
454+
&state->completion_display_matches_hook,
443455
function);
444456
#ifdef HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK
445457
/* We cannot set this hook globally, since it replaces the
446458
default completion display. */
447459
rl_completion_display_matches_hook =
448-
readlinestate_global->completion_display_matches_hook ?
460+
state->completion_display_matches_hook ?
449461
#if defined(HAVE_RL_COMPDISP_FUNC_T)
450462
(rl_compdisp_func_t *)on_completion_display_matches_hook : 0;
451463
#else
@@ -472,7 +484,8 @@ static PyObject *
472484
readline_set_startup_hook_impl(PyObject *module, PyObject *function)
473485
/*[clinic end generated code: output=02cd0e0c4fa082ad input=7783b4334b26d16d]*/
474486
{
475-
return set_hook("startup_hook", &readlinestate_global->startup_hook,
487+
readlinestate *state = get_readline_state(module);
488+
return set_hook("startup_hook", &state->startup_hook,
476489
function);
477490
}
478491

@@ -497,7 +510,8 @@ static PyObject *
497510
readline_set_pre_input_hook_impl(PyObject *module, PyObject *function)
498511
/*[clinic end generated code: output=fe1a96505096f464 input=4f3eaeaf7ce1fdbe]*/
499512
{
500-
return set_hook("pre_input_hook", &readlinestate_global->pre_input_hook,
513+
readlinestate *state = get_readline_state(module);
514+
return set_hook("pre_input_hook", &state->pre_input_hook,
501515
function);
502516
}
503517
#endif
@@ -530,7 +544,8 @@ static PyObject *
530544
readline_get_begidx_impl(PyObject *module)
531545
/*[clinic end generated code: output=362616ee8ed1b2b1 input=e083b81c8eb4bac3]*/
532546
{
533-
return Py_NewRef(readlinestate_global->begidx);
547+
readlinestate *state = get_readline_state(module);
548+
return Py_NewRef(state->begidx);
534549
}
535550

536551
/* Get the ending index for the scope of the tab-completion */
@@ -545,7 +560,8 @@ static PyObject *
545560
readline_get_endidx_impl(PyObject *module)
546561
/*[clinic end generated code: output=7f763350b12d7517 input=d4c7e34a625fd770]*/
547562
{
548-
return Py_NewRef(readlinestate_global->endidx);
563+
readlinestate *state = get_readline_state(module);
564+
return Py_NewRef(state->endidx);
549565
}
550566

551567
/* Set the tab-completion word-delimiters that readline uses */
@@ -772,7 +788,8 @@ static PyObject *
772788
readline_set_completer_impl(PyObject *module, PyObject *function)
773789
/*[clinic end generated code: output=171a2a60f81d3204 input=51e81e13118eb877]*/
774790
{
775-
return set_hook("completer", &readlinestate_global->completer, function);
791+
readlinestate *state = get_readline_state(module);
792+
return set_hook("completer", &state->completer, function);
776793
}
777794

778795
/*[clinic input]
@@ -785,10 +802,11 @@ static PyObject *
785802
readline_get_completer_impl(PyObject *module)
786803
/*[clinic end generated code: output=6e6bbd8226d14475 input=6457522e56d70d13]*/
787804
{
788-
if (readlinestate_global->completer == NULL) {
805+
readlinestate *state = get_readline_state(module);
806+
if (state->completer == NULL) {
789807
Py_RETURN_NONE;
790808
}
791-
return Py_NewRef(readlinestate_global->completer);
809+
return Py_NewRef(state->completer);
792810
}
793811

794812
/* Private function to get current length of history. XXX It may be
@@ -1026,7 +1044,12 @@ on_startup_hook(void)
10261044
{
10271045
int r;
10281046
PyGILState_STATE gilstate = PyGILState_Ensure();
1029-
r = on_hook(readlinestate_global->startup_hook);
1047+
readlinestate *state = get_hook_module_state();
1048+
if (state == NULL) {
1049+
PyGILState_Release(gilstate);
1050+
return -1;
1051+
}
1052+
r = on_hook(state->startup_hook);
10301053
PyGILState_Release(gilstate);
10311054
return r;
10321055
}
@@ -1043,7 +1066,12 @@ on_pre_input_hook(void)
10431066
{
10441067
int r;
10451068
PyGILState_STATE gilstate = PyGILState_Ensure();
1046-
r = on_hook(readlinestate_global->pre_input_hook);
1069+
readlinestate *state = get_hook_module_state();
1070+
if (state == NULL) {
1071+
PyGILState_Release(gilstate);
1072+
return -1;
1073+
}
1074+
r = on_hook(state->pre_input_hook);
10471075
PyGILState_Release(gilstate);
10481076
return r;
10491077
}
@@ -1060,6 +1088,11 @@ on_completion_display_matches_hook(char **matches,
10601088
int i;
10611089
PyObject *sub, *m=NULL, *s=NULL, *r=NULL;
10621090
PyGILState_STATE gilstate = PyGILState_Ensure();
1091+
readlinestate *state = get_hook_module_state();
1092+
if (state == NULL) {
1093+
PyGILState_Release(gilstate);
1094+
return;
1095+
}
10631096
m = PyList_New(num_matches);
10641097
if (m == NULL)
10651098
goto error;
@@ -1070,7 +1103,7 @@ on_completion_display_matches_hook(char **matches,
10701103
PyList_SET_ITEM(m, i, s);
10711104
}
10721105
sub = decode(matches[0]);
1073-
r = PyObject_CallFunction(readlinestate_global->completion_display_matches_hook,
1106+
r = PyObject_CallFunction(state->completion_display_matches_hook,
10741107
"NNi", sub, m, max_length);
10751108

10761109
m=NULL;
@@ -1118,12 +1151,17 @@ static char *
11181151
on_completion(const char *text, int state)
11191152
{
11201153
char *result = NULL;
1121-
if (readlinestate_global->completer != NULL) {
1154+
PyGILState_STATE gilstate = PyGILState_Ensure();
1155+
readlinestate *module_state = get_hook_module_state();
1156+
if (module_state == NULL) {
1157+
PyGILState_Release(gilstate);
1158+
return NULL;
1159+
}
1160+
if (module_state->completer != NULL) {
11221161
PyObject *r = NULL, *t;
1123-
PyGILState_STATE gilstate = PyGILState_Ensure();
11241162
rl_attempted_completion_over = 1;
11251163
t = decode(text);
1126-
r = PyObject_CallFunction(readlinestate_global->completer, "Ni", t, state);
1164+
r = PyObject_CallFunction(module_state->completer, "Ni", t, state);
11271165
if (r == NULL)
11281166
goto error;
11291167
if (r == Py_None) {
@@ -1145,6 +1183,7 @@ on_completion(const char *text, int state)
11451183
PyGILState_Release(gilstate);
11461184
return result;
11471185
}
1186+
PyGILState_Release(gilstate);
11481187
return result;
11491188
}
11501189

@@ -1160,6 +1199,7 @@ flex_complete(const char *text, int start, int end)
11601199
size_t start_size, end_size;
11611200
wchar_t *s;
11621201
PyGILState_STATE gilstate = PyGILState_Ensure();
1202+
readlinestate *state = get_hook_module_state();
11631203
#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
11641204
rl_completion_append_character ='\0';
11651205
#endif
@@ -1187,10 +1227,12 @@ flex_complete(const char *text, int start, int end)
11871227
end = start + (int)end_size;
11881228

11891229
done:
1190-
Py_XDECREF(readlinestate_global->begidx);
1191-
Py_XDECREF(readlinestate_global->endidx);
1192-
readlinestate_global->begidx = PyLong_FromLong((long) start);
1193-
readlinestate_global->endidx = PyLong_FromLong((long) end);
1230+
if (state) {
1231+
Py_XDECREF(state->begidx);
1232+
Py_XDECREF(state->endidx);
1233+
state->begidx = PyLong_FromLong((long) start);
1234+
state->endidx = PyLong_FromLong((long) end);
1235+
}
11941236
result = completion_matches((char *)text, *on_completion);
11951237
PyGILState_Release(gilstate);
11961238
return result;
@@ -1511,12 +1553,17 @@ PyInit_readline(void)
15111553
}
15121554

15131555
mod_state = (readlinestate *) PyModule_GetState(m);
1556+
if (mod_state == NULL){
1557+
goto error;
1558+
}
15141559
PyOS_ReadlineFunctionPointer = call_readline;
15151560
if (setup_readline(mod_state) < 0) {
15161561
PyErr_NoMemory();
15171562
goto error;
15181563
}
1519-
1564+
if (PyErr_Occurred()){
1565+
goto error;
1566+
}
15201567
return m;
15211568

15221569
error:

0 commit comments

Comments
 (0)