From 5f7e7dad20a0b2269641bc71cca22c925bab698e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Sat, 5 Apr 2025 15:53:19 +0200 Subject: [PATCH] Abort on C23 UB zero sized realloc --- h_malloc.c | 5 +++++ test/.gitignore | 1 + test/Makefile | 3 ++- test/realloc_c23_undefined_behaviour.c | 16 ++++++++++++++++ test/test_smc.py | 6 ++++++ 5 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 test/realloc_c23_undefined_behaviour.c diff --git a/h_malloc.c b/h_malloc.c index 6221d0b..91be2c7 100644 --- a/h_malloc.c +++ b/h_malloc.c @@ -1513,6 +1513,11 @@ EXPORT void *h_calloc(size_t nmemb, size_t size) { } EXPORT void *h_realloc(void *old, size_t size) { + // deprecated in C17, UB since C23 + if (unlikely(old != NULL && size == 0)) { + fatal_error("invalid zero sized realloc"); + } + size = adjust_size_for_canary(size); if (old == NULL) { return alloc(size); diff --git a/test/.gitignore b/test/.gitignore index d37a6a7..edcb7a9 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -41,4 +41,5 @@ overflow_small_8_byte uninitialized_read_large uninitialized_read_small realloc_init +realloc_c23_undefined_behaviour __pycache__/ diff --git a/test/Makefile b/test/Makefile index 0eb3921..8b08059 100644 --- a/test/Makefile +++ b/test/Makefile @@ -67,7 +67,8 @@ EXECUTABLES := \ invalid_malloc_object_size_small \ invalid_malloc_object_size_small_quarantine \ impossibly_large_malloc \ - realloc_init + realloc_init \ + realloc_c23_undefined_behaviour all: $(EXECUTABLES) diff --git a/test/realloc_c23_undefined_behaviour.c b/test/realloc_c23_undefined_behaviour.c new file mode 100644 index 0000000..0c45be0 --- /dev/null +++ b/test/realloc_c23_undefined_behaviour.c @@ -0,0 +1,16 @@ +#include + +#include "test_util.h" + +OPTNONE int main(void) { + void *p, *q; + + p = malloc(16); + if (!p) { + return -1; + } + + q = realloc(p, 0); + + return 0; +} diff --git a/test/test_smc.py b/test/test_smc.py index 170278e..d571b82 100644 --- a/test/test_smc.py +++ b/test/test_smc.py @@ -169,6 +169,12 @@ class TestSimpleMemoryCorruption(unittest.TestCase): self.assertEqual(stderr.decode("utf-8"), "fatal allocator error: invalid realloc\n") + def test_realloc_c23_undefined_behaviour(self): + _stdout, stderr, returncode = self.run_test("realloc_c23_undefined_behaviour") + self.assertEqual(returncode, -6) + self.assertEqual(stderr.decode("utf-8"), + "fatal allocator error: invalid zero sized realloc\n") + def test_write_after_free_large_reuse(self): _stdout, _stderr, returncode = self.run_test( "write_after_free_large_reuse")