From 882ee618fb598e8a4a67f631d3d78b550b168e7c Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+ndossche@users.noreply.github.com> Date: Sat, 15 Nov 2025 18:30:29 +0100 Subject: [PATCH] Avoid string copy in ZipArchive::addFromString() Instead of copying the data we increment the refcount of the string. --- UPGRADING | 3 +++ ext/zip/php_zip.c | 11 +++++------ ext/zip/php_zip.h | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/UPGRADING b/UPGRADING index 3b0301522d460..1e84b8beee97a 100644 --- a/UPGRADING +++ b/UPGRADING @@ -130,3 +130,6 @@ PHP 8.6 UPGRADE NOTES . Improved performance of array_walk(). . Improved performance of intval('+0b...', 2) and intval('0b...', 2). . Improved performance of str_split(). + +- Zip: + . Avoid string copies in ZipArchive::addFromString(). diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 40c098d8901ca..06bd41d602c06 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -1014,7 +1014,7 @@ static void php_zip_object_free_storage(zend_object *object) /* {{{ */ if (intern->buffers_cnt>0) { for (i=0; ibuffers_cnt; i++) { - efree(intern->buffers[i]); + zend_string_release(intern->buffers[i]); } efree(intern->buffers); } @@ -1868,17 +1868,16 @@ PHP_METHOD(ZipArchive, addFromString) ze_obj = Z_ZIP_P(self); if (ze_obj->buffers_cnt) { - ze_obj->buffers = (char **)safe_erealloc(ze_obj->buffers, sizeof(char *), (ze_obj->buffers_cnt+1), 0); + ze_obj->buffers = safe_erealloc(ze_obj->buffers, sizeof(*ze_obj->buffers), (ze_obj->buffers_cnt + 1), 0); pos = ze_obj->buffers_cnt++; } else { - ze_obj->buffers = (char **)emalloc(sizeof(char *)); + ze_obj->buffers = emalloc(sizeof(*ze_obj->buffers)); ze_obj->buffers_cnt++; pos = 0; } - ze_obj->buffers[pos] = (char *)safe_emalloc(ZSTR_LEN(buffer), 1, 1); - memcpy(ze_obj->buffers[pos], ZSTR_VAL(buffer), ZSTR_LEN(buffer) + 1); + ze_obj->buffers[pos] = zend_string_copy(buffer); - zs = zip_source_buffer(intern, ze_obj->buffers[pos], ZSTR_LEN(buffer), 0); + zs = zip_source_buffer(intern, ZSTR_VAL(buffer), ZSTR_LEN(buffer), 0); if (zs == NULL) { RETURN_FALSE; diff --git a/ext/zip/php_zip.h b/ext/zip/php_zip.h index 61e7fb8dad1ea..5dc7bab250042 100644 --- a/ext/zip/php_zip.h +++ b/ext/zip/php_zip.h @@ -68,7 +68,7 @@ typedef struct _ze_zip_read_rsrc { /* Extends zend object */ typedef struct _ze_zip_object { struct zip *za; - char **buffers; + zend_string **buffers; HashTable *prop_handler; char *filename; int filename_len;