diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2024-10-18 10:14:50 -0700 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2024-10-18 10:14:50 -0700 |
commit | 3d158182ef29d19e61f1271380d54e49bf16de05 (patch) | |
tree | 211ad287f513895c6932d4264e2ab4614c0e796a | |
parent | 069d910388502aa5d374c78bd7dfb54af09d38ec (diff) |
vcr: clip vcr_shift_below_row_up_one() for mem backend
There was an unintentional assumption that hierarchy_end wouldn't
extend beyond the bottom, which just isn't always the case.
I'm sure there's more of this kind of thing in the headless code
since the original Xlib backend could lean on XRender clipping
everything.
-rw-r--r-- | src/vcr.c | 21 |
1 files changed, 17 insertions, 4 deletions
@@ -1347,10 +1347,7 @@ void vcr_clear_row(vcr_t *vcr, vcr_layer_t layer, int row, int x, int width) } -/* copy what's below a given row up the specified amount across all the layers */ -/* XXX: note for now we expect (and assert) rows == 1, to simplify TYPE_MEM, - * this is acceptable for all existing call sites - */ +/* copy what's below a given row up by one row across all the layers */ void vcr_shift_below_row_up_one(vcr_t *vcr, int row) { assert(vcr); @@ -1391,6 +1388,22 @@ void vcr_shift_below_row_up_one(vcr_t *vcr, int row) uint8_t *src = &vcr->mem.bits[(1 + row) * VCR_ROW_HEIGHT * vcr->mem.pitch]; size_t len = ((1 + *(vcr->hierarchy_end_ptr)) - (1 + row)) * VCR_ROW_HEIGHT * vcr->mem.pitch; + assert(*(vcr->hierarchy_end_ptr) >= row); + + /* (hierarchy_end * VCR_ROW_HEIGHT) may overflow vcr->height, as it's not kept clipped. + * It more represents where the process hierarchy virtually ends - which may or may not stay within + * the chart's allocated area. So len must be clamped here to ensure we're not attempting + * to copy out of bounds. + */ + len = MIN(len, &vcr->mem.bits[vcr->height * vcr->mem.pitch] - src); + + assert(src + len <= vcr->mem.bits + vcr->mem.pitch * vcr->height); + assert(dest + len <= vcr->mem.bits + vcr->mem.pitch * vcr->height); + + /* XXX the xlib backend enjoys some luxuries in dealing with clipping that must be dealt with manually here, + * and that just hasn't been entirely fleshed out beyond "do enough to at least not segfault" + */ + memmove(dest, src, len); break; } |