avoid recursion in cxBufferWrite() - fixes #567

Wed, 22 Jan 2025 20:36:10 +0100

author
Mike Becker <universe@uap-core.de>
date
Wed, 22 Jan 2025 20:36:10 +0100
changeset 1138
29672c777a28
parent 1137
61939929030a
child 1139
7dfa5bcf39ee

avoid recursion in cxBufferWrite() - fixes #567

src/buffer.c file | annotate | diff | comparison | revisions
--- a/src/buffer.c	Mon Jan 20 22:50:24 2025 +0100
+++ b/src/buffer.c	Wed Jan 22 20:36:10 2025 +0100
@@ -268,17 +268,18 @@
         return nitems;
     }
 
-    size_t len;
+    size_t len, total_flushed = 0;
+cx_buffer_write_retry:
     if (cx_szmul(size, nitems, &len)) {
         errno = EOVERFLOW;
-        return 0;
+        return total_flushed;
     }
     if (buffer->pos > SIZE_MAX - len) {
         errno = EOVERFLOW;
-        return 0;
+        return total_flushed;
     }
+
     size_t required = buffer->pos + len;
-
     bool perform_flush = false;
     if (required > buffer->capacity) {
         if (buffer->flags & CX_BUFFER_AUTO_EXTEND) {
@@ -286,7 +287,7 @@
                 perform_flush = true;
             } else {
                 if (cxBufferMinimumCapacity(buffer, required)) {
-                    return 0; // LCOV_EXCL_LINE
+                    return total_flushed; // LCOV_EXCL_LINE
                 }
             }
         } else {
@@ -305,7 +306,7 @@
 
     // check here and not above because of possible truncation
     if (len == 0) {
-        return 0;
+        return total_flushed;
     }
 
     // check if we need to copy
@@ -313,27 +314,26 @@
 
     // perform the operation
     if (perform_flush) {
-        size_t items_flush;
+        size_t items_flushed;
         if (buffer->pos == 0) {
             // if we don't have data in the buffer, but are instructed
             // to flush, it means that we are supposed to relay the data
-            items_flush = cx_buffer_flush_helper(buffer, ptr, size, nitems);
-            if (items_flush == 0) {
+            items_flushed = cx_buffer_flush_helper(buffer, ptr, size, nitems);
+            if (items_flushed == 0) {
                 // we needed to relay data, but could not flush anything
                 // i.e. we have to give up to avoid endless trying
                 return 0;
             }
-            size_t ritems = nitems - items_flush;
-            if (ritems > 0) {
-                const unsigned char *rest = ptr;
-                rest += items_flush * size;
-                return items_flush + cxBufferWrite(rest, size, ritems, buffer);
-            } else {
-                return items_flush;
+            nitems -= items_flushed;
+            total_flushed += items_flushed;
+            if (nitems > 0) {
+                ptr = ((unsigned char*)ptr) + items_flushed * size;
+                goto cx_buffer_write_retry;
             }
+            return total_flushed;
         } else {
-            items_flush = cx_buffer_flush_impl(buffer, size);
-            if (items_flush == 0) {
+            items_flushed = cx_buffer_flush_impl(buffer, size);
+            if (items_flushed == 0) {
                 // flush target is full, let's try to truncate
                 size_t remaining_space;
                 if (buffer->flags & CX_BUFFER_AUTO_EXTEND) {
@@ -347,10 +347,10 @@
                 }
                 nitems = remaining_space / size;
                 if (nitems == 0) {
-                    return 0;
+                    return total_flushed;
                 }
             }
-            return cxBufferWrite(ptr, size, nitems, buffer);
+            goto cx_buffer_write_retry;
         }
     } else {
         memcpy(buffer->bytes + buffer->pos, ptr, len);
@@ -358,9 +358,8 @@
         if (buffer->pos > buffer->size) {
             buffer->size = buffer->pos;
         }
-        return nitems;
+        return total_flushed + nitems;
     }
-
 }
 
 size_t cxBufferAppend(

mercurial