mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-06-14 12:31:25 +00:00
Be more careful about X selection sizes
* src/xselect.c (selection_data_for_offset): Offset is size_t, not long, since that’s what caller passes. (selection_data_size): Truncate large selection sizes to a value that is more likely to work without involving undefined behavior. Do not exceed X_ULONG_MAX which is all X can handle, or PTRDIFF_MAX which can confuse underlying code. (x_start_selection_transfer): Invoke selection_data_size just once.
This commit is contained in:
parent
1bee33c1c8
commit
fbd2f781b2
1 changed files with 18 additions and 11 deletions
|
|
@ -712,7 +712,7 @@ x_size_for_format (int format)
|
|||
|
||||
static unsigned char *
|
||||
selection_data_for_offset (struct selection_data *data,
|
||||
long offset, size_t *remaining)
|
||||
size_t offset, size_t *remaining)
|
||||
{
|
||||
unsigned char *base;
|
||||
size_t size;
|
||||
|
|
@ -741,12 +741,17 @@ selection_data_for_offset (struct selection_data *data,
|
|||
|
||||
/* Return the size, in bytes transferred to the X server, of
|
||||
data->size items of selection data in data->format-bit
|
||||
quantities. */
|
||||
quantities. If this size is too large, silently return
|
||||
the largest supported size in bytes for this format.
|
||||
|
||||
FIXME: Silent truncation is bad. */
|
||||
|
||||
static size_t
|
||||
selection_data_size (struct selection_data *data)
|
||||
{
|
||||
size_t scratch;
|
||||
ptrdiff_t max_selection_size = min (min (PTRDIFF_MAX, SIZE_MAX),
|
||||
X_ULONG_MAX);
|
||||
|
||||
if (!NILP (data->string))
|
||||
return SBYTES (data->string);
|
||||
|
|
@ -754,17 +759,19 @@ selection_data_size (struct selection_data *data)
|
|||
switch (data->format)
|
||||
{
|
||||
case 8:
|
||||
return (size_t) data->size;
|
||||
return min (data->size, max_selection_size);
|
||||
|
||||
case 16:
|
||||
if (ckd_mul (&scratch, data->size, 2))
|
||||
return SIZE_MAX;
|
||||
if (ckd_mul (&scratch, data->size, 2)
|
||||
|| max_selection_size - max_selection_size % 2 < scratch)
|
||||
return max_selection_size - max_selection_size % 2;
|
||||
|
||||
return scratch;
|
||||
|
||||
case 32:
|
||||
if (ckd_mul (&scratch, data->size, 4))
|
||||
return SIZE_MAX;
|
||||
if (ckd_mul (&scratch, data->size, 4)
|
||||
|| max_selection_size - max_selection_size % 4 < scratch)
|
||||
return max_selection_size - max_selection_size % 4;
|
||||
|
||||
return scratch;
|
||||
}
|
||||
|
|
@ -885,12 +892,12 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor,
|
|||
|
||||
max_size = selection_quantum (dpyinfo->display);
|
||||
|
||||
size_t seldata_size = selection_data_size (&transfer->data);
|
||||
TRACE3 (" x_start_selection_transfer: transferring to 0x%lx. "
|
||||
"transfer consists of %zu bytes, quantum being %zu",
|
||||
requestor, selection_data_size (&transfer->data),
|
||||
max_size);
|
||||
requestor, seldata_size, max_size);
|
||||
|
||||
if (selection_data_size (&transfer->data) > max_size)
|
||||
if (max_size < seldata_size)
|
||||
{
|
||||
/* Begin incremental selection transfer. First, calculate how
|
||||
many elements it is ok to write for every ChangeProperty
|
||||
|
|
@ -918,7 +925,7 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor,
|
|||
/* Now, write the INCR property to begin incremental selection
|
||||
transfer. offset is currently 0. */
|
||||
|
||||
data_size = selection_data_size (&transfer->data);
|
||||
data_size = seldata_size;
|
||||
|
||||
/* Set SELECTED_EVENTS before the actual XSelectInput
|
||||
request. */
|
||||
|
|
|
|||
Loading…
Reference in a new issue