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. */
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
+
+/* Maximum unsigned 'short' and 'long' values suitable for libX11. */
+#define X_USHRT_MAX 0xffff
+#define X_ULONG_MAX 0xffffffff
+
/* 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.
+
+ 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)))))
-#define SELECTION_QUANTUM(dpy) ((XMaxRequestSize(dpy) << 2) - 100)
+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)
struct selection_data
{
unsigned char *data;
- unsigned int size;
+ ptrdiff_t size;
int format;
Atom type;
int nofree;
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;
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);
else
{
/* Send an INCR tag to initiate incremental transfer. */
- long value[1];
+ unsigned 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,
/* XChangeProperty expects an array of long even if long is
more than 32 bits. */
- value[0] = bytes_remaining;
+ value[0] = min (bytes_remaining, X_ULONG_MAX);
XChangeProperty (display, window, cs->property,
dpyinfo->Xatom_INCR, 32, PropModeReplace,
(unsigned char *) value, 1);
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. */
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
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;
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
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. */
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.
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);
&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 */
{
XFlush (display);
UNBLOCK_INPUT;
- if (*size_bytes_ret < offset + tmp_size_bytes)
+ 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);
+ ptrdiff_t size;
+ if (min (PTRDIFF_MAX, SIZE_MAX) - offset < tmp_size_bytes)
+ {
+ xfree (tmp_data);
+ memory_full (SIZE_MAX);
+ }
+ size = offset + tmp_size_bytes;
+ *data_ret = (unsigned char *) xrealloc (*data_ret, size);
+ *size_bytes_ret = size;
}
memcpy ((*data_ret) + offset, tmp_data, tmp_size_bytes);
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);
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);
/* 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
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));
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;
}
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 (0, obj, X_USHRT_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);
+ (*(unsigned short **) data_ret) [0] = XINT (obj);
if (NILP (type)) type = QINTEGER;
}
else if (INTEGERP (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);
+ (*(unsigned long **) data_ret) [0] = cons_to_unsigned (obj, X_ULONG_MAX);
if (NILP (type)) type = QINTEGER;
}
else if (VECTORP (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 (min (PTRDIFF_MAX, SIZE_MAX) / sizeof (Atom) < size)
+ memory_full (SIZE_MAX);
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 = (unsigned char *) xmalloc (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 format = 16;
int data_size = 2;
- *size_ret = ASIZE (obj);
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)
+ for (i = 0; i < size; i++)
+ if (X_USHRT_MAX
+ < cons_to_unsigned (XVECTOR (obj)->contents[i], X_ULONG_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;
+ }
+ if (min (PTRDIFF_MAX, SIZE_MAX) / data_size < size)
+ memory_full (SIZE_MAX);
+ *data_ret = (unsigned char *) xmalloc (size * data_size);
+ *format_ret = format;
+ *size_ret = size;
+ for (i = 0; i < size; i++)
+ if (format == 32)
(*((unsigned long **) data_ret)) [i] =
- cons_to_unsigned (XVECTOR (obj)->contents [i], ULONG_MAX);
+ cons_to_unsigned (XVECTOR (obj)->contents[i], X_ULONG_MAX);
else
(*((unsigned short **) data_ret)) [i] =
- cons_to_unsigned (XVECTOR (obj)->contents [i], USHRT_MAX);
+ cons_to_unsigned (XVECTOR (obj)->contents[i], X_USHRT_MAX);
}
}
else
}
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]);
else if (CONSP (o) &&
(! NUMBERP (XCAR (o)) || ! NUMBERP (XCDR (o))))
return -1;
+ if (size == INT_MAX)
+ return -1;
size++;
}
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. */
if (min (PTRDIFF_MAX, SIZE_MAX) / sizeof *dpyinfo->x_dnd_atoms / 2
< dpyinfo->x_dnd_atoms_size)
memory_full (SIZE_MAX);
- 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);
+ (2 * sizeof *dpyinfo->x_dnd_atoms
+ * dpyinfo->x_dnd_atoms_size));
+ dpyinfo->x_dnd_atoms_size *= 2;
}
dpyinfo->x_dnd_atoms[dpyinfo->x_dnd_atoms_length++] = x_atom;
unsigned long size = 160/event->format;
int x, y;
unsigned char *data = (unsigned char *) event->data.b;
- int idata[5];
+ unsigned int idata[5];
ptrdiff_t i;
for (i = 0; i < dpyinfo->x_dnd_atoms_length; ++i)
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;
}