[PECL-CVS] [pecl-mail-mailparse] master: Fix leak and fixed-size buffer in get_structure_callback

[email protected] (Ilia Alshanetsky via Remi Collet) Fri, 12 Jun 2026 13:33:01 +0000
Newsgroups php.pecl.cvs
Message-ID <[email protected]>
Author: Ilia Alshanetsky (iliaal)
Committer: Remi Collet (remicollet)
Date: 2026-06-12T15:32:47+02:00

Commit: https://github.com/php/pecl-mail-mailparse/commit/156d6e6e92e67dff5ed1a49410d162095a01fc38
Raw diff: https://github.com/php/pecl-mail-mailparse/commit/156d6e6e92e67dff5ed1a49410d162095a01fc38.diff

Fix leak and fixed-size buffer in get_structure_callback

The callback emalloc'd a fixed 1KB buffer for every part and, on the
"too many sections" path, returned FAILURE without freeing it. That
grow-and-bail logic was also dead code: erealloc aborts rather than
returning NULL, and the size check could only fire after the doubling
realloc had already grown the buffer.

Replace the manual buffer with a smart_string that grows as needed and
is always released. The output (dot-joined section ids) is unchanged.

Changed paths:
  M  mailparse.c


Diff:

diff --git a/mailparse.c b/mailparse.c
index 371ec9b..1e23ebd 100644
--- a/mailparse.c
+++ b/mailparse.c
@@ -1149,34 +1149,19 @@ PHP_FUNCTION(mailparse_msg_create)
 static int get_structure_callback(php_mimepart *part, php_mimepart_enumerator *id, void *ptr)
 {
 	zval *return_value = (zval *)ptr;
-	char intbuf[16];
-	char *buf;
-	int buf_size;
-	int len, i = 0;
-
-	buf_size = 1024;
-	buf = emalloc(buf_size);
-	while(id && i < buf_size)	{
-		sprintf(intbuf, "%d", id->id);
-		len = strlen(intbuf);
-		if (len > (buf_size-i))	{
-			/* too many sections: bail */
-			zend_error(E_WARNING, "%s(): too many nested sections in message", get_active_function_name());
-			return FAILURE;
-		}
-		if ((i + len + 1) >= buf_size) {
-			buf_size = buf_size << 1;
-			buf = erealloc(buf, buf_size);
-			if (!buf) {
-				zend_error(E_ERROR, "The structure buffer has been exceeded (%d).  Please try decreasing the nesting depth of messages and report this to the developers.", buf_size);
-			}
+	smart_string buf = {0};
+
+	while (id) {
+		smart_string_append_long(&buf, id->id);
+		if (id->next) {
+			smart_string_appendc(&buf, '.');
 		}
-		sprintf(&buf[i], "%s%c", intbuf, id->next ? '.' : '\0');
-		i += len + (id->next ? 1 : 0);
 		id = id->next;
 	}
-	add_next_index_string(return_value, buf);
-	efree(buf);
+	smart_string_0(&buf);
+
+	add_next_index_string(return_value, buf.c ? buf.c : "");
+	smart_string_free(&buf);
 	return SUCCESS;
 }