diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-15 11:31:50 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-15 11:31:50 +0300 |
| commit | acd338ea33de36d223cc6d301712eed4a9501e6c (patch) | |
| tree | d93c46a97e2ed4e8a86e3402de5f847cdc144ec8 /tests/snapshot_failure_test.c | |
| parent | f97c3a585e2efc1d0a4bc10e6ac04b96ee6428ea (diff) | |
Fix snapshot storage and allocation failure correctness
Account for cluster records discarded by snapshot scrolling, propagate snapshot allocation failures with an empty retryable view, and allocate resized screens before mutating visible state. Add bounded-memory and allocation-failure regressions, and update the saved diagnostic and audit report.
Diffstat (limited to 'tests/snapshot_failure_test.c')
| -rw-r--r-- | tests/snapshot_failure_test.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/tests/snapshot_failure_test.c b/tests/snapshot_failure_test.c new file mode 100644 index 0000000..4133bfd --- /dev/null +++ b/tests/snapshot_failure_test.c @@ -0,0 +1,91 @@ +#include "term/term.h" + +#include <assert.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> + +static bool fail_next_realloc; +static int malloc_failure_countdown = -1; +static bool malloc_was_failed; +void *__real_malloc(size_t); +void *__wrap_malloc(size_t size) +{ + if (malloc_failure_countdown >= 0) { + if (malloc_failure_countdown-- == 0) { + malloc_failure_countdown = -1; + malloc_was_failed = true; + return NULL; + } + } + return __real_malloc(size); +} + +void *__real_realloc(void *, size_t); +void *__wrap_realloc(void *p, size_t size) +{ + if (fail_next_realloc) { + fail_next_realloc = false; + return NULL; + } + return __real_realloc(p, size); +} + +int main(void) +{ + struct term_options options = { .size = { 8, 3 }, .scrollback = 5 }; + struct term *term = term_new(&options); + struct term_snapshot *snapshot = term_snapshot_new(); + assert(term && snapshot && term_snapshot_update(snapshot, term)); + + const char accented[] = "e\xcc\x81"; + term_feed(term, accented, sizeof(accented) - 1, 0); + fail_next_realloc = true; + assert(!term_snapshot_update(snapshot, term)); + assert(!fail_next_realloc); + assert(term_snapshot_view(snapshot)->size.x == 0); + assert(term_snapshot_view(snapshot)->size.y == 0); + assert(term_snapshot_row(snapshot, 0) == NULL); + + assert(term_snapshot_update(snapshot, term)); + const struct term_cell *row = term_snapshot_row(snapshot, 0); + assert(row); + uint32_t cps[4]; + assert(term_snapshot_cluster(snapshot, row[0].text, cps, 4) == 2); + assert(cps[0] == 'e' && cps[1] == 0x301); + + term_snapshot_free(snapshot); + term_free(term); + + /* More than 256 rows moves both temporary arrays off the stack. */ + options.size.y = 300; + term = term_new(&options); + snapshot = term_snapshot_new(); + assert(term && snapshot && term_snapshot_update(snapshot, term)); + + /* Fail new_keys allocation, then make sure retry fills all rows. */ + malloc_was_failed = false; + malloc_failure_countdown = 0; + assert(!term_snapshot_update(snapshot, term)); + assert(malloc_was_failed); + assert(term_snapshot_view(snapshot)->size.y == 0); + assert(term_snapshot_row(snapshot, 0) == NULL); + assert(term_snapshot_update(snapshot, term)); + assert(term_snapshot_view(snapshot)->size.y == 300); + assert(term_snapshot_row(snapshot, 299)); + + /* The first malloc is new_keys; fail the following selection-span array. */ + malloc_was_failed = false; + malloc_failure_countdown = 1; + assert(!term_snapshot_update(snapshot, term)); + assert(malloc_was_failed); + assert(term_snapshot_view(snapshot)->size.y == 0); + assert(term_snapshot_row(snapshot, 0) == NULL); + assert(term_snapshot_update(snapshot, term)); + assert(term_snapshot_view(snapshot)->size.y == 300); + assert(term_snapshot_row(snapshot, 299)); + + term_snapshot_free(snapshot); + term_free(term); + return 0; +} |
