[gjs] closure: Prevent use-after-free in closures



commit 41b78ae516946cb0753e44df4153dd227fd8a2e0
Author: Philip Chimento <philip chimento gmail com>
Date:   Tue Jun 20 19:31:15 2017 -0700

    closure: Prevent use-after-free in closures
    
    Closures trace the function object that they call on, in order to keep
    the function alive during garbage collection. When the closure is
    invalidated, we break that link so the function can be garbage collected,
    but we must do so in an idle function, since it is illegal to stop
    tracing a GC-thing in the middle of GC.
    
    However, this caused a possible use-after-free if the closure was
    scheduled to stop tracing the function object, but the last reference on
    the closure was dropped before the idle function could be run.
    
    Similar to the recent fix in gi/object.cpp [commit 2593d3d], this avoids
    use-after-free by cancelling any pending idle function in the finalize
    notifier, and dropping the function object immediately.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=783935

 gi/closure.cpp |   14 ++++++++++++--
 1 files changed, 12 insertions(+), 2 deletions(-)
---
diff --git a/gi/closure.cpp b/gi/closure.cpp
index e3ef0ba..6352c7f 100644
--- a/gi/closure.cpp
+++ b/gi/closure.cpp
@@ -35,6 +35,7 @@
 struct Closure {
     JSContext *context;
     GjsMaybeOwned<JSObject *> obj;
+    unsigned idle_clear_id;
 };
 
 struct GjsClosure {
@@ -129,6 +130,7 @@ closure_clear_idle(void *data)
 
     closure->priv.obj.reset();
     closure->priv.context = nullptr;
+    closure->priv.idle_clear_id = 0;
 
     g_closure_unref(static_cast<GClosure *>(data));
     return G_SOURCE_REMOVE;
@@ -174,7 +176,7 @@ closure_invalidated(gpointer data,
                       "removing our destroy notifier on global object)",
                       closure);
 
-    g_idle_add(closure_clear_idle, closure);
+    c->idle_clear_id = g_idle_add(closure_clear_idle, closure);
     g_closure_ref(closure);
 }
 
@@ -183,7 +185,8 @@ closure_set_invalid(gpointer  data,
                     GClosure *closure)
 {
     GJS_DEC_COUNTER(closure);
-    g_idle_add(closure_clear_idle, closure);
+    Closure *c = &(reinterpret_cast<GjsClosure *>(closure))->priv;
+    c->idle_clear_id = g_idle_add(closure_clear_idle, closure);
     g_closure_ref(closure);
 }
 
@@ -193,6 +196,13 @@ closure_finalize(gpointer  data,
 {
     Closure *self = &((GjsClosure*) closure)->priv;
 
+    if (self->idle_clear_id > 0) {
+        /* Remove any pending closure_clear_idle(), we are doing it
+         * immediately here. */
+        g_source_remove(self->idle_clear_id);
+        closure_clear_idle(closure);
+    }
+
     self->~Closure();
 }
 


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