Skip to content

Commit 5d4121a

Browse files
committed
Issue #18458: Prevent crashes with newer versions of libedit. Its readline
emulation has changed from 0-based indexing to 1-based like gnu readline. Original patch by Ronald Oussoren.
1 parent a140348 commit 5d4121a

File tree

2 files changed

+29
-15
lines changed

2 files changed

+29
-15
lines changed

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ Core and Builtins
7676
Library
7777
-------
7878

79+
- Issue #18458: Prevent crashes with newer versions of libedit. Its readline
80+
emulation has changed from 0-based indexing to 1-based like gnu readline.
81+
Original patch by Ronald Oussoren.
82+
7983
- Issue #18919: If the close() method of a writer in the sunau or wave module
8084
failed, second invocation of close() and destructor no more raise an
8185
exception.

Modules/readline.c

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,16 @@ extern char **completion_matches(char *, CPFunction *);
5454
* with the "real" readline and cannot be detected at compile-time,
5555
* hence we use a runtime check to detect if we're using libedit
5656
*
57-
* Currently there is one know API incompatibility:
57+
* Currently there is one known API incompatibility:
5858
* - 'get_history' has a 1-based index with GNU readline, and a 0-based
59-
* index with libedit's emulation.
59+
* index with older versions of libedit's emulation.
6060
* - Note that replace_history and remove_history use a 0-based index
61-
* with both implementation.
61+
* with both implementations.
6262
*/
6363
static int using_libedit_emulation = 0;
6464
static const char libedit_version_tag[] = "EditLine wrapper";
65+
66+
static int libedit_history_start = 0;
6567
#endif /* __APPLE__ */
6668

6769
#ifdef HAVE_RL_COMPLETION_DISPLAY_MATCHES_HOOK
@@ -579,21 +581,21 @@ get_history_item(PyObject *self, PyObject *args)
579581
return NULL;
580582
#ifdef __APPLE__
581583
if (using_libedit_emulation) {
582-
/* Libedit emulation uses 0-based indexes,
583-
* the real one uses 1-based indexes,
584-
* adjust the index to ensure that Python
585-
* code doesn't have to worry about the
586-
* difference.
584+
/* Older versions of libedit's readline emulation
585+
* use 0-based indexes, while readline and newer
586+
* versions of libedit use 1-based indexes.
587587
*/
588588
int length = _py_get_history_length();
589-
idx --;
589+
590+
idx = idx - 1 + libedit_history_start;
590591

591592
/*
592593
* Apple's readline emulation crashes when
593594
* the index is out of range, therefore
594595
* test for that and fail gracefully.
595596
*/
596-
if (idx < 0 || idx >= length) {
597+
if (idx < (0 + libedit_history_start)
598+
|| idx >= (length + libedit_history_start)) {
597599
Py_RETURN_NONE;
598600
}
599601
}
@@ -908,6 +910,17 @@ setup_readline(void)
908910
*/
909911
if (using_libedit_emulation)
910912
rl_initialize();
913+
914+
/* Detect if libedit's readline emulation uses 0-based
915+
* indexing or 1-based indexing.
916+
*/
917+
add_history("1");
918+
if (history_get(1) == NULL) {
919+
libedit_history_start = 0;
920+
} else {
921+
libedit_history_start = 1;
922+
}
923+
clear_history();
911924
#endif /* __APPLE__ */
912925

913926
using_history();
@@ -1116,11 +1129,8 @@ call_readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt)
11161129
if (length > 0)
11171130
#ifdef __APPLE__
11181131
if (using_libedit_emulation) {
1119-
/*
1120-
* Libedit's emulation uses 0-based indexes,
1121-
* the real readline uses 1-based indexes.
1122-
*/
1123-
line = (const char *)history_get(length - 1)->line;
1132+
/* handle older 0-based or newer 1-based indexing */
1133+
line = (const char *)history_get(length + libedit_history_start - 1)->line;
11241134
} else
11251135
#endif /* __APPLE__ */
11261136
line = (const char *)history_get(length)->line;

0 commit comments

Comments
 (0)