summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/tests/bug51822.phpt40
-rw-r--r--Zend/zend_opcode.c16
2 files changed, 54 insertions, 2 deletions
diff --git a/Zend/tests/bug51822.phpt b/Zend/tests/bug51822.phpt
new file mode 100644
index 0000000000..cffae7bb1a
--- /dev/null
+++ b/Zend/tests/bug51822.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Bug #51822 (Segfault with strange __destruct() for static class variables)
+--FILE--
+<?php
+class DestructableObject
+{
+ public function __destruct()
+ {
+ echo "2\n";
+ }
+}
+
+class DestructorCreator
+{
+ public function __destruct()
+ {
+ $this->test = new DestructableObject;
+ echo "1\n";
+ }
+}
+
+class Test
+{
+ public static $mystatic;
+}
+
+// Uncomment this to avoid segfault
+//Test::$mystatic = new DestructorCreator();
+
+$x = new Test();
+
+if (!isset(Test::$mystatic))
+ Test::$mystatic = new DestructorCreator();
+
+echo "bla\n";
+?>
+--EXPECT--
+bla
+1
+2
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
index be30da3fc7..08f0e69406 100644
--- a/Zend/zend_opcode.c
+++ b/Zend/zend_opcode.c
@@ -166,7 +166,17 @@ ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC)
/* Note that only run-time accessed data need to be cleaned up, pre-defined data can
not contain objects and thus are not probelmatic */
zend_hash_apply(&(*pce)->function_table, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC);
- (*pce)->static_members_table = NULL;
+ if ((*pce)->static_members_table) {
+ int i;
+
+ for (i = 0; i < (*pce)->default_static_members_count; i++) {
+ if ((*pce)->static_members_table[i]) {
+ zval_ptr_dtor(&(*pce)->static_members_table[i]);
+ (*pce)->static_members_table[i] = NULL;
+ }
+ }
+ (*pce)->static_members_table = NULL;
+ }
} else if (CE_STATIC_MEMBERS(*pce)) {
int i;
@@ -255,7 +265,9 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce)
int i;
for (i = 0; i < ce->default_static_members_count; i++) {
- zval_ptr_dtor(&ce->default_static_members_table[i]);
+ if (ce->default_static_members_table[i]) {
+ zval_ptr_dtor(&ce->default_static_members_table[i]);
+ }
}
efree(ce->default_static_members_table);
}