From d679f9e388cde367d8d0c2e438b62a16ec1aca67 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Mon, 3 Jul 2023 11:45:04 +0800 Subject: [PATCH] Fix leak when quit arrives during incremental selection transfer * src/xselect.c (x_free_selection_data): New function. (x_get_window_property_as_lisp_data): Free `data' reliably if receive_incremental_selection quits. --- src/xselect.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/xselect.c b/src/xselect.c index 40be6d4c00c..c38a1f8b6a9 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -1989,9 +1989,22 @@ receive_incremental_selection (struct x_display_info *dpyinfo, } + +/* Free the selection data allocated inside *DATA, which is actually a + pointer to unsigned char *. */ + +static void +x_free_selection_data (void *data) +{ + unsigned char **ptr; + + ptr = data; + xfree (*ptr); +} + /* Fetch a value from property PROPERTY of X window WINDOW on display - DISPLAY. TARGET_TYPE and SELECTION_ATOM are used in error message - if this fails. */ + DISPLAY. TARGET_TYPE and SELECTION_ATOM are used in the error + message signaled if this fails. */ static Lisp_Object x_get_window_property_as_lisp_data (struct x_display_info *dpyinfo, @@ -2007,6 +2020,7 @@ x_get_window_property_as_lisp_data (struct x_display_info *dpyinfo, ptrdiff_t bytes = 0, array_bytes; Lisp_Object val; Display *display = dpyinfo->display; + specpdl_ref count; /* array_bytes is only used as an argument to xpalloc. The actual size of the data inside the buffer is inside bytes. */ @@ -2042,6 +2056,13 @@ x_get_window_property_as_lisp_data (struct x_display_info *dpyinfo, } } + /* Make sure DATA is freed even if `receive_incremental_connection' + quits. Use xfree, not XFree, because x_get_window_property calls + xmalloc itself. */ + + count = SPECPDL_INDEX (); + record_unwind_protect_ptr (x_free_selection_data, &data); + if (!for_multiple && actual_type == dpyinfo->Xatom_INCR) { /* That wasn't really the data, just the beginning. */ @@ -2051,6 +2072,9 @@ x_get_window_property_as_lisp_data (struct x_display_info *dpyinfo, /* Use xfree, not XFree, because x_get_window_property calls xmalloc itself. */ xfree (data); + + /* In case quitting happens below. */ + data = NULL; unblock_input (); /* Clear bytes again. Previously, receive_incremental_selection @@ -2077,10 +2101,8 @@ x_get_window_property_as_lisp_data (struct x_display_info *dpyinfo, val = selection_data_to_lisp_data (dpyinfo, data, bytes, actual_type, actual_format); - /* Use xfree, not XFree, because x_get_window_property - calls xmalloc itself. */ - xfree (data); - return val; + /* This will also free `data'. */ + return unbind_to (count, val); } /* These functions convert from the selection data read from the server into -- 2.39.2