Commit 391ec277d54 for php.net
commit 391ec277d5497dc0a801fd193905d021f1fb34a0
Author: David Carlier <devnexen@gmail.com>
Date: Fri Apr 10 06:05:44 2026 +0100
Fix GH-21698: memory leak in ZipArchive::addGlob on early returns.
globfree was not called on the no-matches path and on the
open_basedir reject path, leaking the glob_t contents populated by a
successful glob() call.
close GH-21702
diff --git a/NEWS b/NEWS
index 2071326cf6e..07653ef6a37 100644
--- a/NEWS
+++ b/NEWS
@@ -44,6 +44,10 @@ PHP NEWS
- XSL:
. Fixed bug GH-21600 (Segfault on module shutdown). (David Carlier)
+- Zip:
+ . Fixed bug GH-21698 (memory leak with ZipArchive::addGlob()
+ early return statements). (David Carlier)
+
09 Apr 2026, PHP 8.4.20
- Bz2:
diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c
index 75ae4aa9191..d25cfe04326 100644
--- a/ext/zip/php_zip.c
+++ b/ext/zip/php_zip.c
@@ -675,12 +675,14 @@ int php_zip_glob(char *pattern, int pattern_len, zend_long flags, zval *return_v
/* now catch the FreeBSD style of "no matches" */
if (!globbuf.gl_pathc || !globbuf.gl_pathv) {
+ globfree(&globbuf);
return 0;
}
/* we assume that any glob pattern will match files from one directory only
so checking the dirname of the first match should be sufficient */
if (ZIP_OPENBASEDIR_CHECKPATH(globbuf.gl_pathv[0])) {
+ globfree(&globbuf);
return -1;
}
diff --git a/ext/zip/tests/gh21698.phpt b/ext/zip/tests/gh21698.phpt
new file mode 100644
index 00000000000..d77b2152e72
--- /dev/null
+++ b/ext/zip/tests/gh21698.phpt
@@ -0,0 +1,21 @@
+--TEST--
+GH-21698 (ZipArchive::addGlob memory leak when open_basedir rejects the match)
+--EXTENSIONS--
+zip
+--FILE--
+<?php
+$zipfile = __DIR__ . '/gh21698.zip';
+$zip = new ZipArchive();
+$zip->open($zipfile, ZipArchive::CREATE | ZipArchive::OVERWRITE);
+
+ini_set('open_basedir', '/nonexistent_dir_for_gh21698');
+var_dump($zip->addGlob(__FILE__, 0, []));
+$zip->close();
+?>
+--CLEAN--
+<?php
+@unlink(__DIR__ . '/gh21698.zip');
+?>
+--EXPECTF--
+Warning: ZipArchive::addGlob(): open_basedir restriction in effect. File(%s) is not within the allowed path(s): (%s) in %s on line %d
+bool(false)