[Lldb-commits] [lldb] 9357b5d - Revert and patch "[Python] Remove readline module"

via lldb-commits lldb-commits at lists.llvm.org
Tue Nov 5 03:02:03 PST 2019


Author: serge-sans-paille
Date: 2019-11-05T11:39:19+01:00
New Revision: 9357b5d08497326a1895cab6c1d712bf12a34519

URL: https://github.com/llvm/llvm-project/commit/9357b5d08497326a1895cab6c1d712bf12a34519
DIFF: https://github.com/llvm/llvm-project/commit/9357b5d08497326a1895cab6c1d712bf12a34519.diff

LOG: 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

Added: 
    lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp
    lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.h

Modified: 
    lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
    lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
index 54b5c236f752..6febb0385781 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
@@ -5,6 +5,7 @@ add_definitions(-DLLDB_PYTHON_RELATIVE_LIBDIR="${LLDB_PYTHON_RELATIVE_PATH}")
 
 add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN
   PythonDataObjects.cpp
+  PythonReadline.cpp
   ScriptInterpreterPython.cpp
 
   LINK_LIBS

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp
new file mode 100644
index 000000000000..616522f9de90
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp
@@ -0,0 +1,80 @@
+#include "PythonReadline.h"
+
+#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE
+
+#include <stdio.h>
+
+#include <editline/readline.h>
+
+// Simple implementation of the Python readline module using libedit.
+// In the event that libedit is excluded from the build, this turns
+// back into a null implementation that blocks the module from pulling
+// in the GNU readline shared lib, which causes linkage confusion when
+// both readline and libedit's readline compatibility symbols collide.
+//
+// Currently it only installs a PyOS_ReadlineFunctionPointer, without
+// implementing any of the readline module methods. This is meant to
+// work around LLVM pr18841 to avoid seg faults in the stock Python
+// readline.so linked against GNU readline.
+//
+// Bug on the cpython side: https://bugs.python.org/issue38634
+
+PyDoc_STRVAR(moduleDocumentation,
+             "Simple readline module implementation based on libedit.");
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef readline_module = {
+    PyModuleDef_HEAD_INIT, // m_base
+    "lldb_editline",       // m_name
+    moduleDocumentation,   // m_doc
+    -1,                    // m_size
+    nullptr,               // m_methods
+    nullptr,               // m_reload
+    nullptr,               // m_traverse
+    nullptr,               // m_clear
+    nullptr,               // m_free
+};
+#else
+static struct PyMethodDef moduleMethods[] = {{nullptr, nullptr, 0, nullptr}};
+#endif
+
+static char *
+#if PY_MAJOR_VERSION >= 3
+simple_readline(FILE *stdin, FILE *stdout, const char *prompt)
+#else
+simple_readline(FILE *stdin, FILE *stdout, char *prompt)
+#endif
+{
+  rl_instream = stdin;
+  rl_outstream = stdout;
+  char *line = readline(prompt);
+  if (!line) {
+    char *ret = (char *)PyMem_RawMalloc(1);
+    if (ret != NULL)
+      *ret = '\0';
+    return ret;
+  }
+  if (*line)
+    add_history(line);
+  int n = strlen(line);
+  char *ret = (char *)PyMem_RawMalloc(n + 2);
+  if (ret) {
+    strncpy(ret, line, n);
+    free(line);
+    ret[n] = '\n';
+    ret[n + 1] = '\0';
+  }
+  return ret;
+}
+
+PyMODINIT_FUNC initlldb_readline(void) {
+  PyOS_ReadlineFunctionPointer = simple_readline;
+
+#if PY_MAJOR_VERSION >= 3
+  return PyModule_Create(&readline_module);
+#else
+  Py_InitModule4("lldb_readline", moduleMethods, moduleDocumentation,
+                 static_cast<PyObject *>(NULL), PYTHON_API_VERSION);
+#endif
+}
+#endif

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.h b/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.h
new file mode 100644
index 000000000000..20242e2324d8
--- /dev/null
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.h
@@ -0,0 +1,26 @@
+//===-- PythonReadline.h ----------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONREADLINE_H
+#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONREADLINE_H
+
+#if !defined(LLDB_DISABLE_LIBEDIT) && !defined(__APPLE__)
+// NOTE: Since Python may define some pre-processor definitions which affect the
+// standard headers on some systems, you must include Python.h before any
+// standard headers are included.
+#include "Python.h"
+
+// no need to hack into Python's readline module if libedit isn't used.
+//
+#define LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE 1
+
+extern "C" PyMODINIT_FUNC initlldb_readline(void);
+
+#endif
+
+#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONREADLINE_H

diff  --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
index e7d9443c5fdb..29509f5b98e0 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -16,6 +16,7 @@
 #include "lldb-python.h"
 
 #include "PythonDataObjects.h"
+#include "PythonReadline.h"
 #include "ScriptInterpreterPythonImpl.h"
 
 #include "lldb/API/SBFrame.h"
@@ -217,6 +218,22 @@ struct InitializePythonRAII {
 
     InitializePythonHome();
 
+#ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE
+    // Python's readline is incompatible with libedit being linked into lldb.
+    // Provide a patched version local to the embedded interpreter.
+    bool ReadlinePatched = false;
+    for (auto *p = PyImport_Inittab; p->name != NULL; p++) {
+      if (strcmp(p->name, "readline") == 0) {
+        p->initfunc = initlldb_readline;
+        break;
+      }
+    }
+    if (!ReadlinePatched) {
+      PyImport_AppendInittab("readline", initlldb_readline);
+      ReadlinePatched = true;
+    }
+#endif
+
     // Register _lldb as a built-in module.
     PyImport_AppendInittab("_lldb", LLDBSwigPyInit);
 


        


More information about the lldb-commits mailing list