Simplify previous changes.
[bpt/emacs.git] / src / xselect.c
index 5b01fc2..77bda79 100644 (file)
@@ -66,22 +66,15 @@ static Lisp_Object wait_for_property_change_unwind (Lisp_Object);
 static void wait_for_property_change (struct prop_location *);
 static Lisp_Object x_get_foreign_selection (Lisp_Object, Lisp_Object,
                                            Lisp_Object, Lisp_Object);
-static void x_get_window_property (Display *, Window, Atom,
-                                   unsigned char **, int *,
-                                   Atom *, int *, unsigned long *, int);
-static void receive_incremental_selection (Display *, Window, Atom,
-                                           Lisp_Object, unsigned,
-                                           unsigned char **, int *,
-                                           Atom *, int *, unsigned long *);
 static Lisp_Object x_get_window_property_as_lisp_data (Display *,
                                                        Window, Atom,
                                                        Lisp_Object, Atom);
 static Lisp_Object selection_data_to_lisp_data (Display *,
                                                const unsigned char *,
-                                                int, Atom, int);
+                                               ptrdiff_t, Atom, int);
 static void lisp_data_to_selection_data (Display *, Lisp_Object,
                                          unsigned char **, Atom *,
-                                         unsigned *, int *, int *);
+                                        ptrdiff_t *, int *, int *);
 static Lisp_Object clean_local_selection_data (Lisp_Object);
 
 /* Printing traces to stderr.  */
@@ -112,16 +105,41 @@ static Lisp_Object QUTF8_STRING;  /* This is a type of selection.  */
 static Lisp_Object Qcompound_text_with_extensions;
 
 static Lisp_Object Qforeign_selection;
+static Lisp_Object Qx_lost_selection_functions, Qx_sent_selection_functions;
+
+/* Bytes needed to represent 'long' data.  This is as per libX11; it
+   is not necessarily sizeof (long).  */
+#define X_LONG_SIZE 4
+
+/* Extreme 'short' and 'long' values suitable for libX11.  */
+#define X_SHRT_MAX 0x7fff
+#define X_SHRT_MIN (-1 - X_SHRT_MAX)
+#define X_LONG_MAX 0x7fffffff
+#define X_LONG_MIN (-1 - X_LONG_MAX)
 
 /* If this is a smaller number than the max-request-size of the display,
    emacs will use INCR selection transfer when the selection is larger
    than this.  The max-request-size is usually around 64k, so if you want
    emacs to use incremental selection transfers when the selection is
    smaller than that, set this.  I added this mostly for debugging the
-   incremental transfer stuff, but it might improve server performance.  */
-#define MAX_SELECTION_QUANTUM 0xFFFFFF
+   incremental transfer stuff, but it might improve server performance.
 
-#define SELECTION_QUANTUM(dpy) ((XMaxRequestSize(dpy) << 2) - 100)
+   This value cannot exceed INT_MAX / max (X_LONG_SIZE, sizeof (long))
+   because it is multiplied by X_LONG_SIZE and by sizeof (long) in
+   subscript calculations.  Similarly for PTRDIFF_MAX - 1 or SIZE_MAX
+   - 1 in place of INT_MAX.  */
+#define MAX_SELECTION_QUANTUM                                          \
+  ((int) min (0xFFFFFF, (min (INT_MAX, min (PTRDIFF_MAX, SIZE_MAX) - 1)        \
+                        / max (X_LONG_SIZE, sizeof (long)))))
+
+static int
+selection_quantum (Display *display)
+{
+  long mrs = XMaxRequestSize (display);
+  return (mrs < MAX_SELECTION_QUANTUM / X_LONG_SIZE + 25
+         ? (mrs - 25) * X_LONG_SIZE
+         : MAX_SELECTION_QUANTUM);
+}
 
 #define LOCAL_SELECTION(selection_symbol,dpyinfo)                      \
   assq_no_quit (selection_symbol, dpyinfo->terminal->Vselection_alist)
@@ -476,7 +494,7 @@ static struct x_display_info *selection_request_dpyinfo;
 struct selection_data
 {
   unsigned char *data;
-  unsigned int size;
+  ptrdiff_t size;
   int format;
   Atom type;
   int nofree;
@@ -580,14 +598,11 @@ x_reply_selection_request (struct input_event *event, struct x_display_info *dpy
   XSelectionEvent *reply = &(reply_base.xselection);
   Display *display = SELECTION_EVENT_DISPLAY (event);
   Window window = SELECTION_EVENT_REQUESTOR (event);
-  int bytes_remaining;
-  int max_bytes = SELECTION_QUANTUM (display);
+  ptrdiff_t bytes_remaining;
+  int max_bytes = selection_quantum (display);
   int count = SPECPDL_INDEX ();
   struct selection_data *cs;
 
-  if (max_bytes > MAX_SELECTION_QUANTUM)
-    max_bytes = MAX_SELECTION_QUANTUM;
-
   reply->type = SelectionNotify;
   reply->display = display;
   reply->requestor = window;
@@ -615,11 +630,12 @@ x_reply_selection_request (struct input_event *event, struct x_display_info *dpy
       if (cs->property == None)
        continue;
 
-      bytes_remaining = cs->size * (cs->format / 8);
+      bytes_remaining = cs->size;
+      bytes_remaining *= cs->format >> 3;
       if (bytes_remaining <= max_bytes)
        {
          /* Send all the data at once, with minimal handshaking.  */
-         TRACE1 ("Sending all %d bytes", bytes_remaining);
+         TRACE1 ("Sending all %"pD"d bytes", bytes_remaining);
          XChangeProperty (display, window, cs->property,
                           cs->type, cs->format, PropModeReplace,
                           cs->data, cs->size);
@@ -629,7 +645,7 @@ x_reply_selection_request (struct input_event *event, struct x_display_info *dpy
          /* Send an INCR tag to initiate incremental transfer.  */
          long value[1];
 
-         TRACE2 ("Start sending %d bytes incrementally (%s)",
+         TRACE2 ("Start sending %"pD"d bytes incrementally (%s)",
                  bytes_remaining, XGetAtomName (display, cs->property));
          cs->wait_object
            = expect_property_change (display, window, cs->property,
@@ -637,7 +653,7 @@ x_reply_selection_request (struct input_event *event, struct x_display_info *dpy
 
          /* XChangeProperty expects an array of long even if long is
             more than 32 bits.  */
-         value[0] = bytes_remaining;
+         value[0] = min (bytes_remaining, X_LONG_MAX);
          XChangeProperty (display, window, cs->property,
                           dpyinfo->Xatom_INCR, 32, PropModeReplace,
                           (unsigned char *) value, 1);
@@ -671,7 +687,8 @@ x_reply_selection_request (struct input_event *event, struct x_display_info *dpy
        int had_errors = x_had_errors_p (display);
        UNBLOCK_INPUT;
 
-       bytes_remaining = cs->size * format_bytes;
+       bytes_remaining = cs->size;
+       bytes_remaining *= format_bytes;
 
        /* Wait for the requester to ack by deleting the property.
           This can run Lisp code (process handlers) or signal.  */
@@ -809,7 +826,7 @@ x_handle_selection_request (struct input_event *event)
         non-None property.  */
       Window requestor = SELECTION_EVENT_REQUESTOR (event);
       Lisp_Object multprop;
-      int j, nselections;
+      ptrdiff_t j, nselections;
 
       if (property == None) goto DONE;
       multprop
@@ -855,7 +872,7 @@ x_handle_selection_request (struct input_event *event)
       && !EQ (Vx_sent_selection_functions, Qunbound))
     {
       Lisp_Object args[4];
-      args[0] = Vx_sent_selection_functions;
+      args[0] = Qx_sent_selection_functions;
       args[1] = selection_symbol;
       args[2] = target_symbol;
       args[3] = success ? Qt : Qnil;
@@ -979,7 +996,7 @@ x_handle_selection_clear (struct input_event *event)
   /* Run the `x-lost-selection-functions' abnormal hook.  */
   {
     Lisp_Object args[2];
-    args[0] = Vx_lost_selection_functions;
+    args[0] = Qx_lost_selection_functions;
     args[1] = selection_symbol;
     Frun_hook_with_args (2, args);
   }
@@ -1020,7 +1037,7 @@ x_clear_frame_selections (FRAME_PTR f)
     {
       /* Run the `x-lost-selection-functions' abnormal hook.  */
       Lisp_Object args[2];
-      args[0] = Vx_lost_selection_functions;
+      args[0] = Qx_lost_selection_functions;
       args[1] = Fcar (Fcar (t->Vselection_alist));
       Frun_hook_with_args (2, args);
 
@@ -1033,7 +1050,7 @@ x_clear_frame_selections (FRAME_PTR f)
        && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (XCDR (rest))))))))
       {
        Lisp_Object args[2];
-       args[0] = Vx_lost_selection_functions;
+       args[0] = Qx_lost_selection_functions;
        args[1] = XCAR (XCAR (XCDR (rest)));
        Frun_hook_with_args (2, args);
        XSETCDR (rest, XCDR (XCDR (rest)));
@@ -1268,19 +1285,28 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
 
 static void
 x_get_window_property (Display *display, Window window, Atom property,
-                      unsigned char **data_ret, int *bytes_ret,
+                      unsigned char **data_ret, ptrdiff_t *bytes_ret,
                       Atom *actual_type_ret, int *actual_format_ret,
                       unsigned long *actual_size_ret, int delete_p)
 {
-  int total_size;
+  ptrdiff_t total_size;
   unsigned long bytes_remaining;
-  int offset = 0;
+  ptrdiff_t offset = 0;
+  unsigned char *data = 0;
   unsigned char *tmp_data = 0;
   int result;
-  int buffer_size = SELECTION_QUANTUM (display);
+  int buffer_size = selection_quantum (display);
+
+  /* Wide enough to avoid overflow in expressions using it.  */
+  ptrdiff_t x_long_size = X_LONG_SIZE;
 
-  if (buffer_size > MAX_SELECTION_QUANTUM)
-    buffer_size = MAX_SELECTION_QUANTUM;
+  /* Maximum value for TOTAL_SIZE.  It cannot exceed PTRDIFF_MAX - 1
+     and SIZE_MAX - 1, for an extra byte at the end.  And it cannot
+     exceed LONG_MAX * X_LONG_SIZE, for XGetWindowProperty.  */
+  ptrdiff_t total_size_max =
+    ((min (PTRDIFF_MAX, SIZE_MAX) - 1) / x_long_size < LONG_MAX
+     ? min (PTRDIFF_MAX, SIZE_MAX) - 1
+     : LONG_MAX * x_long_size);
 
   BLOCK_INPUT;
 
@@ -1291,49 +1317,44 @@ x_get_window_property (Display *display, Window window, Atom property,
                               actual_size_ret,
                               &bytes_remaining, &tmp_data);
   if (result != Success)
-    {
-      UNBLOCK_INPUT;
-      *data_ret = 0;
-      *bytes_ret = 0;
-      return;
-    }
+    goto done;
 
   /* This was allocated by Xlib, so use XFree.  */
   XFree ((char *) tmp_data);
 
   if (*actual_type_ret == None || *actual_format_ret == 0)
-    {
-      UNBLOCK_INPUT;
-      return;
-    }
+    goto done;
 
-  total_size = bytes_remaining + 1;
-  *data_ret = (unsigned char *) xmalloc (total_size);
+  if (total_size_max < bytes_remaining)
+    goto size_overflow;
+  total_size = bytes_remaining;
+  data = malloc (total_size + 1);
+  if (! data)
+    goto memory_exhausted;
 
   /* Now read, until we've gotten it all.  */
   while (bytes_remaining)
     {
-#ifdef TRACE_SELECTION
-      unsigned long last = bytes_remaining;
-#endif
+      ptrdiff_t bytes_gotten;
+      int bytes_per_item;
       result
        = XGetWindowProperty (display, window, property,
-                             (long)offset/4, (long)buffer_size/4,
+                             offset / X_LONG_SIZE,
+                             buffer_size / X_LONG_SIZE,
                              False,
                              AnyPropertyType,
                              actual_type_ret, actual_format_ret,
                              actual_size_ret, &bytes_remaining, &tmp_data);
 
-      TRACE2 ("Read %lu bytes from property %s",
-             last - bytes_remaining,
-             XGetAtomName (display, property));
-
       /* If this doesn't return Success at this point, it means that
         some clod deleted the selection while we were in the midst of
         reading it.  Deal with that, I guess.... */
       if (result != Success)
        break;
 
+      bytes_per_item = *actual_format_ret >> 3;
+      xassert (*actual_size_ret <= buffer_size / bytes_per_item);
+
       /* The man page for XGetWindowProperty says:
          "If the returned format is 32, the returned data is represented
           as a long array and should be cast to that type to obtain the
@@ -1347,32 +1368,61 @@ x_get_window_property (Display *display, Window window, Atom property,
          The bytes and offsets passed to XGetWindowProperty refers to the
          property and those are indeed in 32 bit quantities if format is 32.  */
 
+      bytes_gotten = *actual_size_ret;
+      bytes_gotten *= bytes_per_item;
+
+      TRACE2 ("Read %"pD"d bytes from property %s",
+             bytes_gotten, XGetAtomName (display, property));
+
+      if (total_size - offset < bytes_gotten)
+       {
+         unsigned char *data1;
+         ptrdiff_t remaining_lim = total_size_max - offset - bytes_gotten;
+         if (remaining_lim < 0 || remaining_lim < bytes_remaining)
+           goto size_overflow;
+         total_size = offset + bytes_gotten + bytes_remaining;
+         data1 = realloc (data, total_size + 1);
+         if (! data1)
+           goto memory_exhausted;
+         data = data1;
+       }
+
       if (32 < BITS_PER_LONG && *actual_format_ret == 32)
         {
           unsigned long i;
-          int  *idata = (int *) ((*data_ret) + offset);
+         int  *idata = (int *) (data + offset);
           long *ldata = (long *) tmp_data;
 
           for (i = 0; i < *actual_size_ret; ++i)
-            {
-              idata[i]= (int) ldata[i];
-              offset += 4;
-            }
+           idata[i] = ldata[i];
         }
       else
-        {
-          *actual_size_ret *= *actual_format_ret / 8;
-          memcpy ((*data_ret) + offset, tmp_data, *actual_size_ret);
-          offset += *actual_size_ret;
-        }
+       memcpy (data + offset, tmp_data, bytes_gotten);
+
+      offset += bytes_gotten;
 
       /* This was allocated by Xlib, so use XFree.  */
       XFree ((char *) tmp_data);
     }
 
   XFlush (display);
+  data[offset] = '\0';
+
+ done:
   UNBLOCK_INPUT;
+  *data_ret = data;
   *bytes_ret = offset;
+  return;
+
+ size_overflow:
+  free (data);
+  UNBLOCK_INPUT;
+  memory_full (SIZE_MAX);
+
+ memory_exhausted:
+  free (data);
+  UNBLOCK_INPUT;
+  memory_full (total_size + 1);
 }
 \f
 /* Use xfree, not XFree, to free the data obtained with this function.  */
@@ -1381,16 +1431,19 @@ static void
 receive_incremental_selection (Display *display, Window window, Atom property,
                               Lisp_Object target_type,
                               unsigned int min_size_bytes,
-                              unsigned char **data_ret, int *size_bytes_ret,
+                              unsigned char **data_ret,
+                              ptrdiff_t *size_bytes_ret,
                               Atom *type_ret, int *format_ret,
                               unsigned long *size_ret)
 {
-  int offset = 0;
+  ptrdiff_t offset = 0;
   struct prop_location *wait_object;
+  if (min (PTRDIFF_MAX, SIZE_MAX) < min_size_bytes)
+    memory_full (SIZE_MAX);
+  *data_ret = (unsigned char *) xmalloc (min_size_bytes);
   *size_bytes_ret = min_size_bytes;
-  *data_ret = (unsigned char *) xmalloc (*size_bytes_ret);
 
-  TRACE1 ("Read %d bytes incrementally", min_size_bytes);
+  TRACE1 ("Read %u bytes incrementally", min_size_bytes);
 
   /* At this point, we have read an INCR property.
      Delete the property to ack it.
@@ -1415,7 +1468,7 @@ receive_incremental_selection (Display *display, Window window, Atom property,
   while (1)
     {
       unsigned char *tmp_data;
-      int tmp_size_bytes;
+      ptrdiff_t tmp_size_bytes;
 
       TRACE0 ("  Wait for property change");
       wait_for_property_change (wait_object);
@@ -1428,7 +1481,7 @@ receive_incremental_selection (Display *display, Window window, Atom property,
                             &tmp_data, &tmp_size_bytes,
                             type_ret, format_ret, size_ret, 1);
 
-      TRACE1 ("  Read increment of %d bytes", tmp_size_bytes);
+      TRACE1 ("  Read increment of %"pD"d bytes", tmp_size_bytes);
 
       if (tmp_size_bytes == 0) /* we're done */
        {
@@ -1451,11 +1504,10 @@ receive_incremental_selection (Display *display, Window window, Atom property,
       XFlush (display);
       UNBLOCK_INPUT;
 
-      if (*size_bytes_ret < offset + tmp_size_bytes)
-       {
-         *size_bytes_ret = offset + tmp_size_bytes;
-         *data_ret = (unsigned char *) xrealloc (*data_ret, *size_bytes_ret);
-       }
+      if (*size_bytes_ret - offset < tmp_size_bytes)
+       *data_ret = xpalloc (*data_ret, size_bytes_ret,
+                            tmp_size_bytes - (*size_bytes_ret - offset),
+                            -1, 1);
 
       memcpy ((*data_ret) + offset, tmp_data, tmp_size_bytes);
       offset += tmp_size_bytes;
@@ -1481,7 +1533,7 @@ x_get_window_property_as_lisp_data (Display *display, Window window,
   int actual_format;
   unsigned long actual_size;
   unsigned char *data = 0;
-  int bytes = 0;
+  ptrdiff_t bytes = 0;
   Lisp_Object val;
   struct x_display_info *dpyinfo = x_display_info_for_display (display);
 
@@ -1573,7 +1625,7 @@ x_get_window_property_as_lisp_data (Display *display, Window window,
 
 static Lisp_Object
 selection_data_to_lisp_data (Display *display, const unsigned char *data,
-                            int size, Atom type, int format)
+                            ptrdiff_t size, Atom type, int format)
 {
   struct x_display_info *dpyinfo = x_display_info_for_display (display);
 
@@ -1606,7 +1658,7 @@ selection_data_to_lisp_data (Display *display, const unsigned char *data,
           /* Treat ATOM_PAIR type similar to list of atoms.  */
           || type == dpyinfo->Xatom_ATOM_PAIR)
     {
-      int i;
+      ptrdiff_t i;
       /* On a 64 bit machine sizeof(Atom) == sizeof(long) == 8.
          But the callers of these function has made sure the data for
          format == 32 is an array of int.  Thus, use int instead
@@ -1633,28 +1685,29 @@ selection_data_to_lisp_data (Display *display, const unsigned char *data,
   else if (format == 32 && size == sizeof (int))
     return INTEGER_TO_CONS (((unsigned int *) data) [0]);
   else if (format == 16 && size == sizeof (short))
-    return make_number ((int) (((unsigned short *) data) [0]));
+    return make_number (((unsigned short *) data) [0]);
 
   /* Convert any other kind of data to a vector of numbers, represented
      as above (as an integer, or a cons of two 16 bit integers.)
    */
   else if (format == 16)
     {
-      int i;
+      ptrdiff_t i;
       Lisp_Object v;
       v = Fmake_vector (make_number (size / 2), make_number (0));
       for (i = 0; i < size / 2; i++)
        {
-         int j = (int) ((unsigned short *) data) [i];
+         EMACS_INT j = ((unsigned short *) data) [i];
          Faset (v, make_number (i), make_number (j));
        }
       return v;
     }
   else
     {
-      int i;
-      Lisp_Object v = Fmake_vector (make_number (size / 4), make_number (0));
-      for (i = 0; i < size / 4; i++)
+      ptrdiff_t i;
+      Lisp_Object v = Fmake_vector (make_number (size / X_LONG_SIZE),
+                                   make_number (0));
+      for (i = 0; i < size / X_LONG_SIZE; i++)
        {
          unsigned int j = ((unsigned int *) data) [i];
          Faset (v, make_number (i), INTEGER_TO_CONS (j));
@@ -1669,7 +1722,7 @@ selection_data_to_lisp_data (Display *display, const unsigned char *data,
 static void
 lisp_data_to_selection_data (Display *display, Lisp_Object obj,
                             unsigned char **data_ret, Atom *type_ret,
-                            unsigned int *size_ret,
+                            ptrdiff_t *size_ret,
                             int *format_ret, int *nofree_ret)
 {
   Lisp_Object type = Qnil;
@@ -1706,22 +1759,20 @@ lisp_data_to_selection_data (Display *display, Lisp_Object obj,
     }
   else if (SYMBOLP (obj))
     {
+      *data_ret = (unsigned char *) xmalloc (sizeof (Atom) + 1);
       *format_ret = 32;
       *size_ret = 1;
-      *data_ret = (unsigned char *) xmalloc (sizeof (Atom) + 1);
       (*data_ret) [sizeof (Atom)] = 0;
       (*(Atom **) data_ret) [0] = symbol_to_x_atom (dpyinfo, obj);
       if (NILP (type)) type = QATOM;
     }
-  else if (INTEGERP (obj)
-          && XINT (obj) < 0xFFFF
-          && XINT (obj) > -0xFFFF)
+  else if (RANGED_INTEGERP (X_SHRT_MIN, obj, X_SHRT_MAX))
     {
+      *data_ret = (unsigned char *) xmalloc (sizeof (short) + 1);
       *format_ret = 16;
       *size_ret = 1;
-      *data_ret = (unsigned char *) xmalloc (sizeof (short) + 1);
       (*data_ret) [sizeof (short)] = 0;
-      (*(short **) data_ret) [0] = (short) XINT (obj);
+      (*(short **) data_ret) [0] = XINT (obj);
       if (NILP (type)) type = QINTEGER;
     }
   else if (INTEGERP (obj)
@@ -1730,11 +1781,11 @@ lisp_data_to_selection_data (Display *display, Lisp_Object obj,
                   || (CONSP (XCDR (obj))
                       && INTEGERP (XCAR (XCDR (obj)))))))
     {
+      *data_ret = (unsigned char *) xmalloc (sizeof (long) + 1);
       *format_ret = 32;
       *size_ret = 1;
-      *data_ret = (unsigned char *) xmalloc (sizeof (long) + 1);
       (*data_ret) [sizeof (long)] = 0;
-      (*(unsigned long **) data_ret) [0] = cons_to_unsigned (obj, ULONG_MAX);
+      (*(long **) data_ret) [0] = cons_to_signed (obj, X_LONG_MIN, X_LONG_MAX);
       if (NILP (type)) type = QINTEGER;
     }
   else if (VECTORP (obj))
@@ -1743,50 +1794,55 @@ lisp_data_to_selection_data (Display *display, Lisp_Object obj,
         a set of 16 or 32 bit INTEGERs;
         or a set of ATOM_PAIRs (represented as [[A1 A2] [A3 A4] ...]
        */
-      int i;
+      ptrdiff_t i;
+      ptrdiff_t size = ASIZE (obj);
 
       if (SYMBOLP (XVECTOR (obj)->contents [0]))
        /* This vector is an ATOM set */
        {
          if (NILP (type)) type = QATOM;
-         *size_ret = ASIZE (obj);
-         *format_ret = 32;
-         for (i = 0; i < *size_ret; i++)
+         for (i = 0; i < size; i++)
            if (!SYMBOLP (XVECTOR (obj)->contents [i]))
              signal_error ("All elements of selection vector must have same type", obj);
 
-         *data_ret = (unsigned char *) xmalloc ((*size_ret) * sizeof (Atom));
-         for (i = 0; i < *size_ret; i++)
+         *data_ret = xnmalloc (size, sizeof (Atom));
+         *format_ret = 32;
+         *size_ret = size;
+         for (i = 0; i < size; i++)
            (*(Atom **) data_ret) [i]
              = symbol_to_x_atom (dpyinfo, XVECTOR (obj)->contents [i]);
        }
       else
        /* This vector is an INTEGER set, or something like it */
        {
-          int data_size = 2;
-         *size_ret = ASIZE (obj);
+         int format = 16;
+         int data_size = sizeof (short);
          if (NILP (type)) type = QINTEGER;
-         *format_ret = 16;
-         for (i = 0; i < *size_ret; i++)
-           if (CONSP (XVECTOR (obj)->contents [i]))
-             *format_ret = 32;
-           else if (!INTEGERP (XVECTOR (obj)->contents [i]))
-             signal_error (/* Qselection_error */
-    "Elements of selection vector must be integers or conses of integers",
-                           obj);
-
-          /* Use sizeof(long) even if it is more than 32 bits.  See comment
-             in x_get_window_property and x_fill_property_data.  */
-
-          if (*format_ret == 32) data_size = sizeof(long);
-         *data_ret = (unsigned char *) xmalloc (*size_ret * data_size);
-         for (i = 0; i < *size_ret; i++)
-           if (*format_ret == 32)
-             (*((unsigned long **) data_ret)) [i] =
-               cons_to_unsigned (XVECTOR (obj)->contents [i], ULONG_MAX);
-           else
-             (*((unsigned short **) data_ret)) [i] =
-               cons_to_unsigned (XVECTOR (obj)->contents [i], USHRT_MAX);
+         for (i = 0; i < size; i++)
+           {
+             intmax_t v = cons_to_signed (XVECTOR (obj)->contents[i],
+                                          X_LONG_MIN, X_LONG_MAX);
+             if (X_SHRT_MIN <= v && v <= X_SHRT_MAX)
+               {
+                 /* Use sizeof (long) even if it is more than 32 bits.
+                    See comment in x_get_window_property and
+                    x_fill_property_data.  */
+                 data_size = sizeof (long);
+                 format = 32;
+               }
+           }
+         *data_ret = xnmalloc (size, data_size);
+         *format_ret = format;
+         *size_ret = size;
+         for (i = 0; i < size; i++)
+           {
+             long v = cons_to_signed (XVECTOR (obj)->contents[i],
+                                      X_LONG_MIN, X_LONG_MAX);
+             if (format == 32)
+               (*((long **) data_ret)) [i] = v;
+             else
+               (*((short **) data_ret)) [i] = v;
+           }
        }
     }
   else
@@ -1816,8 +1872,8 @@ clean_local_selection_data (Lisp_Object obj)
     }
   if (VECTORP (obj))
     {
-      int i;
-      int size = ASIZE (obj);
+      ptrdiff_t i;
+      ptrdiff_t size = ASIZE (obj);
       Lisp_Object copy;
       if (size == 1)
        return clean_local_selection_data (XVECTOR (obj)->contents [0]);
@@ -2212,6 +2268,8 @@ x_check_property_data (Lisp_Object data)
       else if (CONSP (o) &&
                (! NUMBERP (XCAR (o)) || ! NUMBERP (XCDR (o))))
         return -1;
+      if (size == INT_MAX)
+       return -1;
       size++;
     }
 
@@ -2293,8 +2351,11 @@ Lisp_Object
 x_property_data_to_lisp (struct frame *f, const unsigned char *data,
                         Atom type, int format, long unsigned int size)
 {
+  ptrdiff_t format_bytes = format >> 3;
+  if (PTRDIFF_MAX / format_bytes < size)
+    memory_full (SIZE_MAX);
   return selection_data_to_lisp_data (FRAME_X_DISPLAY (f),
-                                      data, size*format/8, type, format);
+                                     data, size * format_bytes, type, format);
 }
 
 /* Get the mouse position in frame relative coordinates.  */
@@ -2361,7 +2422,7 @@ If the value is 0 or the atom is not known, return the empty string.  */)
   x_uncatch_errors ();
 
   if (!had_errors)
-    ret = make_string (name, strlen (name));
+    ret = build_string (name);
 
   if (atom && name) XFree (name);
   if (NILP (ret)) ret = empty_unibyte_string;
@@ -2380,7 +2441,7 @@ FRAME is on.  If FRAME is nil, the selected frame is used.  */)
 {
   Atom x_atom;
   struct frame *f = check_x_frame (frame);
-  size_t i;
+  ptrdiff_t i;
   struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
 
 
@@ -2400,12 +2461,9 @@ FRAME is on.  If FRAME is nil, the selected frame is used.  */)
       return Qnil;
 
   if (dpyinfo->x_dnd_atoms_length == dpyinfo->x_dnd_atoms_size)
-    {
-      dpyinfo->x_dnd_atoms_size *= 2;
-      dpyinfo->x_dnd_atoms = xrealloc (dpyinfo->x_dnd_atoms,
-                                       sizeof (*dpyinfo->x_dnd_atoms)
-                                       * dpyinfo->x_dnd_atoms_size);
-    }
+    dpyinfo->x_dnd_atoms =
+      xpalloc (dpyinfo->x_dnd_atoms, &dpyinfo->x_dnd_atoms_size,
+              1, -1, sizeof *dpyinfo->x_dnd_atoms);
 
   dpyinfo->x_dnd_atoms[dpyinfo->x_dnd_atoms_length++] = x_atom;
   return Qnil;
@@ -2423,7 +2481,7 @@ x_handle_dnd_message (struct frame *f, XClientMessageEvent *event, struct x_disp
   int x, y;
   unsigned char *data = (unsigned char *) event->data.b;
   int idata[5];
-  size_t i;
+  ptrdiff_t i;
 
   for (i = 0; i < dpyinfo->x_dnd_atoms_length; ++i)
     if (dpyinfo->x_dnd_atoms[i] == event->message_type) break;
@@ -2440,7 +2498,7 @@ x_handle_dnd_message (struct frame *f, XClientMessageEvent *event, struct x_disp
   if (32 < BITS_PER_LONG && event->format == 32)
     {
       for (i = 0; i < 5; ++i) /* There are only 5 longs in a ClientMessage. */
-        idata[i] = (int) event->data.l[i];
+       idata[i] = event->data.l[i];
       data = (unsigned char *) idata;
     }
 
@@ -2679,4 +2737,6 @@ A value of 0 means wait as long as necessary.  This is initialized from the
   DEFSYM (QNULL, "NULL");
   DEFSYM (Qcompound_text_with_extensions, "compound-text-with-extensions");
   DEFSYM (Qforeign_selection, "foreign-selection");
+  DEFSYM (Qx_lost_selection_functions, "x-lost-selection-functions");
+  DEFSYM (Qx_sent_selection_functions, "x-sent-selection-functions");
 }