aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndreas Schwab2018-05-21 14:18:24 +0200
committerAndreas Schwab2018-05-21 22:51:20 +0200
commit8811c2408d3329eb84efe63d148a80afd080017c (patch)
tree71b5c2952c571590019a1f827a16ddf05da3e380 /src
parent7b9fb7ace4357f1d630bf6b332eab34ae130ca44 (diff)
downloademacs-8811c2408d3329eb84efe63d148a80afd080017c.tar.gz
emacs-8811c2408d3329eb84efe63d148a80afd080017c.zip
Make xwidget-webkit-execute-script safe against GC (Bug#31545)
* src/xwidget.h (struct xwidget): Add script_callbacks. * src/xwidget.c (save_script_callback): New function. (Fxwidget_webkit_execute_script): Use it. Encode script before passing to execution engine. Always use a callback. (webkit_javascript_finished_cb): Deallocate script. (kill_buffer_xwidgets): Deallocate remaining scripts. (Fxwidget_webkit_zoom): Doc fix. (Fxwidget_resize): Doc fix.
Diffstat (limited to 'src')
-rw-r--r--src/xwidget.c99
-rw-r--r--src/xwidget.h3
2 files changed, 75 insertions, 27 deletions
diff --git a/src/xwidget.c b/src/xwidget.c
index 95fa5f19c40..c4a3b1990d3 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -362,7 +362,7 @@ webkit_js_to_lisp (JSContextRef context, JSValueRef value)
362static void 362static void
363webkit_javascript_finished_cb (GObject *webview, 363webkit_javascript_finished_cb (GObject *webview,
364 GAsyncResult *result, 364 GAsyncResult *result,
365 gpointer lisp_callback) 365 gpointer arg)
366{ 366{
367 WebKitJavascriptResult *js_result; 367 WebKitJavascriptResult *js_result;
368 JSValueRef value; 368 JSValueRef value;
@@ -370,6 +370,11 @@ webkit_javascript_finished_cb (GObject *webview,
370 GError *error = NULL; 370 GError *error = NULL;
371 struct xwidget *xw = g_object_get_data (G_OBJECT (webview), 371 struct xwidget *xw = g_object_get_data (G_OBJECT (webview),
372 XG_XWIDGET); 372 XG_XWIDGET);
373 ptrdiff_t script_idx = (ptrdiff_t) arg;
374 Lisp_Object script_callback = AREF (xw->script_callbacks, script_idx);
375 ASET (xw->script_callbacks, script_idx, Qnil);
376 if (!NILP (script_callback))
377 xfree (XSAVE_POINTER (XCAR (script_callback), 0));
373 378
374 js_result = webkit_web_view_run_javascript_finish 379 js_result = webkit_web_view_run_javascript_finish
375 (WEBKIT_WEB_VIEW (webview), result, &error); 380 (WEBKIT_WEB_VIEW (webview), result, &error);
@@ -381,18 +386,19 @@ webkit_javascript_finished_cb (GObject *webview,
381 return; 386 return;
382 } 387 }
383 388
384 context = webkit_javascript_result_get_global_context (js_result); 389 if (!NILP (script_callback) && !NILP (XCDR (script_callback)))
385 value = webkit_javascript_result_get_value (js_result); 390 {
386 Lisp_Object lisp_value = webkit_js_to_lisp (context, value); 391 context = webkit_javascript_result_get_global_context (js_result);
387 webkit_javascript_result_unref (js_result); 392 value = webkit_javascript_result_get_value (js_result);
393 Lisp_Object lisp_value = webkit_js_to_lisp (context, value);
394
395 /* Register an xwidget event here, which then runs the callback.
396 This ensures that the callback runs in sync with the Emacs
397 event loop. */
398 store_xwidget_js_callback_event (xw, XCDR (script_callback), lisp_value);
399 }
388 400
389 /* Register an xwidget event here, which then runs the callback. 401 webkit_javascript_result_unref (js_result);
390 This ensures that the callback runs in sync with the Emacs
391 event loop. */
392 /* FIXME: This might lead to disaster if LISP_CALLBACK's object
393 was garbage collected before now. See the FIXME in
394 Fxwidget_webkit_execute_script. */
395 store_xwidget_js_callback_event (xw, XPL (lisp_callback), lisp_value);
396} 402}
397 403
398 404
@@ -684,8 +690,7 @@ DEFUN ("xwidget-webkit-goto-uri",
684DEFUN ("xwidget-webkit-zoom", 690DEFUN ("xwidget-webkit-zoom",
685 Fxwidget_webkit_zoom, Sxwidget_webkit_zoom, 691 Fxwidget_webkit_zoom, Sxwidget_webkit_zoom,
686 2, 2, 0, 692 2, 2, 0,
687 doc: /* Change the zoom factor of the xwidget webkit instance 693 doc: /* Change the zoom factor of the xwidget webkit instance referenced by XWIDGET. */)
688referenced by XWIDGET. */)
689 (Lisp_Object xwidget, Lisp_Object factor) 694 (Lisp_Object xwidget, Lisp_Object factor)
690{ 695{
691 WEBKIT_FN_INIT (); 696 WEBKIT_FN_INIT ();
@@ -700,12 +705,46 @@ referenced by XWIDGET. */)
700 return Qnil; 705 return Qnil;
701} 706}
702 707
708/* Save script and fun in the script/callback save vector and return
709 its index. */
710static ptrdiff_t
711save_script_callback (struct xwidget *xw, Lisp_Object script, Lisp_Object fun)
712{
713 ptrdiff_t script_bytes = STRING_BYTES (XSTRING (script));
714 char *script_data = xmalloc (script_bytes + 1);
715 memcpy (script_data, SSDATA (script), script_bytes + 1);
716
717 ptrdiff_t idx;
718 Lisp_Object cbs = xw->script_callbacks;
719 if (NILP (cbs))
720 xw->script_callbacks = cbs = Fmake_vector (make_number (32), Qnil);
721
722 /* Find first free index. */
723 for (idx = 0; ; idx++)
724 {
725 if (idx >= ASIZE (cbs))
726 {
727 /* Resize script/callback save vector. */
728 Lisp_Object new_cbs = Fmake_vector (make_number (idx + 32), Qnil);
729 ptrdiff_t n;
730 for (n = 0; n < idx; n++)
731 ASET (new_cbs, n, AREF (cbs, n));
732 xw->script_callbacks = cbs = new_cbs;
733 }
734 if (NILP (AREF (cbs, idx)))
735 {
736 ASET (cbs, idx, Fcons (make_save_ptr (script_data), fun));
737 break;
738 }
739 }
740 return idx;
741}
703 742
704DEFUN ("xwidget-webkit-execute-script", 743DEFUN ("xwidget-webkit-execute-script",
705 Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script, 744 Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script,
706 2, 3, 0, 745 2, 3, 0,
707 doc: /* Make the Webkit XWIDGET execute JavaScript SCRIPT. If 746 doc: /* Make the Webkit XWIDGET execute JavaScript SCRIPT.
708FUN is provided, feed the JavaScript return value to the single 747If FUN is provided, feed the JavaScript return value to the single
709argument procedure FUN.*/) 748argument procedure FUN.*/)
710 (Lisp_Object xwidget, Lisp_Object script, Lisp_Object fun) 749 (Lisp_Object xwidget, Lisp_Object script, Lisp_Object fun)
711{ 750{
@@ -714,28 +753,24 @@ argument procedure FUN.*/)
714 if (!NILP (fun) && !FUNCTIONP (fun)) 753 if (!NILP (fun) && !FUNCTIONP (fun))
715 wrong_type_argument (Qinvalid_function, fun); 754 wrong_type_argument (Qinvalid_function, fun);
716 755
717 GAsyncReadyCallback callback 756 script = ENCODE_SYSTEM (script);
718 = FUNCTIONP (fun) ? webkit_javascript_finished_cb : NULL;
719 757
720 /* FIXME: The following hack assumes USE_LSB_TAG. */ 758 /* Protect script and fun during GC. */
721 verify (USE_LSB_TAG); 759 ptrdiff_t idx = save_script_callback (xw, script, fun);
722 /* FIXME: This hack might lead to disaster if FUN is garbage
723 collected before store_xwidget_js_callback_event makes it visible
724 to Lisp again. See the FIXME in webkit_javascript_finished_cb. */
725 gpointer callback_arg = XLP (fun);
726 760
727 /* JavaScript execution happens asynchronously. If an elisp 761 /* JavaScript execution happens asynchronously. If an elisp
728 callback function is provided we pass it to the C callback 762 callback function is provided we pass it to the C callback
729 procedure that retrieves the return value. */ 763 procedure that retrieves the return value. */
730 webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (xw->widget_osr), 764 webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (xw->widget_osr),
731 SSDATA (script), 765 XSAVE_POINTER (XCAR (AREF (xw->script_callbacks, idx)), 0),
732 NULL, /* cancelable */ 766 NULL, /* cancelable */
733 callback, callback_arg); 767 webkit_javascript_finished_cb,
768 (gpointer) idx);
734 return Qnil; 769 return Qnil;
735} 770}
736 771
737DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, 772DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
738 doc: /* Resize XWIDGET. NEW_WIDTH, NEW_HEIGHT define the new size. */ ) 773 doc: /* Resize XWIDGET to NEW_WIDTH, NEW_HEIGHT. */ )
739 (Lisp_Object xwidget, Lisp_Object new_width, Lisp_Object new_height) 774 (Lisp_Object xwidget, Lisp_Object new_width, Lisp_Object new_height)
740{ 775{
741 CHECK_XWIDGET (xwidget); 776 CHECK_XWIDGET (xwidget);
@@ -1197,6 +1232,16 @@ kill_buffer_xwidgets (Lisp_Object buffer)
1197 gtk_widget_destroy (xw->widget_osr); 1232 gtk_widget_destroy (xw->widget_osr);
1198 gtk_widget_destroy (xw->widgetwindow_osr); 1233 gtk_widget_destroy (xw->widgetwindow_osr);
1199 } 1234 }
1235 if (!NILP (xw->script_callbacks))
1236 {
1237 ptrdiff_t idx;
1238 for (idx = 0; idx < ASIZE (xw->script_callbacks); idx++)
1239 {
1240 if (!NILP (AREF (xw->script_callbacks, idx)))
1241 xfree (XSAVE_POINTER (XCAR (AREF (xw->script_callbacks, idx)), 0));
1242 ASET (xw->script_callbacks, idx, Qnil);
1243 }
1244 }
1200 } 1245 }
1201 } 1246 }
1202} 1247}
diff --git a/src/xwidget.h b/src/xwidget.h
index 8267012d5d6..93f4cfb7949 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -47,6 +47,9 @@ struct xwidget
47 /* A title used for button labels, for instance. */ 47 /* A title used for button labels, for instance. */
48 Lisp_Object title; 48 Lisp_Object title;
49 49
50 /* Vector of currently executing scripts with callbacks. */
51 Lisp_Object script_callbacks;
52
50 /* Here ends the Lisp part. "height" is the marker field. */ 53 /* Here ends the Lisp part. "height" is the marker field. */
51 54
52 int height; 55 int height;