Skip to content

Commit 186c848

Browse files
author
serge-sans-paille
committed
Revert and patch "[Python] Remove readline module"
Fix https://bugs.llvm.org/show_bug.cgi?id=43830 while avoiding polluting the global Python namespace. This both reverts r357277 to rebundle a version of Python's readline module based on libedit. However, this patch also provides two improvements over the previous implementation: 1. use PyMem_RawMalloc instead of PyMem_Malloc, as expected by PyOS_Readline (prevents to segfault upon exit of interactive session) 2. patch the readline module upon embedded interpreter loading, instead of patching it globally, which should prevent any side effect on other modules/packages 3. only activate the patched module if libedit is actually linked in lldb Differential Revision: https://reviews.llvm.org/D69793 (cherry picked from commit 9357b5d)
1 parent d1f4d6a commit 186c848

File tree

4 files changed

+124
-0
lines changed

4 files changed

+124
-0
lines changed

lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ endif()
1414
add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN
1515
PythonDataObjects.cpp
1616
PythonExceptionState.cpp
17+
PythonReadline.cpp
1718
ScriptInterpreterPython.cpp
1819

1920
LINK_LIBS
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#include "PythonReadline.h"
2+
3+
#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE
4+
5+
#include <stdio.h>
6+
7+
#include <editline/readline.h>
8+
9+
// Simple implementation of the Python readline module using libedit.
10+
// In the event that libedit is excluded from the build, this turns
11+
// back into a null implementation that blocks the module from pulling
12+
// in the GNU readline shared lib, which causes linkage confusion when
13+
// both readline and libedit's readline compatibility symbols collide.
14+
//
15+
// Currently it only installs a PyOS_ReadlineFunctionPointer, without
16+
// implementing any of the readline module methods. This is meant to
17+
// work around LLVM pr18841 to avoid seg faults in the stock Python
18+
// readline.so linked against GNU readline.
19+
//
20+
// Bug on the cpython side: https://bugs.python.org/issue38634
21+
22+
PyDoc_STRVAR(moduleDocumentation,
23+
"Simple readline module implementation based on libedit.");
24+
25+
#if PY_MAJOR_VERSION >= 3
26+
static struct PyModuleDef readline_module = {
27+
PyModuleDef_HEAD_INIT, // m_base
28+
"lldb_editline", // m_name
29+
moduleDocumentation, // m_doc
30+
-1, // m_size
31+
nullptr, // m_methods
32+
nullptr, // m_reload
33+
nullptr, // m_traverse
34+
nullptr, // m_clear
35+
nullptr, // m_free
36+
};
37+
#else
38+
static struct PyMethodDef moduleMethods[] = {{nullptr, nullptr, 0, nullptr}};
39+
#endif
40+
41+
static char *
42+
#if PY_MAJOR_VERSION >= 3
43+
simple_readline(FILE *stdin, FILE *stdout, const char *prompt)
44+
#else
45+
simple_readline(FILE *stdin, FILE *stdout, char *prompt)
46+
#endif
47+
{
48+
rl_instream = stdin;
49+
rl_outstream = stdout;
50+
char *line = readline(prompt);
51+
if (!line) {
52+
char *ret = (char *)PyMem_RawMalloc(1);
53+
if (ret != NULL)
54+
*ret = '\0';
55+
return ret;
56+
}
57+
if (*line)
58+
add_history(line);
59+
int n = strlen(line);
60+
char *ret = (char *)PyMem_RawMalloc(n + 2);
61+
if (ret) {
62+
strncpy(ret, line, n);
63+
free(line);
64+
ret[n] = '\n';
65+
ret[n + 1] = '\0';
66+
}
67+
return ret;
68+
}
69+
70+
PyMODINIT_FUNC initlldb_readline(void) {
71+
PyOS_ReadlineFunctionPointer = simple_readline;
72+
73+
#if PY_MAJOR_VERSION >= 3
74+
return PyModule_Create(&readline_module);
75+
#else
76+
Py_InitModule4("lldb_readline", moduleMethods, moduleDocumentation,
77+
static_cast<PyObject *>(NULL), PYTHON_API_VERSION);
78+
#endif
79+
}
80+
#endif
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//===-- PythonReadline.h ----------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONREADLINE_H
10+
#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONREADLINE_H
11+
12+
#if !defined(LLDB_DISABLE_LIBEDIT) && !defined(__APPLE__)
13+
// NOTE: Since Python may define some pre-processor definitions which affect the
14+
// standard headers on some systems, you must include Python.h before any
15+
// standard headers are included.
16+
#include "Python.h"
17+
18+
// no need to hack into Python's readline module if libedit isn't used.
19+
//
20+
#define LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE 1
21+
22+
extern "C" PyMODINIT_FUNC initlldb_readline(void);
23+
24+
#endif
25+
26+
#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONREADLINE_H

lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "PythonDataObjects.h"
1919
#include "PythonExceptionState.h"
20+
#include "PythonReadline.h"
2021
#include "ScriptInterpreterPythonImpl.h"
2122

2223
#include "lldb/API/SBFrame.h"
@@ -207,6 +208,22 @@ struct InitializePythonRAII {
207208

208209
InitializePythonHome();
209210

211+
#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE
212+
// Python's readline is incompatible with libedit being linked into lldb.
213+
// Provide a patched version local to the embedded interpreter.
214+
bool ReadlinePatched = false;
215+
for (auto *p = PyImport_Inittab; p->name != NULL; p++) {
216+
if (strcmp(p->name, "readline") == 0) {
217+
p->initfunc = initlldb_readline;
218+
break;
219+
}
220+
}
221+
if (!ReadlinePatched) {
222+
PyImport_AppendInittab("readline", initlldb_readline);
223+
ReadlinePatched = true;
224+
}
225+
#endif
226+
210227
// Register _lldb as a built-in module.
211228
PyImport_AppendInittab("_lldb", LLDBSwigPyInit);
212229

0 commit comments

Comments
 (0)