Subject: bug#25816: Emacs xwidget GC issue with callback

From: Paul Eggert <[email-masked]>
Date: Mon, 20 Feb 2017 09:10:32 -0800

When configuring with --with-xwidgets --enable-check-lisp-object-type the Emacs 
build would fail due to a type confusion in src/xwidget.c, which I attempted to 
fix by installing the attached patch. However, as noted in the patch, this code 
appears to have a garbage-collection bug, as it converts a Lisp_Object to a C 
pointer and stores that pointer (for what appears to be an indefinite period of 
time) into a C object that the garbage collector does not know about. If 
garbage-collection reclaims the object before the callback is used, disaster can 
occur. As I don't know the lifetime of the C object I'm reluctant to try to fix 
this myself, so I'm filing this bug report in the hope that an xwidget expert 
can fix it.

From 5baceff92d8947ed5b64fadae808b366f5ca1da7 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Mon, 20 Feb 2017 08:53:50 -0800
Subject: [PATCH] Port xwidget to -DCHECK_LISP_OBJECT_TYPE
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* src/xwidget.c (webkit_javascript_finished_cb)
(Fxwidget_webkit_execute_script): Don't assume Lisp_Object is an
integer.  This fix is just a hack; I’ll file a bug report about
the underlying problem.
---
 src/xwidget.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/src/xwidget.c b/src/xwidget.c
index 5c276b1..dc705bb 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -389,7 +389,10 @@ webkit_javascript_finished_cb (GObject      *webview,
     /* Register an xwidget event here, which then runs the callback.
        This ensures that the callback runs in sync with the Emacs
        event loop.  */
-    store_xwidget_js_callback_event (xw, (Lisp_Object)lisp_callback,
+    /* FIXME: This might lead to disaster if LISP_CALLBACK’s object
+       was garbage collected before now.  See the FIXME in
+       Fxwidget_webkit_execute_script.  */
+    store_xwidget_js_callback_event (xw, XIL ((intptr_t) lisp_callback),
                                      lisp_value);
 }
 
@@ -714,8 +717,13 @@ argument procedure FUN.*/)
   if (!NILP (fun) && !FUNCTIONP (fun))
     wrong_type_argument (Qinvalid_function, fun);
 
-  void *callback = (FUNCTIONP (fun)) ?
-    &webkit_javascript_finished_cb : NULL;
+  GAsyncReadyCallback callback
+    = FUNCTIONP (fun) ? webkit_javascript_finished_cb : NULL;
+
+  /* FIXME: This hack might lead to disaster if FUN is garbage
+     collected before store_xwidget_js_callback_event makes it visible
+     to Lisp again.  See the FIXME in webkit_javascript_finished_cb.  */
+  gpointer callback_arg = (gpointer) (intptr_t) XLI (fun);
 
   /* JavaScript execution happens asynchronously.  If an elisp
      callback function is provided we pass it to the C callback
@@ -723,8 +731,7 @@ argument procedure FUN.*/)
   webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (xw->widget_osr),
                                   SSDATA (script),
                                   NULL, /* cancelable */
-                                  callback,
-                                  (gpointer) fun);
+                                  callback, callback_arg);
   return Qnil;
 }
 
-- 
2.9.3