Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ PHP NEWS
(Lazizbek Ergashev, David Carlier)
. Fixed bug GH-25302 (Use-after-free in zend_compile_const_decl() with
OPcache during concurrent compilation). (Nicolas Grekas)
. Fixed use-after-free when the error handler releases a string while an
"Illegal string offset" warning is raised for its offset in a read, ?? or
nested isset()/empty(). (Jorg Sowa)

- Curl:
. Fixed curl_reset() retaining CURLOPT_PRIVATE after reset. (lacatoire)
Expand All @@ -44,6 +47,9 @@ PHP NEWS
(Ilia Alshanetsky)
. Fixed JIT ignoring leading-numeric string offsets in isset(), empty() and
??. (Jorg Sowa)
. Fixed use-after-free in JIT when the error handler releases a string while
an "Undefined variable" warning is raised for its offset in ?? or nested
isset()/empty(). (Jorg Sowa)

- PDO_Firebird:
. Fixed stack buffer overflow with long connection user names, passwords,
Expand Down
25 changes: 25 additions & 0 deletions Zend/tests/offsets/string_offset_read_warning_frees_string.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
--TEST--
Reading a leading-numeric string offset when the error handler releases the string
--FILE--
<?php
set_error_handler(function ($errno, $errstr) {
$GLOBALS['s'] = null;
echo $errstr, "\n";
});

function make(int $n) {
return str_repeat("abc", $n);
}

function test() {
global $s;
return $s["1x"];
}

$s = make(2);
test();
var_dump($s);
?>
--EXPECT--
Illegal string offset "1x"
NULL
10 changes: 10 additions & 0 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -2956,7 +2956,17 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
if (IS_LONG == is_numeric_string_ex(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset,
NULL, /* allow errors */ true, NULL, &trailing_data)) {
if (UNEXPECTED(trailing_data)) {
/* The string may be destroyed while throwing the warning.
* Temporarily increase the refcount to detect this situation. */
if (!(GC_FLAGS(str) & IS_STR_INTERNED)) {
GC_ADDREF(str);
}
zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim));
if (!(GC_FLAGS(str) & IS_STR_INTERNED) && UNEXPECTED(GC_DELREF(str) == 0)) {
zend_string_efree(str);
ZVAL_NULL(result);
return;
}
}
goto out;
}
Expand Down
9 changes: 9 additions & 0 deletions ext/opcache/jit/zend_jit_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1134,7 +1134,16 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_str_is_helper(zend_string *str, zva
break;
}
case IS_UNDEF:
/* The string may be destroyed while throwing the notice */
if (!(GC_FLAGS(str) & IS_STR_INTERNED)) {
GC_ADDREF(str);
}
zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var);
if (!(GC_FLAGS(str) & IS_STR_INTERNED) && UNEXPECTED(GC_DELREF(str) == 0)) {
zend_string_efree(str);
ZVAL_NULL(result);
return;
}
ZEND_FALLTHROUGH;
case IS_DOUBLE:
case IS_NULL:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--TEST--
JIT FETCH_DIM_IS: undefined offset variable when the error handler releases the string
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.jit=function
opcache.file_update_protection=0
--EXTENSIONS--
opcache
--FILE--
<?php
set_error_handler(function ($errno, $errstr) {
$GLOBALS['s'] = null;
echo $errstr, "\n";
});

function make(int $n) {
return str_repeat("abc", $n);
}

function test() {
global $s;
return $s[$undef] ?? "default";
}

$s = make(2);
var_dump(test());
?>
--EXPECT--
Undefined variable $undef
string(7) "default"
Loading