]> granicus.if.org Git - php/commitdiff
Fixed bug #78937 (Preloading unlinkable anonymous class can segfault)
authorDmitry Stogov <dmitry@zend.com>
Tue, 10 Dec 2019 21:46:30 +0000 (00:46 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 10 Dec 2019 21:46:30 +0000 (00:46 +0300)
Zend/zend_compile.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/opcache/tests/bug78937_1.phpt [new file with mode: 0644]
ext/opcache/tests/bug78937_2.phpt [new file with mode: 0644]
ext/opcache/tests/bug78937_3.phpt [new file with mode: 0644]
ext/opcache/tests/bug78937_4.phpt [new file with mode: 0644]
ext/opcache/tests/bug78937_5.phpt [new file with mode: 0644]
ext/opcache/tests/bug78937_6.phpt [new file with mode: 0644]
ext/opcache/tests/preload_bug78937.inc [new file with mode: 0644]

index 7d35a92ade679d132c9435ff0b04b271968953a6..b6a120c94b2328bea8e2d603eaad4310d7018c93 100644 (file)
@@ -1068,8 +1068,12 @@ ZEND_API int do_bind_class(zval *lcname, zend_string *lc_parent_name) /* {{{ */
 
        if (UNEXPECTED(!zv)) {
                ce = zend_hash_find_ptr(EG(class_table), Z_STR_P(lcname));
-               ZEND_ASSERT(ce && "Class with lcname should be registered");
-               zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
+               if (ce) {
+                       zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
+               } else {
+                       ZEND_ASSERT(EG(current_execute_data)->func->op_array.fn_flags & ZEND_ACC_PRELOADED);
+                       zend_error_noreturn(E_ERROR, "Class %s wasn't preloaded", Z_STRVAL_P(lcname));
+               }
                return FAILURE;
        }
 
index b17020137258c75bdc6b86b509fb170e7fc37df2..87d475bf186191d72957873f23fcd248d01eeb40 100644 (file)
@@ -7306,6 +7306,11 @@ ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY, CACHE_SLOT)
        if (UNEXPECTED(ce == NULL)) {
                zend_string *rtd_key = Z_STR_P(RT_CONSTANT(opline, opline->op1));
                zv = zend_hash_find_ex(EG(class_table), rtd_key, 1);
+               if (UNEXPECTED(zv == NULL)) {
+                       SAVE_OPLINE();
+                       ZEND_ASSERT(EX(func)->op_array.fn_flags & ZEND_ACC_PRELOADED);
+                       zend_error_noreturn(E_ERROR, "Anonymous class wasn't preloaded");
+               }
                ZEND_ASSERT(zv != NULL);
                ce = Z_CE_P(zv);
                if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
index 3d10728415aa787d998d91cf3932bbb09597d79a..14e1314bcb4fa15230dba71484050d4a4827cd49 100644 (file)
@@ -2446,6 +2446,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ANON_CLASS_SPEC_HANDLE
        if (UNEXPECTED(ce == NULL)) {
                zend_string *rtd_key = Z_STR_P(RT_CONSTANT(opline, opline->op1));
                zv = zend_hash_find_ex(EG(class_table), rtd_key, 1);
+               if (UNEXPECTED(zv == NULL)) {
+                       SAVE_OPLINE();
+                       ZEND_ASSERT(EX(func)->op_array.fn_flags & ZEND_ACC_PRELOADED);
+                       zend_error_noreturn(E_ERROR, "Anonymous class wasn't preloaded");
+               }
                ZEND_ASSERT(zv != NULL);
                ce = Z_CE_P(zv);
                if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
diff --git a/ext/opcache/tests/bug78937_1.phpt b/ext/opcache/tests/bug78937_1.phpt
new file mode 100644 (file)
index 0000000..1125ad4
--- /dev/null
@@ -0,0 +1,22 @@
+--TEST--
+Bug #78937.1 (Preloading unlinkable anonymous class can segfault)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+opcache.preload={PWD}/preload_bug78937.inc
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class Bar {
+}
+var_dump(foo());
+?>
+--EXPECTF--
+Warning: Can't preload unlinked class Foo: Unknown parent Bar in %spreload_bug78937.inc on line 6
+
+Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3
+
+Fatal error: Anonymous class wasn't preloaded in %spreload_bug78937.inc on line 3
+
diff --git a/ext/opcache/tests/bug78937_2.phpt b/ext/opcache/tests/bug78937_2.phpt
new file mode 100644 (file)
index 0000000..8800632
--- /dev/null
@@ -0,0 +1,22 @@
+--TEST--
+Bug #78937.2 (Preloading unlinkable anonymous class can segfault)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+opcache.preload={PWD}/preload_bug78937.inc
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+include(__DIR__ . "/preload_bug78937.inc");
+class Bar {
+}
+var_dump(foo());
+?>
+--EXPECTF--
+Warning: Can't preload unlinked class Foo: Unknown parent Bar in %spreload_bug78937.inc on line 6
+
+Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3
+object(class@anonymous)#%d (0) {
+}
\ No newline at end of file
diff --git a/ext/opcache/tests/bug78937_3.phpt b/ext/opcache/tests/bug78937_3.phpt
new file mode 100644 (file)
index 0000000..1c706e2
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+Bug #78937.3 (Preloading unlinkable anonymous class can segfault)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+opcache.preload={PWD}/preload_bug78937.inc
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+include(__DIR__ . "/preload_bug78937.inc");
+var_dump(foo());
+?>
+--EXPECTF--
+Warning: Can't preload unlinked class Foo: Unknown parent Bar in %spreload_bug78937.inc on line 6
+
+Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3
+
+Fatal error: Uncaught Error: Class 'Bar' not found in %spreload_bug78937.inc:3
+Stack trace:
+#0 %sbug78937_3.php(3): foo()
+#1 {main}
+  thrown in %spreload_bug78937.inc on line 3
diff --git a/ext/opcache/tests/bug78937_4.phpt b/ext/opcache/tests/bug78937_4.phpt
new file mode 100644 (file)
index 0000000..b555516
--- /dev/null
@@ -0,0 +1,22 @@
+--TEST--
+Bug #78937.4 (Preloading unlinkable anonymous class can segfault)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+opcache.preload={PWD}/preload_bug78937.inc
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+class Bar {
+}
+bar();
+var_dump(new Foo);
+?>
+--EXPECTF--
+Warning: Can't preload unlinked class Foo: Unknown parent Bar in %spreload_bug78937.inc on line 6
+
+Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3
+
+Fatal error: Class foo wasn't preloaded in %spreload_bug78937.inc on line 6
\ No newline at end of file
diff --git a/ext/opcache/tests/bug78937_5.phpt b/ext/opcache/tests/bug78937_5.phpt
new file mode 100644 (file)
index 0000000..f9f01a2
--- /dev/null
@@ -0,0 +1,23 @@
+--TEST--
+Bug #78937.5 (Preloading unlinkable anonymous class can segfault)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+opcache.preload={PWD}/preload_bug78937.inc
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+include(__DIR__ . "/preload_bug78937.inc");
+class Bar {
+}
+bar();
+var_dump(new Foo);
+?>
+--EXPECTF--
+Warning: Can't preload unlinked class Foo: Unknown parent Bar in %spreload_bug78937.inc on line 6
+
+Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3
+object(Foo)#%d (0) {
+}
\ No newline at end of file
diff --git a/ext/opcache/tests/bug78937_6.phpt b/ext/opcache/tests/bug78937_6.phpt
new file mode 100644 (file)
index 0000000..28dcb0c
--- /dev/null
@@ -0,0 +1,25 @@
+--TEST--
+Bug #78937.6 (Preloading unlinkable anonymous class can segfault)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+opcache.preload={PWD}/preload_bug78937.inc
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+include(__DIR__ . "/preload_bug78937.inc");
+bar();
+var_dump(new Foo);
+?>
+--EXPECTF--
+Warning: Can't preload unlinked class Foo: Unknown parent Bar in %spreload_bug78937.inc on line 6
+
+Warning: Can't preload unlinked class class@anonymous: Unknown parent Bar in %spreload_bug78937.inc on line 3
+
+Fatal error: Uncaught Error: Class 'Bar' not found in %spreload_bug78937.inc:6
+Stack trace:
+#0 %sbug78937_6.php(3): bar()
+#1 {main}
+  thrown in %spreload_bug78937.inc on line 6
diff --git a/ext/opcache/tests/preload_bug78937.inc b/ext/opcache/tests/preload_bug78937.inc
new file mode 100644 (file)
index 0000000..7da2dc3
--- /dev/null
@@ -0,0 +1,8 @@
+<?php
+function foo() {
+    return new class extends Bar {};
+}
+function bar() {
+       class Foo extends Bar {
+       }
+}