From 20ef51db22c46fd45976eb6d0b780c14022c8873 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 11 Dec 2019 00:46:30 +0300 Subject: [PATCH] Fixed bug #78937 (Preloading unlinkable anonymous class can segfault) --- Zend/zend_compile.c | 8 ++++++-- Zend/zend_vm_def.h | 5 +++++ Zend/zend_vm_execute.h | 5 +++++ ext/opcache/tests/bug78937_1.phpt | 22 ++++++++++++++++++++++ ext/opcache/tests/bug78937_2.phpt | 22 ++++++++++++++++++++++ ext/opcache/tests/bug78937_3.phpt | 24 ++++++++++++++++++++++++ ext/opcache/tests/bug78937_4.phpt | 22 ++++++++++++++++++++++ ext/opcache/tests/bug78937_5.phpt | 23 +++++++++++++++++++++++ ext/opcache/tests/bug78937_6.phpt | 25 +++++++++++++++++++++++++ ext/opcache/tests/preload_bug78937.inc | 8 ++++++++ 10 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 ext/opcache/tests/bug78937_1.phpt create mode 100644 ext/opcache/tests/bug78937_2.phpt create mode 100644 ext/opcache/tests/bug78937_3.phpt create mode 100644 ext/opcache/tests/bug78937_4.phpt create mode 100644 ext/opcache/tests/bug78937_5.phpt create mode 100644 ext/opcache/tests/bug78937_6.phpt create mode 100644 ext/opcache/tests/preload_bug78937.inc diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 7d35a92ade6..b6a120c94b2 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -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; } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index b1702013725..87d475bf186 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -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)) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 3d10728415a..14e1314bcb4 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -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 index 00000000000..1125ad4eb04 --- /dev/null +++ b/ext/opcache/tests/bug78937_1.phpt @@ -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-- + +--FILE-- + +--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 index 00000000000..880063298bf --- /dev/null +++ b/ext/opcache/tests/bug78937_2.phpt @@ -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-- + +--FILE-- + +--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 index 00000000000..1c706e237dc --- /dev/null +++ b/ext/opcache/tests/bug78937_3.phpt @@ -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-- + +--FILE-- + +--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 index 00000000000..b555516d008 --- /dev/null +++ b/ext/opcache/tests/bug78937_4.phpt @@ -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-- + +--FILE-- + +--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 index 00000000000..f9f01a2a261 --- /dev/null +++ b/ext/opcache/tests/bug78937_5.phpt @@ -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-- + +--FILE-- + +--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 index 00000000000..28dcb0ce538 --- /dev/null +++ b/ext/opcache/tests/bug78937_6.phpt @@ -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-- + +--FILE-- + +--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 index 00000000000..7da2dc32271 --- /dev/null +++ b/ext/opcache/tests/preload_bug78937.inc @@ -0,0 +1,8 @@ +