From cd18d88b83a6801bd7631e646fa9e30a2eaf5783 Mon Sep 17 00:00:00 2001 From: overflowerror Date: Sat, 18 May 2024 18:00:13 +0200 Subject: [PATCH] fix: wrong buffer resize in strbuf replace --- common/src/strbuf.c | 8 +++++--- common/src/tests.c | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/common/src/strbuf.c b/common/src/strbuf.c index 8710179..bc28a28 100644 --- a/common/src/strbuf.c +++ b/common/src/strbuf.c @@ -27,12 +27,14 @@ strbuf_t _strbuf_replace(strbuf_t buffer, char* needle, char* replace) { if (replace_length == needle_length) { memcpy(result, replace, replace_length); } else if (replace_length > needle_length) { - list_ensure_space(buffer, 1, replace_length - needle_length); - memmove(result + replace_length, result + needle_length, strlen(buffer) - offset - needle_length + 1); - memcpy(result, replace, replace_length); + buffer = list_ensure_space(buffer, 1, replace_length - needle_length); + memmove(buffer + offset + replace_length, buffer + offset + needle_length, strlen(buffer) - offset - needle_length + 1); + memcpy(buffer + offset, replace, replace_length); + list_header(buffer)->length += (replace_length - needle_length); } else { memcpy(result, replace, replace_length); memmove(result + replace_length, result + needle_length, strlen(buffer) - offset - needle_length + 1); + list_header(buffer)->length -= (needle_length - replace_length); } } diff --git a/common/src/tests.c b/common/src/tests.c index 64c750a..cea5d6b 100644 --- a/common/src/tests.c +++ b/common/src/tests.c @@ -100,7 +100,7 @@ void test_strbuf_replace_shorter_length(void) { assert_streq("hello ba world ba !", buffer, "buffer doesn't match"); printf("%lu, %zu\n", strlen(buffer), list_size(buffer)); - assert_equals(strlen(buffer) + 1 + 2, list_size(buffer), "allocation doesn't match"); + assert_equals(strlen(buffer) + 1, list_size(buffer), "allocation doesn't match"); strbuf_free(buffer); } @@ -113,7 +113,20 @@ void test_strbuf_replace_greater_length(void) { assert_streq("hello barr world barr !", buffer, "buffer doesn't match"); printf("%lu, %zu\n", strlen(buffer), list_size(buffer)); - assert_equals(strlen(buffer) - 1, list_size(buffer), "allocation doesn't match"); + assert_equals(strlen(buffer) + 1, list_size(buffer), "allocation doesn't match"); + + strbuf_free(buffer); +} + +void test_strbuf_replace_bug_realloc_moves(void) { + strbuf_t buffer = strbuf_new(); + strbuf_append(buffer, "hello foo world foo !"); + + strbuf_replace(buffer, "foo", "a very long string that will cause the region to be too small"); + + assert_streq("hello a very long string that will cause the region to be too small world a very long string that will cause the region to be too small !", buffer, "buffer doesn't match"); + printf("%lu, %zu\n", strlen(buffer), list_size(buffer)); + assert_equals(strlen(buffer) + 1, list_size(buffer), "allocation doesn't match"); strbuf_free(buffer); } @@ -130,6 +143,7 @@ int main(void) { test_run(test_strbuf_replace_equal_length); test_run(test_strbuf_replace_shorter_length); test_run(test_strbuf_replace_greater_length); + test_run(test_strbuf_replace_bug_realloc_moves); if (test_results()) { return 0;