fix critical memory overflow in the stack-based array reallocator

Thu, 22 May 2025 16:23:55 +0200

author
Mike Becker <universe@uap-core.de>
date
Thu, 22 May 2025 16:23:55 +0200
changeset 1322
7be10b57f658
parent 1321
1003c014bf92
child 1323
deccdb82f24e

fix critical memory overflow in the stack-based array reallocator

CHANGELOG file | annotate | diff | comparison | revisions
docs/Writerside/topics/about.md file | annotate | diff | comparison | revisions
docs/Writerside/topics/array_list.h.md file | annotate | diff | comparison | revisions
src/array_list.c file | annotate | diff | comparison | revisions
src/cx/array_list.h file | annotate | diff | comparison | revisions
--- a/CHANGELOG	Thu May 22 16:03:20 2025 +0200
+++ b/CHANGELOG	Thu May 22 16:23:55 2025 +0200
@@ -19,6 +19,7 @@
  * changes the implementation of cx_strreplacen() for improved efficiency
  * changes all cxListIterator() without index to also accept NULL as list argument
  * changes insert_element member function of CxList to accept NULL source and return a pointer to the inserted element
+ * fixes critical memory overflow in the stack-based array reallocator (this unfortunately breaks the function signature)
  * fixes that starting an iteration in a non-root node incorrectly continues iteration with the siblings of that node
  * fixes unnecessary allocations in cx_strcat() family of functions
  * fixes errno value after failing cxBufferSeek() to be consistently EINVAL
--- a/docs/Writerside/topics/about.md	Thu May 22 16:03:20 2025 +0200
+++ b/docs/Writerside/topics/about.md	Thu May 22 16:23:55 2025 +0200
@@ -46,6 +46,7 @@
 * changes the implementation of cx_strreplacen() for improved efficiency
 * changes all cxListIterator() without index to also accept NULL as list argument
 * changes insert_element member function of CxList to accept NULL source and return a pointer to the inserted element
+* fixes critical memory overflow in the stack-based array reallocator (this unfortunately breaks the function signature)
 * fixes that starting an iteration in a non-root node incorrectly continues iteration with the siblings of that node
 * fixes unnecessary allocations in cx_strcat() family of functions
 * fixes errno value after failing cxBufferSeek() to be consistently EINVAL
--- a/docs/Writerside/topics/array_list.h.md	Thu May 22 16:03:20 2025 +0200
+++ b/docs/Writerside/topics/array_list.h.md	Thu May 22 16:23:55 2025 +0200
@@ -93,8 +93,9 @@
 #include <cx/array_list.h>
 
 typedef struct {
-    void *(*realloc)(void *array, size_t capacity, size_t elem_size,
-            CxArrayReallocator *alloc);
+    void *(*realloc)(void *array,
+            size_t old_capacity, size_t new_capacity,
+            size_t elem_size, CxArrayReallocator *alloc);
     void *ptr1;
     void *ptr2;
     size_t int1;
--- a/src/array_list.c	Thu May 22 16:03:20 2025 +0200
+++ b/src/array_list.c	Thu May 22 16:23:55 2025 +0200
@@ -36,12 +36,13 @@
 
 static void *cx_array_default_realloc(
         void *array,
-        size_t capacity,
+        cx_attr_unused size_t old_capacity,
+        size_t new_capacity,
         size_t elem_size,
         cx_attr_unused CxArrayReallocator *alloc
 ) {
     size_t n;
-    if (cx_szmul(capacity, elem_size, &n)) {
+    if (cx_szmul(new_capacity, elem_size, &n)) {
         errno = EOVERFLOW;
         return NULL;
     }
@@ -58,13 +59,14 @@
 
 static void *cx_array_advanced_realloc(
         void *array,
-        size_t capacity,
+        size_t old_capacity,
+        size_t new_capacity,
         size_t elem_size,
         cx_attr_unused CxArrayReallocator *alloc
 ) {
     // check for overflow
     size_t n;
-    if (cx_szmul(capacity, elem_size, &n)) {
+    if (cx_szmul(new_capacity, elem_size, &n)) {
         errno = EOVERFLOW;
         return NULL;
     }
@@ -77,7 +79,7 @@
     if (array == alloc->ptr2) {
         newmem = cxMalloc(al, n);
         if (newmem != NULL && array != NULL) {
-            memcpy(newmem, array, n);
+            memcpy(newmem, array, old_capacity*elem_size);
         }
     } else {
         newmem = cxRealloc(al, array, n);
@@ -180,7 +182,7 @@
 
         // perform reallocation
         void *newmem = reallocator->realloc(
-                *array, newcap, elem_size, reallocator
+                *array, oldcap, newcap, elem_size, reallocator
         );
         if (newmem == NULL) {
             return 1; // LCOV_EXCL_LINE
@@ -286,7 +288,7 @@
 
         // perform reallocation
         void *newmem = reallocator->realloc(
-                *target, newcap, elem_size, reallocator
+                *target, oldcap, newcap, elem_size, reallocator
         );
         if (newmem == NULL) {
             return 1;
@@ -366,13 +368,14 @@
 
     // store some counts
     size_t old_size = *size;
+    size_t old_capacity = *capacity;
     size_t needed_capacity = old_size + elem_count;
 
     // if we need more than we have, try a reallocation
-    if (needed_capacity > *capacity) {
+    if (needed_capacity > old_capacity) {
         size_t new_capacity = cx_array_align_capacity(needed_capacity, 16, SIZE_MAX);
         void *new_mem = reallocator->realloc(
-                *target, new_capacity, elem_size, reallocator
+                *target, old_capacity, new_capacity, elem_size, reallocator
         );
         if (new_mem == NULL) {
             // give it up right away, there is no contract
--- a/src/cx/array_list.h	Thu May 22 16:03:20 2025 +0200
+++ b/src/cx/array_list.h	Thu May 22 16:23:55 2025 +0200
@@ -178,17 +178,19 @@
      * or to transport other additional data.
      *
      * @param array the array to reallocate
-     * @param capacity the new capacity (number of elements)
+     * @param old_capacity the old number of elements
+     * @param new_capacity the new number of elements
      * @param elem_size the size of each element
      * @param alloc a reference to this allocator
      * @return a pointer to the reallocated memory or @c NULL on failure
      */
     cx_attr_nodiscard
-    cx_attr_nonnull_arg(4)
-    cx_attr_allocsize(2, 3)
+    cx_attr_nonnull_arg(5)
+    cx_attr_allocsize(3, 4)
     void *(*realloc)(
             void *array,
-            size_t capacity,
+            size_t old_capacity,
+            size_t new_capacity,
             size_t elem_size,
             struct cx_array_reallocator_s *alloc
     );

mercurial