grid: reload pointers into the uri range vector after inserting

Inserting elements into the URI range vector typically triggers a
vector resize. This is done using realloc(). Sometimes this causes the
vector to move, thus invalidating all existing pointers into the
vector.
This commit is contained in:
Daniel Eklöf 2021-12-08 17:41:29 +01:00
parent de0898821e
commit 2e8c9c2fe5
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
2 changed files with 41 additions and 2 deletions

View file

@ -55,6 +55,7 @@
* Crash when bitmap fonts are scaled down to very small font sizes * Crash when bitmap fonts are scaled down to very small font sizes
(https://codeberg.org/dnkl/foot/issues/830). (https://codeberg.org/dnkl/foot/issues/830).
* Crash when overwriting/erasing an OSC-8 URL.
### Security ### Security

42
grid.c
View file

@ -69,10 +69,10 @@ verify_uris_are_sorted(const struct row_data *extra)
} }
static void static void
uri_range_ensure_size(struct row_data *extra, size_t count_to_add) uri_range_ensure_size(struct row_data *extra, uint32_t count_to_add)
{ {
if (extra->uri_ranges.count + count_to_add > extra->uri_ranges.size) { if (extra->uri_ranges.count + count_to_add > extra->uri_ranges.size) {
extra->uri_ranges.size += count_to_add + count_to_add; extra->uri_ranges.size = extra->uri_ranges.count + count_to_add;
extra->uri_ranges.v = xrealloc( extra->uri_ranges.v = xrealloc(
extra->uri_ranges.v, extra->uri_ranges.v,
extra->uri_ranges.size * sizeof(extra->uri_ranges.v[0])); extra->uri_ranges.size * sizeof(extra->uri_ranges.v[0]));
@ -81,6 +81,10 @@ uri_range_ensure_size(struct row_data *extra, size_t count_to_add)
xassert(extra->uri_ranges.count + count_to_add <= extra->uri_ranges.size); xassert(extra->uri_ranges.count + count_to_add <= extra->uri_ranges.size);
} }
/*
* Be careful! This function may xrealloc() the URI range vector, thus
* invalidating pointers into it.
*/
static void static void
uri_range_insert(struct row_data *extra, size_t idx, int start, int end, uri_range_insert(struct row_data *extra, size_t idx, int start, int end,
uint64_t id, const char *uri) uint64_t id, const char *uri)
@ -1028,6 +1032,9 @@ grid_row_uri_range_put(struct row *row, int col, const char *uri, uint64_t id)
uri_range_insert(extra, i + 1, col + 1, r->end, r->id, r->uri); uri_range_insert(extra, i + 1, col + 1, r->end, r->id, r->uri);
/* The insertion may xrealloc() the vector, making our
* old pointer invalid */
r = &extra->uri_ranges.v[i];
r->end = col - 1; r->end = col - 1;
xassert(r->start <= r->end); xassert(r->start <= r->end);
@ -1161,6 +1168,10 @@ grid_row_uri_range_erase(struct row *row, int start, int end)
/* Erase range erases a part in the middle of the URI */ /* Erase range erases a part in the middle of the URI */
uri_range_insert( uri_range_insert(
extra, i + 1, end + 1, old->end, old->id, old->uri); extra, i + 1, end + 1, old->end, old->id, old->uri);
/* The insertion may xrealloc() the vector, making our
* old pointer invalid */
old = &extra->uri_ranges.v[i];
old->end = start - 1; old->end = start - 1;
return; /* There can be no more URIs affected by the erase range */ return; /* There can be no more URIs affected by the erase range */
} }
@ -1231,6 +1242,33 @@ UNITTEST
verify_no_overlapping_uris(&row_data); verify_no_overlapping_uris(&row_data);
verify_uris_are_sorted(&row_data); verify_uris_are_sorted(&row_data);
grid_row_uri_range_destroy(&row_data.uri_ranges.v[0]);
grid_row_uri_range_destroy(&row_data.uri_ranges.v[1]);
row_data.uri_ranges.count = 0;
/*
* Regression test: erasing the middle part of an URI causes us to
* insert a new URI (we split the partly erased URI into two).
*
* The insertion logic typically triggers an xrealloc(), which, in
* some cases, *moves* the entire URI vector to a new base
* address. grid_row_uri_range_erase() did not account for this,
* and tried to update the end member in the URI range we just
* split. This causes foot to crash when the xrealloc() has moved
* the URI range vector.
*
* (note: were only verifying we dont crash here, hence the lack
* of assertions).
*/
free(row_data.uri_ranges.v);
row_data.uri_ranges.v = NULL;
row_data.uri_ranges.size = 0;
uri_range_append(&row_data, 1, 10, 0, "dummy");
xassert(row_data.uri_ranges.size == 1);
grid_row_uri_range_erase(&row, 5, 7);
xassert(row_data.uri_ranges.count == 2);
for (size_t i = 0; i < row_data.uri_ranges.count; i++) for (size_t i = 0; i < row_data.uri_ranges.count; i++)
grid_row_uri_range_destroy(&row_data.uri_ranges.v[i]); grid_row_uri_range_destroy(&row_data.uri_ranges.v[i]);
free(row_data.uri_ranges.v); free(row_data.uri_ranges.v);