Skip to content

Commit 532f2ca

Browse files
committed
Merge branch 'PHP-8.1'
* PHP-8.1: Fix crash after indirect modification of string by user error handler
2 parents c2aea6e + afd8817 commit 532f2ca

File tree

2 files changed

+36
-3
lines changed

2 files changed

+36
-3
lines changed

Zend/tests/str_offset_005.phpt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
string offset 005 indirect string modification by error handler
3+
--FILE--
4+
<?php
5+
set_error_handler(function(){$GLOBALS['a']=8;});
6+
$a='a';
7+
var_dump($a[$b]);
8+
var_dump($a);
9+
?>
10+
--EXPECT--
11+
string(1) "a"
12+
int(8)

Zend/zend_execute.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2410,6 +2410,7 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
24102410
}
24112411
}
24122412
if (!is_list && EXPECTED(Z_TYPE_P(container) == IS_STRING)) {
2413+
zend_string *str = Z_STR_P(container);
24132414
zend_long offset;
24142415

24152416
try_string_offset:
@@ -2435,14 +2436,34 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
24352436
return;
24362437
}
24372438
case IS_UNDEF:
2439+
/* The string may be destroyed while throwing the notice.
2440+
* Temporarily increase the refcount to detect this situation. */
2441+
if (!(GC_FLAGS(str) & IS_ARRAY_IMMUTABLE)) {
2442+
GC_ADDREF(str);
2443+
}
24382444
ZVAL_UNDEFINED_OP2();
2445+
if (!(GC_FLAGS(str) & IS_ARRAY_IMMUTABLE) && GC_DELREF(str) == 0) {
2446+
zend_string_release_ex(str, 0);
2447+
ZVAL_NULL(result);
2448+
return;
2449+
}
24392450
ZEND_FALLTHROUGH;
24402451
case IS_DOUBLE:
24412452
case IS_NULL:
24422453
case IS_FALSE:
24432454
case IS_TRUE:
24442455
if (type != BP_VAR_IS) {
2456+
/* The string may be destroyed while throwing the notice.
2457+
* Temporarily increase the refcount to detect this situation. */
2458+
if (!(GC_FLAGS(str) & IS_ARRAY_IMMUTABLE)) {
2459+
GC_ADDREF(str);
2460+
}
24452461
zend_error(E_WARNING, "String offset cast occurred");
2462+
if (!(GC_FLAGS(str) & IS_ARRAY_IMMUTABLE) && GC_DELREF(str) == 0) {
2463+
zend_string_release_ex(str, 0);
2464+
ZVAL_NULL(result);
2465+
return;
2466+
}
24462467
}
24472468
break;
24482469
case IS_REFERENCE:
@@ -2460,7 +2481,7 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
24602481
}
24612482
out:
24622483

2463-
if (UNEXPECTED(Z_STRLEN_P(container) < ((offset < 0) ? -(size_t)offset : ((size_t)offset + 1)))) {
2484+
if (UNEXPECTED(ZSTR_LEN(str) < ((offset < 0) ? -(size_t)offset : ((size_t)offset + 1)))) {
24642485
if (type != BP_VAR_IS) {
24652486
zend_error(E_WARNING, "Uninitialized string offset " ZEND_LONG_FMT, offset);
24662487
ZVAL_EMPTY_STRING(result);
@@ -2472,8 +2493,8 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
24722493
zend_long real_offset;
24732494

24742495
real_offset = (UNEXPECTED(offset < 0)) /* Handle negative offset */
2475-
? (zend_long)Z_STRLEN_P(container) + offset : offset;
2476-
c = (zend_uchar)Z_STRVAL_P(container)[real_offset];
2496+
? (zend_long)ZSTR_LEN(str) + offset : offset;
2497+
c = (zend_uchar)ZSTR_VAL(str)[real_offset];
24772498

24782499
ZVAL_CHAR(result, c);
24792500
}

0 commit comments

Comments
 (0)