diff options
| author | Andreas Schwab | 2018-05-21 14:18:24 +0200 |
|---|---|---|
| committer | Andreas Schwab | 2018-05-21 22:51:20 +0200 |
| commit | 8811c2408d3329eb84efe63d148a80afd080017c (patch) | |
| tree | 71b5c2952c571590019a1f827a16ddf05da3e380 /src | |
| parent | 7b9fb7ace4357f1d630bf6b332eab34ae130ca44 (diff) | |
| download | emacs-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.c | 99 | ||||
| -rw-r--r-- | src/xwidget.h | 3 |
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) | |||
| 362 | static void | 362 | static void |
| 363 | webkit_javascript_finished_cb (GObject *webview, | 363 | webkit_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", | |||
| 684 | DEFUN ("xwidget-webkit-zoom", | 690 | DEFUN ("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. */) |
| 688 | referenced 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. */ | ||
| 710 | static ptrdiff_t | ||
| 711 | save_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 | ||
| 704 | DEFUN ("xwidget-webkit-execute-script", | 743 | DEFUN ("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. |
| 708 | FUN is provided, feed the JavaScript return value to the single | 747 | If FUN is provided, feed the JavaScript return value to the single |
| 709 | argument procedure FUN.*/) | 748 | argument 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 | ||
| 737 | DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, | 772 | DEFUN ("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; |