]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix junk data being returned with incremental selection transfers
authorPo Lu <luangruo@yahoo.com>
Tue, 30 Aug 2022 11:27:39 +0000 (19:27 +0800)
committerPo Lu <luangruo@yahoo.com>
Tue, 30 Aug 2022 11:28:03 +0000 (19:28 +0800)
* src/xselect.c (receive_incremental_selection): New arg
REAL_BYTES_RET.  Set it to the actual size instead of using the
size of the array after it was grown by xpalloc.
(x_get_window_property_as_lisp_data): Adjust call to
receive_incremental_selection.

src/xselect.c

index bab0400540e6bba586c441caedb1e3dd0bb44cf7..74d762f3055fb87e1d920a5cc9b72922c0e1f194 100644 (file)
@@ -1567,7 +1567,8 @@ receive_incremental_selection (struct x_display_info *dpyinfo,
                               unsigned char **data_ret,
                               ptrdiff_t *size_bytes_ret,
                               Atom *type_ret, int *format_ret,
-                              unsigned long *size_ret)
+                              unsigned long *size_ret,
+                              ptrdiff_t *real_bytes_ret)
 {
   ptrdiff_t offset = 0;
   struct prop_location *wait_object;
@@ -1622,7 +1623,8 @@ receive_incremental_selection (struct x_display_info *dpyinfo,
 
       if (tmp_size_bytes == 0) /* we're done */
        {
-         TRACE0 ("Done reading incrementally");
+         TRACE1 ("Done reading incrementally; total bytes: %"pD"d",
+                 *size_bytes_ret);
 
          if (! waiting_for_other_props_on_window (display, window))
            XSelectInput (display, window, STANDARD_EVENT_SET);
@@ -1652,6 +1654,19 @@ receive_incremental_selection (struct x_display_info *dpyinfo,
       memcpy ((*data_ret) + offset, tmp_data, tmp_size_bytes);
       offset += tmp_size_bytes;
 
+      /* *size_bytes_ret is not really the size of the data inside the
+        buffer; it is the size of the buffer allocated by xpalloc.
+
+        This matters when the cardinal specified in the INCR property
+        (a _lower bound_ on the size of the selection data) is
+        smaller than the actual selection contents, which can happen
+        when programs are streaming selection data from a file
+        descriptor.  In that case, we used to return junk if xpalloc
+        decided to grow the buffer by more than the provided
+        increment; to avoid that, store the actual size of the
+        selection data in *real_bytes_ret.  */
+      *real_bytes_ret += tmp_size_bytes;
+
       /* Use xfree, not XFree, because x_get_window_property
         calls xmalloc itself.  */
       xfree (tmp_data);
@@ -1674,10 +1689,14 @@ x_get_window_property_as_lisp_data (struct x_display_info *dpyinfo,
   int actual_format;
   unsigned long actual_size;
   unsigned char *data = 0;
-  ptrdiff_t bytes = 0;
+  ptrdiff_t bytes = 0, array_bytes;
   Lisp_Object val;
   Display *display = dpyinfo->display;
 
+  /* array_bytes is only used as an argument to xpalloc.  The actual
+     size of the data inside the buffer is inside bytes.  */
+  array_bytes = 0;
+
   TRACE0 ("Reading selection data");
 
   x_get_window_property (display, window, property, &data, &bytes,
@@ -1718,10 +1737,15 @@ x_get_window_property_as_lisp_data (struct x_display_info *dpyinfo,
         calls xmalloc itself.  */
       xfree (data);
       unblock_input ();
+
+      /* Clear bytes again.  Previously, receive_incremental_selection
+        would set this to min_size_bytes, but that is now done to
+        array_bytes instead.  */
+      bytes = 0;
       receive_incremental_selection (dpyinfo, window, property, target_type,
-                                    min_size_bytes, &data, &bytes,
+                                    min_size_bytes, &data, &array_bytes,
                                     &actual_type, &actual_format,
-                                    &actual_size);
+                                    &actual_size, &bytes);
     }
 
   if (!for_multiple)