Skip to content

Commit afd8817

Browse files
committed
Merge branch 'PHP-8.0' into PHP-8.1
* PHP-8.0: Fix crash after indirect modification of string by user error handler
2 parents 3564001 + df434f0 commit afd8817

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
@@ -2484,6 +2484,7 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
24842484
}
24852485
}
24862486
if (!is_list && EXPECTED(Z_TYPE_P(container) == IS_STRING)) {
2487+
zend_string *str = Z_STR_P(container);
24872488
zend_long offset;
24882489

24892490
try_string_offset:
@@ -2509,14 +2510,34 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
25092510
return;
25102511
}
25112512
case IS_UNDEF:
2513+
/* The string may be destroyed while throwing the notice.
2514+
* Temporarily increase the refcount to detect this situation. */
2515+
if (!(GC_FLAGS(str) & IS_ARRAY_IMMUTABLE)) {
2516+
GC_ADDREF(str);
2517+
}
25122518
ZVAL_UNDEFINED_OP2();
2519+
if (!(GC_FLAGS(str) & IS_ARRAY_IMMUTABLE) && GC_DELREF(str) == 0) {
2520+
zend_string_release_ex(str, 0);
2521+
ZVAL_NULL(result);
2522+
return;
2523+
}
25132524
ZEND_FALLTHROUGH;
25142525
case IS_DOUBLE:
25152526
case IS_NULL:
25162527
case IS_FALSE:
25172528
case IS_TRUE:
25182529
if (type != BP_VAR_IS) {
2530+
/* The string may be destroyed while throwing the notice.
2531+
* Temporarily increase the refcount to detect this situation. */
2532+
if (!(GC_FLAGS(str) & IS_ARRAY_IMMUTABLE)) {
2533+
GC_ADDREF(str);
2534+
}
25192535
zend_error(E_WARNING, "String offset cast occurred");
2536+
if (!(GC_FLAGS(str) & IS_ARRAY_IMMUTABLE) && GC_DELREF(str) == 0) {
2537+
zend_string_release_ex(str, 0);
2538+
ZVAL_NULL(result);
2539+
return;
2540+
}
25202541
}
25212542
break;
25222543
case IS_REFERENCE:
@@ -2534,7 +2555,7 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
25342555
}
25352556
out:
25362557

2537-
if (UNEXPECTED(Z_STRLEN_P(container) < ((offset < 0) ? -(size_t)offset : ((size_t)offset + 1)))) {
2558+
if (UNEXPECTED(ZSTR_LEN(str) < ((offset < 0) ? -(size_t)offset : ((size_t)offset + 1)))) {
25382559
if (type != BP_VAR_IS) {
25392560
zend_error(E_WARNING, "Uninitialized string offset " ZEND_LONG_FMT, offset);
25402561
ZVAL_EMPTY_STRING(result);
@@ -2546,8 +2567,8 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
25462567
zend_long real_offset;
25472568

25482569
real_offset = (UNEXPECTED(offset < 0)) /* Handle negative offset */
2549-
? (zend_long)Z_STRLEN_P(container) + offset : offset;
2550-
c = (zend_uchar)Z_STRVAL_P(container)[real_offset];
2570+
? (zend_long)ZSTR_LEN(str) + offset : offset;
2571+
c = (zend_uchar)ZSTR_VAL(str)[real_offset];
25512572

25522573
ZVAL_CHAR(result, c);
25532574
}

0 commit comments

Comments
 (0)