[PECL-CVS] [pecl-mail-mailparse] fix/gh44-segfault-mimepart-dtor: actually fix the double-free this time

[email protected] (Rasmus Lerdorf) Sun, 5 Apr 2026 10:18:42 +0000
Newsgroups php.pecl.cvs
Message-ID <[email protected]>
Author: Rasmus Lerdorf (rlerdorf)
Date: 2026-04-05T06:18:33-04:00

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

actually fix the double-free this time

Changed paths:
  M  php_mailparse_mime.c


Diff:

diff --git a/php_mailparse_mime.c b/php_mailparse_mime.c
index 2d8a846..2fed283 100644
--- a/php_mailparse_mime.c
+++ b/php_mailparse_mime.c
@@ -321,8 +321,14 @@ PHP_MAILPARSE_API void php_mimepart_free(php_mimepart *part)
 	zval *childpart_z;
 	HashPosition pos;
 
-	/* Recursively free children, NULLing their resource pointers
-	 * to prevent double-free from the resource list cleanup */
+	/* Prevent the resource destructor from freeing this part again */
+	if (part->rsrc && part->rsrc->ptr == part) {
+		part->rsrc->ptr = NULL;
+	}
+
+	/* Recursively free children, NULLing their resource pointers to prevent
+	 * double-free from the resource list cleanup, and releasing the resource
+	 * list entry so the refcount doesn't leak */
 	zend_hash_internal_pointer_reset_ex(&part->children, &pos);
 	while ((childpart_z = zend_hash_get_current_data_ex(&part->children, &pos)) != NULL) {
 		zend_resource *child_res = Z_RES_P(childpart_z);
@@ -331,6 +337,7 @@ PHP_MAILPARSE_API void php_mimepart_free(php_mimepart *part)
 			child_res->ptr = NULL;
 			php_mimepart_free(child);
 		}
+		zend_list_delete(child_res);
 		zend_hash_move_forward_ex(&part->children, &pos);
 	}