diff options
| -rw-r--r-- | ChangeLog | 19 | ||||
| -rw-r--r-- | gio/ginputstream.override | 100 | ||||
| -rw-r--r-- | gio/gio.override | 71 |
3 files changed, 96 insertions, 94 deletions
@@ -1,3 +1,22 @@ +2009-01-29 Paul Pogonyshev <pogonyshev@gmx.net> + + Bug 567792 – gio.InputStream.read_async can cause memory + corruption + + * gio/gio.override (py_decref_callback): Remove (unused now). + (pygio_notify_allocate_buffer, pygio_notify_attach_to_result) + (pygio_notify_get_attached): New functions. + (async_result_callback_marshal): Attach to the result object if + asked and then don't free self. Fix reference leak (spotted by + Gustavo). + + * gio/ginputstream.override (async_result_callback_marshal_read): + Remove. Use new attachment functionality in + async_result_callback_marshal() instead. + (_wrap_g_input_stream_read_async): Use the new functions (also + those mentioned in the cleanup log below). + (_wrap_g_input_stream_read_finish): Use the new functions. + 2009-01-27 Daniel Elstner <danielk@openismus.com> * codegen/docextract_to_xml.py (escape_text): Do not escape the diff --git a/gio/ginputstream.override b/gio/ginputstream.override index 43cd22f..ae5b3a2 100644 --- a/gio/ginputstream.override +++ b/gio/ginputstream.override @@ -23,55 +23,6 @@ headers #define BUFSIZE 8192 -typedef struct { - PyObject *callback; - PyObject *data; - guchar *buffer; -} PyGIONotifyRead; - -static void -async_result_callback_marshal_read(GObject *source_object, - GAsyncResult *result, - PyGIONotifyRead *notify) -{ - PyObject *ret; - PyGILState_STATE state; - static GQuark quark = 0; - - state = pyg_gil_state_ensure(); - - /* buffer is only used by read_async */ - if (notify->buffer) { - if (!quark) - quark = g_quark_from_string("pygio::buffer"); - g_object_set_qdata_full(G_OBJECT(result), quark, - notify->buffer, py_decref_callback); - } - - if (notify->data) - ret = PyEval_CallFunction(notify->callback, "(OOO)", - pygobject_new(source_object), - pygobject_new((GObject *)result), - notify->data); - else - ret = PyObject_CallFunction(notify->callback, "(OO)", - pygobject_new(source_object), - pygobject_new((GObject *)result)); - - if (ret == NULL) - { - PyErr_Print(); - PyErr_Clear(); - } - - Py_XDECREF(ret); - - Py_DECREF(notify->callback); - Py_XDECREF(notify->data); - g_slice_free(PyGIONotifyRead, notify); - - pyg_gil_state_release(state); -} %% override g_input_stream_read kwargs static PyObject * @@ -224,9 +175,9 @@ _wrap_g_input_stream_read_async(PyGObject *self, int io_priority = G_PRIORITY_DEFAULT; PyGObject *pycancellable = NULL; GCancellable *cancellable; - PyGIONotifyRead *notify; + PyGIONotify *notify; - notify = g_slice_new0(PyGIONotifyRead); + notify = pygio_notify_new(); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "lO|iOO:InputStream.read_async", @@ -236,37 +187,34 @@ _wrap_g_input_stream_read_async(PyGObject *self, &io_priority, &pycancellable, ¬ify->data)) - { - g_slice_free(PyGIONotifyRead, notify); - return NULL; - } + goto error; - if (!PyCallable_Check(notify->callback)) - { - PyErr_SetString(PyExc_TypeError, "callback argument not callable"); - g_slice_free(PyGIONotifyRead, notify); - return NULL; - } - Py_INCREF(notify->callback); - Py_XINCREF(notify->data); + if (!pygio_notify_callback_is_valid(notify)) + goto error; if (!pygio_check_cancellable(pycancellable, &cancellable)) - return NULL; + goto error; - notify->buffer = g_malloc(count); - if (notify->buffer == NULL) - return NULL; + if (!pygio_notify_allocate_buffer(notify, count)) + goto error; + + pygio_notify_reference_callback(notify); + pygio_notify_attach_to_result(notify); g_input_stream_read_async(G_INPUT_STREAM(self->obj), notify->buffer, - count, + notify->buffer_size, io_priority, cancellable, - (GAsyncReadyCallback)async_result_callback_marshal_read, + (GAsyncReadyCallback) async_result_callback_marshal, notify); Py_INCREF(Py_None); return Py_None; + + error: + pygio_notify_free(notify); + return NULL; } %% override g_input_stream_read_finish kwargs @@ -278,31 +226,25 @@ _wrap_g_input_stream_read_finish(PyGObject *self, static char *kwlist[] = { "result", NULL }; PyGObject *result; GError *error = NULL; - static GQuark quark = 0; - gchar *buffer; Py_ssize_t bytesread; - - if (!quark) - quark = g_quark_from_string("pygio::buffer"); + PyGIONotify *notify; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:GInputStream.read_finish", kwlist, &PyGAsyncResult_Type, &result)) return NULL; - bytesread = g_input_stream_read_finish(G_INPUT_STREAM(self->obj), G_ASYNC_RESULT(result->obj), &error); if (pyg_error_check(&error)) return NULL; - if (bytesread == 0) { + if (bytesread == 0) return PyString_FromString(""); - } - buffer = g_object_get_qdata(G_OBJECT(result->obj), quark); - return PyString_FromStringAndSize(buffer, bytesread); + notify = pygio_notify_get_attached(result); + return PyString_FromStringAndSize(notify->buffer, bytesread); } %% override g_input_stream_close_async kwargs diff --git a/gio/gio.override b/gio/gio.override index d0a694b..7fb70a5 100644 --- a/gio/gio.override +++ b/gio/gio.override @@ -37,23 +37,18 @@ typedef struct { gboolean referenced; PyObject *callback; PyObject *data; + gboolean attach_self; gpointer buffer; gsize buffer_size; } PyGIONotify; -static void -py_decref_callback (gpointer data) +static GQuark +pygio_notify_get_internal_quark(void) { - Py_DECREF((PyObject*)data); -} - -static void -pygio_notify_copy_buffer(PyGIONotify *notify, gpointer buffer, gsize buffer_size) -{ - if (buffer_size > 0) { - notify->buffer = g_slice_copy(buffer_size, buffer); - notify->buffer_size = buffer_size; - } + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_string("pygio::notify"); + return quark; } static PyGIONotify * @@ -109,6 +104,43 @@ pygio_notify_reference_callback(PyGIONotify *notify) } static void +pygio_notify_copy_buffer(PyGIONotify *notify, gpointer buffer, gsize buffer_size) +{ + if (buffer_size > 0) { + notify->buffer = g_slice_copy(buffer_size, buffer); + notify->buffer_size = buffer_size; + } +} + +static gboolean +pygio_notify_allocate_buffer(PyGIONotify *notify, gsize buffer_size) +{ + if (buffer_size > 0) { + notify->buffer = g_slice_alloc(buffer_size); + if (!notify->buffer) { + PyErr_Format(PyExc_MemoryError, "failed to allocate %d bytes", buffer_size); + return FALSE; + } + + notify->buffer_size = buffer_size; + } + + return TRUE; +} + +static void +pygio_notify_attach_to_result(PyGIONotify *notify) +{ + notify->attach_self = TRUE; +} + +static PyGIONotify * +pygio_notify_get_attached(PyGObject *result) +{ + return g_object_get_qdata(G_OBJECT(result->obj), pygio_notify_get_internal_quark()); +} + +static void pygio_notify_free(PyGIONotify *notify) { if (notify) { @@ -137,13 +169,18 @@ async_result_callback_marshal(GObject *source_object, if (!notify->referenced) g_warning("pygio_notify_reference_callback() hasn't been called before using the structure"); + if (notify->attach_self) { + g_object_set_qdata_full(G_OBJECT(result), pygio_notify_get_internal_quark(), + notify, (GDestroyNotify) pygio_notify_free); + } + if (notify->data) - ret = PyEval_CallFunction(notify->callback, "(OOO)", + ret = PyEval_CallFunction(notify->callback, "NNO", pygobject_new(source_object), pygobject_new((GObject *)result), notify->data); else - ret = PyObject_CallFunction(notify->callback, "(OO)", + ret = PyObject_CallFunction(notify->callback, "NN", pygobject_new(source_object), pygobject_new((GObject *)result)); @@ -153,7 +190,11 @@ async_result_callback_marshal(GObject *source_object, } Py_XDECREF(ret); - pygio_notify_free(notify); + + /* Otherwise the structure is attached to 'result' and will be + * freed when that object dies. */ + if (!notify->attach_self) + pygio_notify_free(notify); pyg_gil_state_release(state); } |
