This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton.git


The following commit(s) were added to refs/heads/main by this push:
     new 75ad2aa02 PROTON-2950: Make pn_buffer/pn_string allocations more robust
75ad2aa02 is described below

commit 75ad2aa0225c7db64400f4eaaf213e2458143ea7
Author: Andrew Stitcher <[email protected]>
AuthorDate: Mon Aug 24 21:43:01 2026 -0400

    PROTON-2950: Make pn_buffer/pn_string allocations more robust
---
 c/src/core/buffer.c        |  7 +++++--
 c/src/core/object/string.c | 50 +++++++++++++++++++++++++++++-----------------
 2 files changed, 37 insertions(+), 20 deletions(-)

diff --git a/c/src/core/buffer.c b/c/src/core/buffer.c
index dbc7a451f..103d57c21 100644
--- a/c/src/core/buffer.c
+++ b/c/src/core/buffer.c
@@ -121,9 +121,12 @@ int pn_buffer_ensure(pn_buffer_t *buf, size_t size)
   size_t old_head = pni_buffer_head(buf);
   bool wrapped = pni_buffer_wrapped(buf);
 
-  uint32_t needed = (uint32_t)(buf->size + size);
+  uint64_t needed = (uint64_t) buf->size + size;
   if (needed < 32) needed = 32;
-  uint32_t new_capacity = pni_round_up_pow2(needed);
+  if (needed > 0x80000000ULL) {
+    return PN_OUT_OF_MEMORY;
+  }
+  uint32_t new_capacity = pni_round_up_pow2((uint32_t) needed);
 
   char* new_bytes = (char *) pni_mem_subreallocate(PN_CLASSCLASS(pn_buffer), 
buf, buf->bytes, new_capacity);
   if (!new_bytes) {
diff --git a/c/src/core/object/string.c b/c/src/core/object/string.c
index eeb297c15..8aff966d3 100644
--- a/c/src/core/object/string.c
+++ b/c/src/core/object/string.c
@@ -25,9 +25,11 @@
 
 #include "core/fixed_string.h"
 #include "core/memory.h"
+#include "core/util.h"
 
 #include <stdio.h>
 #include <stddef.h>
+#include <stdint.h>
 #include <string.h>
 #include <assert.h>
 #include <ctype.h>
@@ -110,9 +112,17 @@ pn_string_t *pn_stringn(const char *bytes, size_t n)
 {
   static const pn_class_t clazz = PN_CLASS(pn_string);
   pn_string_t *string = (pn_string_t *) pn_class_new(&clazz, 
sizeof(pn_string_t));
-  string->capacity = n ? n * sizeof(char) : 16;
-  string->bytes = (char *) pni_mem_suballocate(&clazz, string, 
string->capacity);
-  pn_string_setn(string, bytes, n);
+  if (!string) return NULL;
+
+  /* Make the object safe to finalize before anything can fail */
+  string->bytes = NULL;
+  string->capacity = 0;
+  string->size = PNI_NULL_SIZE;
+
+  if (pn_string_setn(string, bytes, n)) {
+    pn_free(string);
+    return NULL;
+  }
   return string;
 }
 
@@ -152,20 +162,22 @@ int pn_string_grow(pn_string_t *string, size_t capacity)
 {
   if (!string) return PN_ARG_ERR;
 
-  bool grow = false;
-  while (string->capacity < (capacity*sizeof(char) + 1)) {
-    string->capacity *= 2;
-    grow = true;
-  }
+  /* Reject the request before doing any arithmetic on it. Capping the string
+   * at INT32_MAX bytes leaves room for the trailing null within uint32_t and
+   * keeps the (signed) size field from overflowing. */
+  if (capacity > INT32_MAX) return PN_OUT_OF_MEMORY;
 
-  if (grow) {
-    char *growed = (char *) pni_mem_subreallocate(pn_class(string), string, 
string->bytes, string->capacity);
-    if (growed) {
-      string->bytes = growed;
-    } else {
-      return PN_ERR;
-    }
-  }
+  // Never allocate less than 16 bytes, to avoid work for small strings.
+  uint32_t needed = (uint32_t) pn_max(16, capacity + 1);
+  if (needed <= string->capacity) return 0;
+
+  uint32_t new_capacity = pni_round_up_pow2(needed);
+
+  char *growed = (char *) pni_mem_subreallocate(pn_class(string), string, 
string->bytes, new_capacity);
+  if (!growed) return PN_OUT_OF_MEMORY;
+
+  string->bytes = growed;
+  string->capacity = new_capacity;
 
   return 0;
 }
@@ -216,7 +228,8 @@ int pn_string_format(pn_string_t *string, PN_PRINTF_FORMAT 
const char *format, .
 
 int pn_string_vformat(pn_string_t *string, const char *format, va_list ap)
 {
-  pn_string_set(string, "");
+  int err = pn_string_set(string, "");
+  if (err) return err;
   return pn_string_vaddf(string, format, ap);
 }
 
@@ -245,7 +258,8 @@ int pn_string_vaddf(pn_string_t *string, const char 
*format, va_list ap)
     if (err < 0) {
       return err;
     } else if ((size_t) err >= string->capacity - string->size) {
-      pn_string_grow(string, string->size + err);
+      int grow_err = pn_string_grow(string, (size_t) string->size + (size_t) 
err);
+      if (grow_err) return grow_err;
     } else {
       string->size += err;
       return 0;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to