Skip to content

[lldb] Use Python Bytes instead of Buffer for Binary I/O (NFC) #152031

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

JDevlieghere
Copy link
Member

Binary I/O (also called buffered I/O) expects bytes-like objects and produces bytes objects [1]. Switch from using a Python buffer to using Python bytes to read the data. This eliminates calls to functions that aren't part of the Python stable C API.

[1] https://docs.python.org/3/library/io.html#binary-i-o

@llvmbot
Copy link
Member

llvmbot commented Aug 4, 2025

@llvm/pr-subscribers-lldb

Author: Jonas Devlieghere (JDevlieghere)

Changes

Binary I/O (also called buffered I/O) expects bytes-like objects and produces bytes objects [1]. Switch from using a Python buffer to using Python bytes to read the data. This eliminates calls to functions that aren't part of the Python stable C API.

[1] https://docs.python.org/3/library/io.html#binary-i-o


Full diff: https://github.com/llvm/llvm-project/pull/152031.diff

1 Files Affected:

  • (modified) lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp (+6-40)
diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
index e124954057520..3950a4fd7a20c 100644
--- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
+++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp
@@ -1085,40 +1085,6 @@ class SimplePythonFile : public OwnedPythonFile<NativeFile> {
 char SimplePythonFile::ID = 0;
 } // namespace
 
-namespace {
-class PythonBuffer {
-public:
-  PythonBuffer &operator=(const PythonBuffer &) = delete;
-  PythonBuffer(const PythonBuffer &) = delete;
-
-  static Expected<PythonBuffer> Create(PythonObject &obj,
-                                       int flags = PyBUF_SIMPLE) {
-    Py_buffer py_buffer = {};
-    PyObject_GetBuffer(obj.get(), &py_buffer, flags);
-    if (!py_buffer.obj)
-      return llvm::make_error<PythonException>();
-    return PythonBuffer(py_buffer);
-  }
-
-  PythonBuffer(PythonBuffer &&other) {
-    m_buffer = other.m_buffer;
-    other.m_buffer.obj = nullptr;
-  }
-
-  ~PythonBuffer() {
-    if (m_buffer.obj)
-      PyBuffer_Release(&m_buffer);
-  }
-
-  Py_buffer &get() { return m_buffer; }
-
-private:
-  // takes ownership of the buffer.
-  PythonBuffer(const Py_buffer &py_buffer) : m_buffer(py_buffer) {}
-  Py_buffer m_buffer;
-};
-} // namespace
-
 // Shared methods between TextPythonFile and BinaryPythonFile
 namespace {
 class PythonIOFile : public OwnedPythonFile<File> {
@@ -1212,12 +1178,12 @@ class BinaryPythonFile : public PythonIOFile {
       num_bytes = 0;
       return Status();
     }
-    auto pybuffer = PythonBuffer::Create(pybuffer_obj.get());
-    if (!pybuffer)
-      // Cloning since the wrapped exception may still reference the PyThread.
-      return Status::FromError(pybuffer.takeError()).Clone();
-    memcpy(buf, pybuffer.get().get().buf, pybuffer.get().get().len);
-    num_bytes = pybuffer.get().get().len;
+    PythonBytes pybytes(PyRefType::Owned, pybuffer_obj->get());
+    if (!pybytes)
+      return Status::FromErrorString("not a byte array");
+    llvm::ArrayRef<uint8_t> bytes = pybytes.GetBytes();
+    memcpy(buf, bytes.begin(), bytes.size());
+    num_bytes = bytes.size();
     return Status();
   }
 };

Binary I/O (also called buffered I/O) expects bytes-like objects and
produces bytes objects [1]. Switch from using a Python buffer to using
Python bytes to read the data. This eliminates calls to functions that
aren't part of the Python stable C API.

[1] https://docs.python.org/3/library/io.html#binary-i-o
@JDevlieghere
Copy link
Member Author

Part of #151617

num_bytes = pybuffer.get().get().len;
PythonBytes pybytes(PyRefType::Borrowed, pybuffer_obj->get());
if (!pybytes)
return Status::FromErrorString("not a byte array");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This subtly changes behavior from raising a python exception to returning the string "not a byte array". Is that not a breaking change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, this should create a PythonError

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants