Merge branch 'PHP-8.1' into PHP-8.2

This commit is contained in:
Bob Weinand 2023-11-25 00:59:26 +01:00
commit 50ccea31f2
7 changed files with 158 additions and 2 deletions

2
NEWS
View file

@ -7,6 +7,8 @@ PHP NEWS
error handler). (ilutov) error handler). (ilutov)
. Fixed oss-fuzz #64209 (In-place modification of filename in . Fixed oss-fuzz #64209 (In-place modification of filename in
php_message_handler_for_zend). (ilutov) php_message_handler_for_zend). (ilutov)
. Fixed bug GH-12758 / GH-12768 (Invalid opline in OOM handlers within
ZEND_FUNC_GET_ARGS and ZEND_BIND_STATIC). (Florian Engelhardt)
- Date: - Date:
. Fixed improbably integer overflow while parsing really large (or small) . Fixed improbably integer overflow while parsing really large (or small)

View file

@ -8851,6 +8851,8 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, UNUSED, REF)
variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W);
SAVE_OPLINE();
ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr); ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr);
if (!ht) { if (!ht) {
ht = zend_array_dup(EX(func)->op_array.static_variables); ht = zend_array_dup(EX(func)->op_array.static_variables);
@ -8860,7 +8862,6 @@ ZEND_VM_HANDLER(183, ZEND_BIND_STATIC, CV, UNUSED, REF)
value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT))); value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT)));
SAVE_OPLINE();
if (opline->extended_value & ZEND_BIND_REF) { if (opline->extended_value & ZEND_BIND_REF) {
if (Z_TYPE_P(value) == IS_CONSTANT_AST) { if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) { if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) {
@ -9314,6 +9315,7 @@ ZEND_VM_HANDLER(172, ZEND_FUNC_GET_ARGS, UNUSED|CONST, UNUSED)
} }
if (result_size) { if (result_size) {
SAVE_OPLINE();
uint32_t first_extra_arg = EX(func)->op_array.num_args; uint32_t first_extra_arg = EX(func)->op_array.num_args;
ht = zend_new_array(result_size); ht = zend_new_array(result_size);

View file

@ -10805,6 +10805,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FUNC_GET_ARGS_SPEC_CONST_UNUSE
} }
if (result_size) { if (result_size) {
SAVE_OPLINE();
uint32_t first_extra_arg = EX(func)->op_array.num_args; uint32_t first_extra_arg = EX(func)->op_array.num_args;
ht = zend_new_array(result_size); ht = zend_new_array(result_size);
@ -36303,6 +36304,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FUNC_GET_ARGS_SPEC_UNUSED_UNUS
} }
if (result_size) { if (result_size) {
SAVE_OPLINE();
uint32_t first_extra_arg = EX(func)->op_array.num_args; uint32_t first_extra_arg = EX(func)->op_array.num_args;
ht = zend_new_array(result_size); ht = zend_new_array(result_size);
@ -48703,6 +48705,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_UNUSED_HAN
variable_ptr = EX_VAR(opline->op1.var); variable_ptr = EX_VAR(opline->op1.var);
SAVE_OPLINE();
ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr); ht = ZEND_MAP_PTR_GET(EX(func)->op_array.static_variables_ptr);
if (!ht) { if (!ht) {
ht = zend_array_dup(EX(func)->op_array.static_variables); ht = zend_array_dup(EX(func)->op_array.static_variables);
@ -48712,7 +48716,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_STATIC_SPEC_CV_UNUSED_HAN
value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT))); value = (zval*)((char*)ht->arData + (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT)));
SAVE_OPLINE();
if (opline->extended_value & ZEND_BIND_REF) { if (opline->extended_value & ZEND_BIND_REF) {
if (Z_TYPE_P(value) == IS_CONSTANT_AST) { if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) { if (UNEXPECTED(zval_update_constant_ex(value, EX(func)->op_array.scope) != SUCCESS)) {

View file

@ -55,6 +55,9 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
int register_passes; int register_passes;
bool print_stderr_mshutdown; bool print_stderr_mshutdown;
zend_long limit_copy_file_range; zend_long limit_copy_file_range;
int observe_opline_in_zendmm;
zend_mm_heap* zend_orig_heap;
zend_mm_heap* zend_test_heap;
zend_test_fiber *active_fiber; zend_test_fiber *active_fiber;
zend_long quantity_value; zend_long quantity_value;
zend_string *str_test; zend_string *str_test;

View file

@ -30,9 +30,16 @@
#include "zend_interfaces.h" #include "zend_interfaces.h"
#include "zend_weakrefs.h" #include "zend_weakrefs.h"
#include "Zend/Optimizer/zend_optimizer.h" #include "Zend/Optimizer/zend_optimizer.h"
#include "Zend/zend_alloc.h"
#include "test.h" #include "test.h"
#include "test_arginfo.h" #include "test_arginfo.h"
// `php.h` sets `NDEBUG` when not `PHP_DEBUG` which will make `assert()` from
// assert.h a no-op. In order to have `assert()` working on NDEBUG builds, we
// undefine `NDEBUG` and re-include assert.h
#undef NDEBUG
#include "assert.h"
#if defined(HAVE_LIBXML) && !defined(PHP_WIN32) #if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
# include <libxml/globals.h> # include <libxml/globals.h>
# include <libxml/parser.h> # include <libxml/parser.h>
@ -501,6 +508,68 @@ static ZEND_FUNCTION(zend_test_crash)
php_printf("%s", invalid); php_printf("%s", invalid);
} }
static bool has_opline(zend_execute_data *execute_data)
{
return execute_data
&& execute_data->func
&& ZEND_USER_CODE(execute_data->func->type)
&& execute_data->opline
;
}
void * zend_test_custom_malloc(size_t len)
{
if (has_opline(EG(current_execute_data))) {
assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1);
}
return _zend_mm_alloc(ZT_G(zend_orig_heap), len ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC);
}
void zend_test_custom_free(void *ptr)
{
if (has_opline(EG(current_execute_data))) {
assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1);
}
_zend_mm_free(ZT_G(zend_orig_heap), ptr ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC);
}
void * zend_test_custom_realloc(void * ptr, size_t len)
{
if (has_opline(EG(current_execute_data))) {
assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1);
}
return _zend_mm_realloc(ZT_G(zend_orig_heap), ptr, len ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC);
}
static PHP_INI_MH(OnUpdateZendTestObserveOplineInZendMM)
{
if (new_value == NULL) {
return FAILURE;
}
int int_value = zend_ini_parse_bool(new_value);
if (int_value == 1) {
// `zend_mm_heap` is a private struct, so we have not way to find the
// actual size, but 4096 bytes should be enough
ZT_G(zend_test_heap) = malloc(4096);
memset(ZT_G(zend_test_heap), 0, 4096);
zend_mm_set_custom_handlers(
ZT_G(zend_test_heap),
zend_test_custom_malloc,
zend_test_custom_free,
zend_test_custom_realloc
);
ZT_G(zend_orig_heap) = zend_mm_get_heap();
zend_mm_set_heap(ZT_G(zend_test_heap));
} else if (ZT_G(zend_test_heap)) {
free(ZT_G(zend_test_heap));
ZT_G(zend_test_heap) = NULL;
zend_mm_set_heap(ZT_G(zend_orig_heap));
}
return OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
}
static ZEND_FUNCTION(zend_test_is_pcre_bundled) static ZEND_FUNCTION(zend_test_is_pcre_bundled)
{ {
ZEND_PARSE_PARAMETERS_NONE(); ZEND_PARSE_PARAMETERS_NONE();
@ -743,6 +812,7 @@ PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("zend_test.quantity_value", "0", PHP_INI_ALL, OnUpdateLong, quantity_value, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_ENTRY("zend_test.quantity_value", "0", PHP_INI_ALL, OnUpdateLong, quantity_value, zend_zend_test_globals, zend_test_globals)
STD_PHP_INI_ENTRY("zend_test.str_test", "", PHP_INI_ALL, OnUpdateStr, str_test, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_ENTRY("zend_test.str_test", "", PHP_INI_ALL, OnUpdateStr, str_test, zend_zend_test_globals, zend_test_globals)
STD_PHP_INI_ENTRY("zend_test.not_empty_str_test", "val", PHP_INI_ALL, OnUpdateStrNotEmpty, not_empty_str_test, zend_zend_test_globals, zend_test_globals) STD_PHP_INI_ENTRY("zend_test.not_empty_str_test", "val", PHP_INI_ALL, OnUpdateStrNotEmpty, not_empty_str_test, zend_zend_test_globals, zend_test_globals)
STD_PHP_INI_BOOLEAN("zend_test.observe_opline_in_zendmm", "0", PHP_INI_ALL, OnUpdateZendTestObserveOplineInZendMM, observe_opline_in_zendmm, zend_zend_test_globals, zend_test_globals)
PHP_INI_END() PHP_INI_END()
void (*old_zend_execute_ex)(zend_execute_data *execute_data); void (*old_zend_execute_ex)(zend_execute_data *execute_data);
@ -899,6 +969,13 @@ PHP_RSHUTDOWN_FUNCTION(zend_test)
zend_weakrefs_hash_del(&ZT_G(global_weakmap), zend_weakref_key_to_object(obj_key)); zend_weakrefs_hash_del(&ZT_G(global_weakmap), zend_weakref_key_to_object(obj_key));
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
zend_hash_destroy(&ZT_G(global_weakmap)); zend_hash_destroy(&ZT_G(global_weakmap));
if (ZT_G(zend_test_heap)) {
free(ZT_G(zend_test_heap));
ZT_G(zend_test_heap) = NULL;
zend_mm_set_heap(ZT_G(zend_orig_heap));
}
return SUCCESS; return SUCCESS;
} }

View file

@ -0,0 +1,33 @@
--TEST--
possible segfault in `ZEND_BIND_STATIC`
--DESCRIPTION--
https://github.com/php/php-src/pull/12758
--EXTENSIONS--
zend_test
--INI--
zend_test.observe_opline_in_zendmm=1
--FILE--
<?php
function &ref() {
static $a = 5;
return $a;
}
class Foo {
public static int $i;
public static string $s = "x";
}
var_dump(Foo::$i = "1");
var_dump(Foo::$s, Foo::$i);
var_dump(ref());
echo 'Done.';
?>
--EXPECT--
int(1)
string(1) "x"
int(1)
int(5)
Done.

View file

@ -0,0 +1,36 @@
--TEST--
possible segfault in `ZEND_FUNC_GET_ARGS`
--DESCRIPTION--
--EXTENSIONS--
zend_test
--INI--
zend_test.observe_opline_in_zendmm=1
--FILE--
<?php
function ref() {
return func_get_args();
}
class Foo {
public static int $i;
public static string $s = "x";
}
var_dump(Foo::$i = "1");
var_dump(Foo::$s, Foo::$i);
var_dump(ref('string', 0));
echo 'Done.';
?>
--EXPECT--
int(1)
string(1) "x"
int(1)
array(2) {
[0]=>
string(6) "string"
[1]=>
int(0)
}
Done.