From b890fd2900310c9e4f0781aa3427a3bb114788b1 Mon Sep 17 00:00:00 2001 From: Pino Toscano Date: Fri, 3 Mar 2017 13:47:48 +0100 Subject: [PATCH] python: do not try to malloc 0 elements in get_all_event_callbacks In case there are no event handlers registered with the handle, get_all_event_callbacks will count 0 elements, trying to malloc a buffer of that size. POSIX says that this can result in either a null pointer, or an unusable pointer. Short-circuit get_all_event_callbacks to allocate nothing when there are no events, making sure to use its results only when there were events. --- python/handle.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/python/handle.c b/python/handle.c index f4cc8ca0d..806408f91 100644 --- a/python/handle.c +++ b/python/handle.c @@ -71,7 +71,7 @@ guestfs_int_py_close (PyObject *self, PyObject *args) PyThreadState *py_save = NULL; PyObject *py_g; guestfs_h *g; - size_t i, len; + size_t len; PyObject **callbacks; if (!PyArg_ParseTuple (args, (char *) "O:guestfs_close", &py_g)) @@ -81,9 +81,14 @@ guestfs_int_py_close (PyObject *self, PyObject *args) /* As in the OCaml bindings, there is a hard to solve case where the * caller can delete a callback from within the callback, resulting * in a double-free here. XXX + * + * Take care of the result of get_all_event_callbacks: NULL can be + * both an error (and some PyErr_* was called), and no events. + * 'len' is specifically 0 only in the latter case, so filter that + * out. */ callbacks = get_all_event_callbacks (g, &len); - if (callbacks == NULL) + if (len != 0 && callbacks == NULL) return NULL; if (PyEval_ThreadsInitialized ()) @@ -92,9 +97,12 @@ guestfs_int_py_close (PyObject *self, PyObject *args) if (PyEval_ThreadsInitialized ()) PyEval_RestoreThread (py_save); - for (i = 0; i < len; ++i) - Py_XDECREF (callbacks[i]); - free (callbacks); + if (len > 0) { + size_t i; + for (i = 0; i < len; ++i) + Py_XDECREF (callbacks[i]); + free (callbacks); + } Py_INCREF (Py_None); return Py_None; @@ -260,6 +268,10 @@ get_all_event_callbacks (guestfs_h *g, size_t *len_rtn) cb = guestfs_next_private (g, &key); } + /* No events, so no need to allocate anything. */ + if (*len_rtn == 0) + return NULL; + /* Copy them into the return array. */ r = malloc (sizeof (PyObject *) * (*len_rtn)); if (r == NULL) {