serge-sans-paille created this revision.
serge-sans-paille added reviewers: labath, JDevlieghere.
serge-sans-paille added a project: LLDB.
Herald added subscribers: lldb-commits, mgorny.

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


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D69793

Files:
  lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
  lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp
  lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.h
  lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp

Index: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
+++ lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp
@@ -17,6 +17,7 @@
 
 #include "PythonDataObjects.h"
 #include "PythonExceptionState.h"
+#include "PythonReadline.h"
 #include "ScriptInterpreterPythonImpl.h"
 
 #include "lldb/API/SBFrame.h"
@@ -207,6 +208,20 @@
 
     InitializePythonHome();
 
+    // 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;
+    }
+
     // Register _lldb as a built-in module.
     PyImport_AppendInittab("_lldb", LLDBSwigPyInit);
 
Index: lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.h
@@ -0,0 +1,15 @@
+//===-- 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
+
+extern "C" PyMODINIT_FUNC initlldb_readline(void);
+
+#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_PYTHONREADLINE_H
Index: lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp
@@ -0,0 +1,89 @@
+// 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"
+
+#include <stdio.h>
+
+#ifndef LLDB_DISABLE_LIBEDIT
+#include <editline/readline.h>
+#endif
+
+// 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.
+
+#ifndef LLDB_DISABLE_LIBEDIT
+PyDoc_STRVAR(moduleDocumentation,
+             "Simple readline module implementation based on libedit.");
+#else
+PyDoc_STRVAR(moduleDocumentation,
+             "Stub module meant to avoid linking GNU readline.");
+#endif
+
+#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
+
+#ifndef LLDB_DISABLE_LIBEDIT
+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;
+}
+#endif
+
+PyMODINIT_FUNC initlldb_readline(void) {
+#ifndef LLDB_DISABLE_LIBEDIT
+  PyOS_ReadlineFunctionPointer = simple_readline;
+#endif
+
+#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
+}
Index: lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
+++ lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
@@ -14,6 +14,7 @@
 add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN
   PythonDataObjects.cpp
   PythonExceptionState.cpp
+  PythonReadline.cpp
   ScriptInterpreterPython.cpp
 
   LINK_LIBS
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to