Skip to content

Commit 93ce050

Browse files
committed
Fix assertion failures resulting in crashes with stream filter object parameters
This works for dynamic props but not for non-dynamic props due to the missing INDIRECT handling. Closes GH-20500.
1 parent 46a15ed commit 93ce050

File tree

6 files changed

+73
-12
lines changed

6 files changed

+73
-12
lines changed

NEWS

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ PHP NEWS
77
. Fixed bug GH-20435 (SensitiveParameter doesn't work for named argument
88
passing to variadic parameter). (ndossche)
99

10+
- Bz2:
11+
. Fix assertion failures resulting in crashes with stream filter
12+
object parameters. (ndossche)
13+
1014
- Date:
1115
. Fix crashes when trying to instantiate uninstantiable classes via date
1216
static constructors. (ndossche)
@@ -45,6 +49,10 @@ PHP NEWS
4549
- Zip:
4650
. Fix crash in property existence test. (ndossche)
4751

52+
- Zlib:
53+
. Fix assertion failures resulting in crashes with stream filter
54+
object parameters. (ndossche)
55+
4856
20 Nov 2025, PHP 8.3.28
4957

5058
- Core:

ext/bz2/bz2_filter.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -337,12 +337,14 @@ static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *fi
337337
zval *tmpzval = NULL;
338338

339339
if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
340-
if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "concatenated", sizeof("concatenated")-1))) {
340+
HashTable *ht = HASH_OF(filterparams);
341+
342+
if ((tmpzval = zend_hash_str_find_ind(ht, "concatenated", sizeof("concatenated")-1))) {
341343
data->expect_concatenated = zend_is_true(tmpzval);
342344
tmpzval = NULL;
343345
}
344346

345-
tmpzval = zend_hash_str_find(HASH_OF(filterparams), "small", sizeof("small")-1);
347+
tmpzval = zend_hash_str_find_ind(ht, "small", sizeof("small")-1);
346348
} else {
347349
tmpzval = filterparams;
348350
}
@@ -362,7 +364,9 @@ static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *fi
362364
zval *tmpzval;
363365

364366
if (Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) {
365-
if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "blocks", sizeof("blocks")-1))) {
367+
HashTable *ht = HASH_OF(filterparams);
368+
369+
if ((tmpzval = zend_hash_str_find_ind(ht, "blocks", sizeof("blocks")-1))) {
366370
/* How much memory to allocate (1 - 9) x 100kb */
367371
zend_long blocks = zval_get_long(tmpzval);
368372
if (blocks < 1 || blocks > 9) {
@@ -372,7 +376,7 @@ static php_stream_filter *php_bz2_filter_create(const char *filtername, zval *fi
372376
}
373377
}
374378

375-
if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "work", sizeof("work")-1))) {
379+
if ((tmpzval = zend_hash_str_find_ind(ht, "work", sizeof("work")-1))) {
376380
/* Work Factor (0 - 250) */
377381
zend_long work = zval_get_long(tmpzval);
378382
if (work < 0 || work > 250) {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
bz2 filter assertion failure with non-dynamic properties in filter param object
3+
--EXTENSIONS--
4+
bz2
5+
--FILE--
6+
<?php
7+
8+
class ParamsCompress {
9+
public int $blocks = 5;
10+
public int $work = 10;
11+
}
12+
13+
class ParamsDecompress {
14+
public bool $concatenated = true;
15+
public bool $small = true;
16+
}
17+
18+
$fp = fopen('php://stdout', 'w');
19+
stream_filter_append($fp, 'bzip2.compress', STREAM_FILTER_WRITE, new ParamsCompress);
20+
stream_filter_append($fp, 'bzip2.decompress', STREAM_FILTER_WRITE, new ParamsDecompress);
21+
fwrite($fp, "Hello world, hopefully not broken\n");
22+
23+
?>
24+
--EXPECT--
25+
Hello world, hopefully not broken

ext/phar/stream.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,18 +211,18 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, const cha
211211
php_url_free(resource);
212212
efree(internal_file);
213213

214-
if (context && Z_TYPE(context->options) != IS_UNDEF && (pzoption = zend_hash_str_find(HASH_OF(&context->options), "phar", sizeof("phar")-1)) != NULL) {
214+
if (context && Z_TYPE(context->options) != IS_UNDEF && (pzoption = zend_hash_str_find_ind(HASH_OF(&context->options), "phar", sizeof("phar")-1)) != NULL) {
215215
pharcontext = HASH_OF(pzoption);
216216
if (idata->internal_file->uncompressed_filesize == 0
217217
&& idata->internal_file->compressed_filesize == 0
218-
&& (pzoption = zend_hash_str_find(pharcontext, "compress", sizeof("compress")-1)) != NULL
218+
&& (pzoption = zend_hash_str_find_ind(pharcontext, "compress", sizeof("compress")-1)) != NULL
219219
&& Z_TYPE_P(pzoption) == IS_LONG
220220
&& (Z_LVAL_P(pzoption) & ~PHAR_ENT_COMPRESSION_MASK) == 0
221221
) {
222222
idata->internal_file->flags &= ~PHAR_ENT_COMPRESSION_MASK;
223223
idata->internal_file->flags |= Z_LVAL_P(pzoption);
224224
}
225-
if ((pzoption = zend_hash_str_find(pharcontext, "metadata", sizeof("metadata")-1)) != NULL) {
225+
if ((pzoption = zend_hash_str_find_ind(pharcontext, "metadata", sizeof("metadata")-1)) != NULL) {
226226
phar_metadata_tracker_free(&idata->internal_file->metadata_tracker, idata->internal_file->is_persistent);
227227

228228
metadata = pzoption;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
zlib filter assertion failure with non-dynamic properties in filter param object
3+
--EXTENSIONS--
4+
zlib
5+
--FILE--
6+
<?php
7+
8+
class Params {
9+
public int $memory = 6;
10+
public int $window = 15;
11+
public int $level = 6;
12+
}
13+
14+
$fp = fopen('php://stdout', 'w');
15+
stream_filter_append($fp, 'zlib.deflate', STREAM_FILTER_WRITE, new Params);
16+
stream_filter_append($fp, 'zlib.inflate', STREAM_FILTER_WRITE, new Params);
17+
fwrite($fp, "Hello world, hopefully not broken\n");
18+
19+
?>
20+
--EXPECT--
21+
Hello world, hopefully not broken

ext/zlib/zlib_filter.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
323323
zval *tmpzval;
324324

325325
if ((Z_TYPE_P(filterparams) == IS_ARRAY || Z_TYPE_P(filterparams) == IS_OBJECT) &&
326-
(tmpzval = zend_hash_str_find(HASH_OF(filterparams), "window", sizeof("window") - 1))) {
326+
(tmpzval = zend_hash_str_find_ind(HASH_OF(filterparams), "window", sizeof("window") - 1))) {
327327
/* log-2 base of history window (9 - 15) */
328328
zend_long tmp = zval_get_long(tmpzval);
329329
if (tmp < -MAX_WBITS || tmp > MAX_WBITS + 32) {
@@ -354,8 +354,10 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
354354

355355
switch (Z_TYPE_P(filterparams)) {
356356
case IS_ARRAY:
357-
case IS_OBJECT:
358-
if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "memory", sizeof("memory") -1))) {
357+
case IS_OBJECT: {
358+
HashTable *ht = HASH_OF(filterparams);
359+
360+
if ((tmpzval = zend_hash_str_find_ind(ht, "memory", sizeof("memory") -1))) {
359361
/* Memory Level (1 - 9) */
360362
tmp = zval_get_long(tmpzval);
361363
if (tmp < 1 || tmp > MAX_MEM_LEVEL) {
@@ -365,7 +367,7 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
365367
}
366368
}
367369

368-
if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "window", sizeof("window") - 1))) {
370+
if ((tmpzval = zend_hash_str_find_ind(ht, "window", sizeof("window") - 1))) {
369371
/* log-2 base of history window (9 - 15) */
370372
tmp = zval_get_long(tmpzval);
371373
if (tmp < -MAX_WBITS || tmp > MAX_WBITS + 16) {
@@ -375,13 +377,14 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
375377
}
376378
}
377379

378-
if ((tmpzval = zend_hash_str_find(HASH_OF(filterparams), "level", sizeof("level") - 1))) {
380+
if ((tmpzval = zend_hash_str_find_ind(ht, "level", sizeof("level") - 1))) {
379381
tmp = zval_get_long(tmpzval);
380382

381383
/* Pseudo pass through to catch level validating code */
382384
goto factory_setlevel;
383385
}
384386
break;
387+
}
385388
case IS_STRING:
386389
case IS_DOUBLE:
387390
case IS_LONG:

0 commit comments

Comments
 (0)