[Libguestfs] [libnbd PATCH] python: Accept buffers in nbd.Buffer.from_bytearray()

Eric Blake eblake at redhat.com
Thu May 26 01:27:15 UTC 2022


Prior to this patch, the following fails, but at least seems to give a
sensible error:

$ nbdsh -c 'nbd.Buffer.from_bytearray(b"1"*8)'
Traceback (most recent call last):
  File "/usr/lib64/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib64/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/usr/lib64/python3.10/site-packages/nbd.py", line 2726, in <module>
    nbdsh.shell()
  File "/usr/lib64/python3.10/site-packages/nbdsh.py", line 139, in shell
    exec(c, d, d)
  File "<string>", line 1, in <module>
  File "/usr/lib64/python3.10/site-packages/nbd.py", line 132, in from_bytearray
    o = libnbdmod.aio_buffer_from_bytearray(ba)
RuntimeError: parameter is not a bytearray

while this version 1 byte longer flat out segfaults:

$ nbdsh -c 'nbd.Buffer.from_bytearray(b"1"*9)'

and this one is subtly different:

$ nbdsh -c 'nbd.Buffer.from_bytearray(h)'
Traceback (most recent call last):
...
  File "/usr/lib64/python3.10/site-packages/nbd.py", line 132, in from_bytearray
    o = libnbdmod.aio_buffer_from_bytearray(ba)
MemoryError

That's because PyByteArray_AsString() blindly assumes that its
argument is a PyByteArray, and goes haywire when it is not, unless we
got lucky that the incorrectly-typed object behaves similarly enough
(which, for byte literals, is size-dependent).

But Python already has a handy way to convert any object that supports
the buffer interface into a bytearray.  Using it, we can now support
many more parameters; passing in b"1"*9 now correctly creates a 9-byte
buffer rather than failing.  And the error message for a non-buffer
also improves:

$ ./run nbdsh -c 'nbd.Buffer.from_bytearray(h)'
Traceback (most recent call last):
...
  File "/home/eblake/libnbd/python/nbd.py", line 132, in from_bytearray
    o = libnbdmod.aio_buffer_from_bytearray(ba)
TypeError: cannot convert 'NBD' object to bytearray

(A reliable TypeError is always better than an unexpected MemoryError
or segfault).
---
 python/handle.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/python/handle.c b/python/handle.c
index 9c08dc1..9fe3f8e 100644
--- a/python/handle.c
+++ b/python/handle.c
@@ -1,5 +1,5 @@
 /* NBD client library in userspace
- * Copyright (C) 2013-2020 Red Hat Inc.
+ * Copyright (C) 2013-2022 Red Hat Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -159,6 +159,7 @@ PyObject *
 nbd_internal_py_aio_buffer_from_bytearray (PyObject *self, PyObject *args)
 {
   PyObject *obj;
+  PyObject *arr = NULL;
   Py_ssize_t len;
   void *data;
   struct py_aio_buffer *buf;
@@ -169,9 +170,17 @@ nbd_internal_py_aio_buffer_from_bytearray (PyObject *self, PyObject *args)
                          &obj))
     return NULL;

+  if (! PyByteArray_Check (obj)) {
+    arr = PyByteArray_FromObject (obj);
+    if (arr == NULL)
+      return NULL;
+    obj = arr;
+  }
   data = PyByteArray_AsString (obj);
   if (!data) {
-    PyErr_SetString (PyExc_RuntimeError, "parameter is not a bytearray");
+    PyErr_SetString (PyExc_RuntimeError,
+                     "parameter is not a bytearray or buffer");
+    Py_XDECREF (arr);
     return NULL;
   }
   len = PyByteArray_Size (obj);
@@ -179,6 +188,7 @@ nbd_internal_py_aio_buffer_from_bytearray (PyObject *self, PyObject *args)
   buf = malloc (sizeof *buf);
   if (buf == NULL) {
     PyErr_NoMemory ();
+    Py_XDECREF (arr);
     return NULL;
   }

@@ -187,9 +197,11 @@ nbd_internal_py_aio_buffer_from_bytearray (PyObject *self, PyObject *args)
   if (buf->data == NULL) {
     PyErr_NoMemory ();
     free (buf);
+    Py_XDECREF (arr);
     return NULL;
   }
   memcpy (buf->data, data, len);
+  Py_XDECREF (arr);

   ret = PyCapsule_New (buf, aio_buffer_name, free_aio_buffer);
   if (ret == NULL) {
-- 
2.36.1



More information about the Libguestfs mailing list