sixel: fix crash when splitting up an image across the scrollback

If an image was split up across the scrollback, and the first image
chunk was resized due to it being blended with an already existing
sixel, we crashed.

The reason being the second chunk, emitted *after* the scrollback,
tried to memcpy() image data from a now-free:d image buffer.

The fix is pretty simple: create copies for *all* chunks when an image
has to be split up across the scrollback. Previously, the first chunk
re-used the source image buffer.

Closes #608
This commit is contained in:
Daniel Eklöf 2021-06-24 17:08:33 +02:00
parent ba26d63829
commit a52d867947
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F

22
sixel.c
View file

@ -964,16 +964,7 @@ sixel_unhook(struct terminal *term)
(term->sixel.image.height + term->cell_height - 1) / term->cell_height +
(term->sixel.cursor_right_of_graphics ? 0 : 1);
/* Will we be emitting anything at all? */
const bool no_emission =
rows_needed > term->grid->num_rows ||
pixel_rows_left == 0 ||
rows_avail == 0;
if (no_emission) {
/* We wont be emitting any sixels - free backing image */
free(term->sixel.image.data);
}
bool free_image_data = true;
/* We do not allow sixels to cross the scrollback wrap-around, as
* this makes intersection calculations much more complicated */
@ -991,9 +982,13 @@ sixel_unhook(struct terminal *term)
const int height = min(pixel_rows_left, pixel_rows_avail);
uint32_t *img_data;
if (pixel_row_idx == 0)
if (pixel_row_idx == 0 && height == pixel_rows_left) {
/* Entire image will be emitted as a single chunk - reuse
* the source buffer */
img_data = term->sixel.image.data;
else {
free_image_data = false;
} else {
xassert(free_image_data);
img_data = xmalloc(height * stride);
memcpy(
img_data,
@ -1080,6 +1075,9 @@ sixel_unhook(struct terminal *term)
start_row -= image.rows;
}
if (free_image_data)
free(term->sixel.image.data);
term->sixel.image.data = NULL;
term->sixel.image.width = 0;
term->sixel.image.height = 0;