1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix GH-13433: Segmentation Fault in zend_class_init_statics when using opcache.preload

This regressed in 9a250cc9d6, which allowed static properties to get
overridden by a trait during inheritance. In particular, because of the
change to the loop in zend_update_parent_ce(), it's not guaranteed that
all indirects are after one another.

This means that during persisting the zvals of the static members table,
some static properties may be skipped. In case of the test code, this
means that the array in the trait will keep referring to the old, new
freed, stale value. To solve this, we check the type for IS_INDIRECT,
which is the same as what zend_persist_calc() is already doing anyway.

Since 2543e61aed we can check for IS_INDIRECT to see if it should be
persisted or not.

Closes GH-13794.
This commit is contained in:
Niels Dossche
2024-03-23 17:19:54 +01:00
parent 9381129d1b
commit 55e617691a
7 changed files with 56 additions and 4 deletions

3
NEWS
View File

@@ -2,6 +2,9 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 8.3.6
- Opcache:
. Fixed bug GH-13433 (Segmentation Fault in zend_class_init_statics when
using opcache.preload). (nielsdos)
28 Mar 2024, PHP 8.3.5RC1

View File

@@ -0,0 +1,4 @@
<?php
abstract class ParentClass {
use TraitA;
}

View File

@@ -0,0 +1,8 @@
<?php
class TheClass extends ParentClass {
use TraitA;
public function test() {
return self::$non_empty_array;
}
}

View File

@@ -0,0 +1,4 @@
<?php
trait TraitA {
protected static $non_empty_array = ['non-empty'];
}

View File

@@ -0,0 +1,28 @@
--TEST--
GH-13433 (Segmentation Fault in zend_class_init_statics when using opcache.preload)
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.optimization_level=0
opcache.preload={PWD}/preload.inc
--EXTENSIONS--
opcache
--SKIPIF--
<?php
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
?>
--FILE--
<?php
$instance = new TheClass;
var_dump($instance);
var_dump($instance->test());
?>
OK
--EXPECT--
object(TheClass)#1 (0) {
}
array(1) {
[0]=>
string(9) "non-empty"
}
OK

View File

@@ -0,0 +1,4 @@
<?php
require __DIR__.'/TraitA.inc';
require __DIR__.'/ParentClass.inc';
require __DIR__.'/TheClass.inc';

View File

@@ -903,10 +903,11 @@ zend_class_entry *zend_persist_class_entry(zend_class_entry *orig_ce)
ce->default_static_members_table = zend_shared_memdup_free(ce->default_static_members_table, sizeof(zval) * ce->default_static_members_count);
/* Persist only static properties in this class.
* Static properties from parent classes will be handled in class_copy_ctor */
i = (ce->parent && (ce->ce_flags & ZEND_ACC_LINKED)) ? ce->parent->default_static_members_count : 0;
for (; i < ce->default_static_members_count; i++) {
zend_persist_zval(&ce->default_static_members_table[i]);
* Static properties from parent classes will be handled in class_copy_ctor and are marked with IS_INDIRECT */
for (i = 0; i < ce->default_static_members_count; i++) {
if (Z_TYPE(ce->default_static_members_table[i]) != IS_INDIRECT) {
zend_persist_zval(&ce->default_static_members_table[i]);
}
}
if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
if (ce->ce_flags & ZEND_ACC_LINKED) {