summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/zend.c1
-rw-r--r--Zend/zend.h3
-rw-r--r--Zend/zend_compile.c16
-rw-r--r--Zend/zend_vm_def.h13
-rw-r--r--Zend/zend_vm_execute.h13
-rw-r--r--ext/opcache/ZendAccelerator.c30
-rw-r--r--ext/opcache/tests/bug78937_1.phpt5
-rw-r--r--ext/opcache/tests/bug78937_4.phpt4
8 files changed, 73 insertions, 12 deletions
diff --git a/Zend/zend.c b/Zend/zend.c
index 97ac3327ca..a9ae03e624 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -81,6 +81,7 @@ ZEND_API char *(*zend_getenv)(char *name, size_t name_len);
ZEND_API zend_string *(*zend_resolve_path)(const char *filename, size_t filename_len);
ZEND_API int (*zend_post_startup_cb)(void) = NULL;
ZEND_API void (*zend_post_shutdown_cb)(void) = NULL;
+ZEND_API int (*zend_preload_autoload)(zend_string *filename) = NULL;
void (*zend_on_timeout)(int seconds);
diff --git a/Zend/zend.h b/Zend/zend.h
index 9aefc8d26a..94fd9a3559 100644
--- a/Zend/zend.h
+++ b/Zend/zend.h
@@ -292,6 +292,9 @@ extern ZEND_API zend_string *(*zend_resolve_path)(const char *filename, size_t f
extern ZEND_API int (*zend_post_startup_cb)(void);
extern ZEND_API void (*zend_post_shutdown_cb)(void);
+/* Callback for loading of not preloaded part of the script */
+extern ZEND_API int (*zend_preload_autoload)(zend_string *filename);
+
ZEND_API ZEND_COLD void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
/* If filename is NULL the default filename is used. */
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 5661f26439..970011ac08 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -1072,11 +1072,21 @@ ZEND_API int do_bind_class(zval *lcname, zend_string *lc_parent_name) /* {{{ */
ce = zend_hash_find_ptr(EG(class_table), Z_STR_P(lcname));
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));
+ return FAILURE;
} 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));
+ do {
+ if (zend_preload_autoload
+ && zend_preload_autoload(EG(current_execute_data)->func->op_array.filename) == SUCCESS) {
+ zv = zend_hash_find_ex(EG(class_table), Z_STR_P(rtd_key), 1);
+ if (EXPECTED(zv != NULL)) {
+ break;
+ }
+ }
+ 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;
+ } while (0);
}
- return FAILURE;
}
/* Register the derived class */
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 0282c3c584..bb6a300a60 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -7317,8 +7317,17 @@ ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY, CACHE_SLOT)
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");
+ do {
+ if (zend_preload_autoload
+ && zend_preload_autoload(EX(func)->op_array.filename) == SUCCESS) {
+ zv = zend_hash_find_ex(EG(class_table), rtd_key, 1);
+ if (EXPECTED(zv != NULL)) {
+ break;
+ }
+ }
+ ZEND_ASSERT(EX(func)->op_array.fn_flags & ZEND_ACC_PRELOADED);
+ zend_error_noreturn(E_ERROR, "Anonymous class wasn't preloaded");
+ } while (0);
}
ZEND_ASSERT(zv != NULL);
ce = Z_CE_P(zv);
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index d79bdb1c1f..722053bbdc 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -2449,8 +2449,17 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ANON_CLASS_SPEC_HANDLE
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");
+ do {
+ if (zend_preload_autoload
+ && zend_preload_autoload(EX(func)->op_array.filename) == SUCCESS) {
+ zv = zend_hash_find_ex(EG(class_table), rtd_key, 1);
+ if (EXPECTED(zv != NULL)) {
+ break;
+ }
+ }
+ ZEND_ASSERT(EX(func)->op_array.fn_flags & ZEND_ACC_PRELOADED);
+ zend_error_noreturn(E_ERROR, "Anonymous class wasn't preloaded");
+ } while (0);
}
ZEND_ASSERT(zv != NULL);
ce = Z_CE_P(zv);
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c
index 758f8fc4bf..3319f719ec 100644
--- a/ext/opcache/ZendAccelerator.c
+++ b/ext/opcache/ZendAccelerator.c
@@ -4242,6 +4242,34 @@ static void preload_load(void)
}
}
+static int preload_autoload(zend_string *filename)
+{
+ zend_persistent_script *persistent_script;
+ zend_op_array *op_array;
+
+ if (zend_hash_exists(&EG(included_files), filename)) {
+ return FAILURE;
+ }
+
+ persistent_script = zend_accel_hash_find(&ZCSG(hash), filename);
+ if (!persistent_script) {
+ return FAILURE;
+ }
+
+ op_array = zend_accel_load_script(persistent_script, 1);
+ if (!op_array) {
+ return FAILURE;
+ }
+
+ // TODO: we may need to execute this in some special context ???
+ zend_execute(op_array, NULL);
+
+ destroy_op_array(op_array);
+ efree_size(op_array, sizeof(zend_op_array));
+
+ return SUCCESS;
+}
+
static int accel_preload(const char *config)
{
zend_file_handle file_handle;
@@ -4534,6 +4562,8 @@ static int accel_preload(const char *config)
HANDLE_UNBLOCK_INTERRUPTIONS();
zend_shared_alloc_destroy_xlat_table();
+
+ zend_preload_autoload = preload_autoload;
} else {
CG(map_ptr_last) = orig_map_ptr_last;
}
diff --git a/ext/opcache/tests/bug78937_1.phpt b/ext/opcache/tests/bug78937_1.phpt
index bc285f107b..2745fde72c 100644
--- a/ext/opcache/tests/bug78937_1.phpt
+++ b/ext/opcache/tests/bug78937_1.phpt
@@ -20,6 +20,5 @@ var_dump(foo());
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
-
+object(class@anonymous)#%d (0) {
+}
diff --git a/ext/opcache/tests/bug78937_4.phpt b/ext/opcache/tests/bug78937_4.phpt
index 2ad86870de..3652d6de52 100644
--- a/ext/opcache/tests/bug78937_4.phpt
+++ b/ext/opcache/tests/bug78937_4.phpt
@@ -21,5 +21,5 @@ var_dump(new Foo);
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
+object(Foo)#%d (0) {
+}