pygobject r1014 - in branches/pygobject-2-16: . gio



Author: gianmt
Date: Fri Feb 20 21:26:00 2009
New Revision: 1014
URL: http://svn.gnome.org/viewvc/pygobject?rev=1014&view=rev

Log:
gio.InputStream.read_async can cause memory corruption, fix #567792

Modified:
   branches/pygobject-2-16/ChangeLog
   branches/pygobject-2-16/gio/ginputstream.override
   branches/pygobject-2-16/gio/gio.override

Modified: branches/pygobject-2-16/gio/ginputstream.override
==============================================================================
--- branches/pygobject-2-16/gio/ginputstream.override	(original)
+++ branches/pygobject-2-16/gio/ginputstream.override	Fri Feb 20 21:26:00 2009
@@ -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 @@
     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 @@
                                      &io_priority,
                                      &pycancellable,
                                      &notify->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 @@
     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

Modified: branches/pygobject-2-16/gio/gio.override
==============================================================================
--- branches/pygobject-2-16/gio/gio.override	(original)
+++ branches/pygobject-2-16/gio/gio.override	Fri Feb 20 21:26:00 2009
@@ -37,23 +37,18 @@
     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 @@
 }
 
 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 @@
     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 @@
     }
 
     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);
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]