]> granicus.if.org Git - php/commitdiff
Merge branch 'PHP-7.4'
authorNikita Popov <nikita.ppv@gmail.com>
Tue, 10 Dec 2019 12:07:04 +0000 (13:07 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 10 Dec 2019 12:12:29 +0000 (13:12 +0100)
* PHP-7.4:
  Add support for class_alias to preloading
  Fixed bug #78935: Check that all linked classes can be preloaded

1  2 
Zend/zend_compile.c
ext/opcache/ZendAccelerator.c
ext/opcache/tests/preload_009.phpt
ext/opcache/tests/preload_loadable_classes_2.phpt
ext/opcache/zend_persist.c
ext/opcache/zend_persist_calc.c

Simple merge
index c203a06a742a999d0691bf23dfd11bf33cf74c76,ccd300390fc69b471a466eb62cdb787bdfeda052..1b8080800aca3649cf5c8590b07dbcaabf2d45a1
@@@ -3935,6 -3850,108 +3935,117 @@@ static void preload_link(void
        } ZEND_HASH_FOREACH_END();
  }
  
 -                                              if (ZEND_TYPE_IS_NAME(prop->type)) {
+ #ifdef ZEND_WIN32
+ static void preload_check_windows_restriction(zend_class_entry *scope, zend_class_entry *ce) {
+       if (ce && ce->type == ZEND_INTERNAL_CLASS) {
+               zend_error_noreturn(E_ERROR,
+                       "Class %s uses internal class %s during preloading, which is not supported on Windows",
+                       ZSTR_VAL(scope->name), ZSTR_VAL(ce->name));
+       }
+ }
+ static void preload_check_windows_restrictions(zend_class_entry *scope) {
+       uint32_t i;
+       preload_check_windows_restriction(scope, scope->parent);
+       for (i = 0; i < scope->num_interfaces; i++) {
+               preload_check_windows_restriction(scope, scope->interfaces[i]);
+       }
+ }
+ #endif
+ static zend_class_entry *preload_load_prop_type(zend_property_info *prop, zend_string *name) {
+       zend_class_entry *ce;
+       if (zend_string_equals_literal_ci(name, "self")) {
+               ce = prop->ce;
+       } else if (zend_string_equals_literal_ci(name, "parent")) {
+               ce = prop->ce->parent;
+       } else {
+               ce = zend_lookup_class(name);
+       }
+       if (ce) {
+               return ce;
+       }
+       zend_error_noreturn(E_ERROR,
+               "Failed to load class %s used by typed property %s::$%s during preloading",
+               ZSTR_VAL(name), ZSTR_VAL(prop->ce->name), zend_get_unmangled_property_name(prop->name));
+       return ce;
+ }
+ static void preload_ensure_classes_loadable() {
+       /* Run this in a loop, because additional classes may be loaded while updating constants etc. */
+       uint32_t checked_classes_idx = 0;
+       while (1) {
+               zend_class_entry *ce;
+               uint32_t num_classes = zend_hash_num_elements(EG(class_table));
+               if (num_classes == checked_classes_idx) {
+                       return;
+               }
+               ZEND_HASH_REVERSE_FOREACH_PTR(EG(class_table), ce) {
+                       if (ce->type == ZEND_INTERNAL_CLASS || _idx == checked_classes_idx) {
+                               break;
+                       }
+                       if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
+                               /* Only require that already linked classes are loadable, we'll properly check
+                                * things when linking additional classes. */
+                               continue;
+                       }
+ #ifdef ZEND_WIN32
+                       preload_check_windows_restrictions(ce);
+ #endif
+                       if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
+                               int result = SUCCESS;
+                               zend_try {
+                                       result = zend_update_class_constants(ce);
+                               } zend_catch {
+                                       /* Provide some context for the generated error. */
+                                       zend_error_noreturn(E_ERROR,
+                                               "Error generated while resolving initializers of class %s during preloading",
+                                               ZSTR_VAL(ce->name));
+                               } zend_end_try();
+                               if (result == FAILURE) {
+                                       /* Just present to be safe: We generally always throw some
+                                        * other fatal error as part of update_class_constants(). */
+                                       zend_error_noreturn(E_ERROR,
+                                               "Failed to resolve initializers of class %s during preloading",
+                                               ZSTR_VAL(ce->name));
+                               }
+                               ZEND_ASSERT(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED);
+                       }
+                       if (!(ce->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
+                               if (ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) {
+                                       zend_property_info *prop;
+                                       ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
 -                                                      prop->type = ZEND_TYPE_ENCODE_CE(ce, ZEND_TYPE_ALLOW_NULL(prop->type));
++                                              if (ZEND_TYPE_HAS_LIST(prop->type)) {
++                                                      void **entry;
++                                                      ZEND_TYPE_LIST_FOREACH_PTR(ZEND_TYPE_LIST(prop->type), entry) {
++                                                              if (ZEND_TYPE_LIST_IS_NAME(*entry)) {
++                                                                      zend_class_entry *ce = preload_load_prop_type(
++                                                                              prop, ZEND_TYPE_LIST_GET_NAME(*entry));
++                                                                      *entry = ZEND_TYPE_LIST_ENCODE_CE(ce);
++                                                              }
++                                                      } ZEND_TYPE_LIST_FOREACH_END();
++                                              } else if (ZEND_TYPE_HAS_NAME(prop->type)) {
+                                                       zend_class_entry *ce =
+                                                               preload_load_prop_type(prop, ZEND_TYPE_NAME(prop->type));
++                                                      ZEND_TYPE_SET_CE(prop->type, ce);
+                                               }
+                                       } ZEND_HASH_FOREACH_END();
+                               }
+                               ce->ce_flags |= ZEND_ACC_PROPERTY_TYPES_RESOLVED;
+                       }
+               } ZEND_HASH_FOREACH_END();
+               checked_classes_idx = num_classes;
+       }
+ }
  static zend_string *preload_resolve_path(zend_string *filename)
  {
        if (is_stream_path(ZSTR_VAL(filename))) {
index 84f444768c022a064a7980ba3b148e6cef0890e2,1adbf5b00649f53b4640575a4c1e07081fd3ae74..d0c762c801dcc6f4318b46edb9da067122543d79
@@@ -13,6 -13,6 +13,6 @@@ var_dump(trait_exists('T'))
  var_dump(class_exists('Foo'));
  ?>
  --EXPECTF--
- Warning: Can't preload class Foo with unresolved initializer for constant C in %spreload_undef_const_2.inc on line 8
 -Warning: Use of undefined constant UNDEF - assumed 'UNDEF' (this will throw an Error in a future version of PHP) in Unknown on line 0
--bool(true)
- bool(false)
 -bool(true)
++Fatal error: Undefined constant 'UNDEF' in Unknown on line 0
++
++Fatal error: Error generated while resolving initializers of class Foo during preloading in Unknown on line 0
index 0000000000000000000000000000000000000000,4a5d2b8a667a080e6d316dd5852c6f924cf11b53..17100ff64f4375c5904cf51c9f9970d8b42e92aa
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,17 +1,15 @@@
 -Warning: Use of undefined constant UNDEF - assumed 'UNDEF' (this will throw an Error in a future version of PHP) in Unknown on line 0
 -
 -Fatal error: Class 'Foo' not found in Unknown on line 0
+ --TEST--
+ Preloading: Loadable class checking (2)
+ --INI--
+ opcache.enable=1
+ opcache.enable_cli=1
+ opcache.optimization_level=-1
+ opcache.preload={PWD}/preload_loadable_classes_2.inc
+ --SKIPIF--
+ <?php require_once('skipif.inc'); ?>
+ --FILE--
+ Unreachable
+ --EXPECTF--
++Fatal error: Undefined constant 'UNDEF' in Unknown on line 0
+ Fatal error: Error generated while resolving initializers of class Test during preloading in Unknown on line 0
Simple merge
Simple merge