Skip to content

Commit 2eb3100

Browse files
committed
Fix phpGH-18438: Handling of empty data and errors in ZipArchive::addPattern
There is a ZPP arginfo violation because the empty return or error return is not always properly handled. And there is also a memory leak if creating the regular expression instance fails. Closes phpGH-18438.
1 parent b066ac0 commit 2eb3100

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ PHP NEWS
1717
- Zip:
1818
. Fixed bug GH-18431 (Registering ZIP progress callback twice doesn't work).
1919
(nielsdos)
20+
. Fixed bug GH-18438 (Handling of empty data and errors in
21+
ZipArchive::addPattern). (nielsdos)
2022

2123
08 May 2025, PHP 8.3.21
2224

ext/zip/php_zip.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,10 @@ int php_zip_pcre(zend_string *regexp, char *path, int path_len, zval *return_val
761761

762762
re = pcre_get_compiled_regex(regexp, &capture_count);
763763
if (!re) {
764+
for (i = 0; i < files_cnt; i++) {
765+
zend_string_release_ex(namelist[i], 0);
766+
}
767+
efree(namelist);
764768
php_error_docref(NULL, E_WARNING, "Invalid expression");
765769
return -1;
766770
}
@@ -1837,6 +1841,10 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /*
18371841
#endif
18381842
}
18391843
}
1844+
} else if (found == 0) {
1845+
RETURN_EMPTY_ARRAY();
1846+
} else {
1847+
RETURN_FALSE;
18401848
}
18411849
}
18421850
/* }}} */

ext/zip/tests/gh18438.phpt

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
--TEST--
2+
GH-18438 (Handling of empty data and errors in ZipArchive::addPattern)
3+
--EXTENSIONS--
4+
zip
5+
--SKIPIF--
6+
<?php
7+
if (PHP_ZTS) die("skip not for ZTS because of path prefixing breaking custom wrapper test");
8+
?>
9+
--FILE--
10+
<?php
11+
class CustomStreamWrapper {
12+
public $context;
13+
function dir_closedir(): bool {
14+
return true;
15+
}
16+
function dir_opendir(string $path, int $options): bool {
17+
return true;
18+
}
19+
function dir_readdir(): string|false {
20+
return false;
21+
}
22+
function dir_rewinddir(): bool {
23+
return false;
24+
}
25+
}
26+
27+
$file = __DIR__ . '/gh18438.zip';
28+
$zip = new ZipArchive;
29+
$zip->open($file, ZIPARCHIVE::CREATE);
30+
var_dump($zip->addPattern('/nomatches/'));
31+
var_dump($zip->addPattern('/invalid'));
32+
33+
stream_wrapper_register('custom', CustomStreamWrapper::class);
34+
var_dump($zip->addPattern('/invalid', 'custom://'));
35+
?>
36+
--CLEAN--
37+
<?php
38+
$file = __DIR__ . '/gh18438.zip';
39+
@unlink($file);
40+
?>
41+
--EXPECTF--
42+
array(0) {
43+
}
44+
45+
Warning: ZipArchive::addPattern(): No ending delimiter '/' found in %s on line %d
46+
47+
Warning: ZipArchive::addPattern(): Invalid expression in %s on line %d
48+
bool(false)
49+
array(0) {
50+
}

0 commit comments

Comments
 (0)