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.
This commit is contained in:
Po Lu 2023-07-03 11:45:04 +08:00
parent 30f83e3093
commit d679f9e388

View file

@ -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