Fix static variable in methods inheritance during preloading

This is now "bug compatible" with the normal behavior, and more
imporantly, does not crash :)
This commit is contained in:
Nikita Popov 2020-11-04 15:33:11 +01:00
parent b8f2531ff0
commit 670fe594b9
3 changed files with 49 additions and 7 deletions

View file

@ -90,13 +90,6 @@ static zend_function *zend_duplicate_user_function(zend_function *func) /* {{{ *
new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array)); new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
memcpy(new_function, func, sizeof(zend_op_array)); memcpy(new_function, func, sizeof(zend_op_array));
if (ZEND_MAP_PTR_GET(func->op_array.static_variables_ptr)) {
/* See: Zend/tests/method_static_var.phpt */
new_function->op_array.static_variables = ZEND_MAP_PTR_GET(func->op_array.static_variables_ptr);
}
if (!(GC_FLAGS(new_function->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
GC_ADDREF(new_function->op_array.static_variables);
}
if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) { if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
ZEND_ASSERT(new_function->op_array.fn_flags & ZEND_ACC_PRELOADED); ZEND_ASSERT(new_function->op_array.fn_flags & ZEND_ACC_PRELOADED);
@ -105,6 +98,15 @@ static zend_function *zend_duplicate_user_function(zend_function *func) /* {{{ *
ZEND_MAP_PTR_INIT(new_function->op_array.static_variables_ptr, &new_function->op_array.static_variables); ZEND_MAP_PTR_INIT(new_function->op_array.static_variables_ptr, &new_function->op_array.static_variables);
} }
HashTable *static_properties_ptr = ZEND_MAP_PTR_GET(func->op_array.static_variables_ptr);
if (static_properties_ptr) {
/* See: Zend/tests/method_static_var.phpt */
ZEND_MAP_PTR_SET(new_function->op_array.static_variables_ptr, static_properties_ptr);
GC_TRY_ADDREF(static_properties_ptr);
} else {
GC_TRY_ADDREF(new_function->op_array.static_variables);
}
return new_function; return new_function;
} }
/* }}} */ /* }}} */

View file

@ -0,0 +1,15 @@
<?php
class Foo {
public static function test() {
static $i = 0;
var_dump(++$i);
}
}
Foo::test();
eval("class Bar extends Foo {}"); // Avoid early binding.
Foo::test();
Bar::test();
Bar::test();
echo "\n";

View file

@ -0,0 +1,25 @@
--TEST--
Preloading inherited method with separated static vars
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.optimization_level=-1
opcache.preload={PWD}/preload_method_static_vars.inc
--SKIPIF--
<?php
require_once('skipif.inc');
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
?>
--FILE--
<?php
Foo::test();
Bar::test();
?>
--EXPECT--
int(1)
int(2)
int(2)
int(3)
int(1)
int(1)