]> granicus.if.org Git - php/commitdiff
Improve unlinked class diagnostics during preloading
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 3 Jul 2019 12:05:10 +0000 (14:05 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 3 Jul 2019 12:05:10 +0000 (14:05 +0200)
ext/opcache/ZendAccelerator.c
ext/opcache/tests/bug78014.phpt
ext/opcache/tests/preload_011.phpt

index ee9f45609b1c420432927f9812f55cbafb05de81..e41ef6725ddc13b28e7cda624ebaa8ce7fd0203b 100644 (file)
@@ -3350,6 +3350,63 @@ static void get_unresolved_initializer(zend_class_entry *ce, const char **kind,
        } ZEND_HASH_FOREACH_END();
 }
 
+static zend_bool preload_all_types_known(zend_class_entry *ce);
+static void get_unlinked_dependency(zend_class_entry *ce, const char **kind, const char **name) {
+       zend_class_entry *p;
+       *kind = "Unknown reason";
+       *name = "";
+
+       if (ce->parent_name) {
+               zend_string *key = zend_string_tolower(ce->parent_name);
+               p = zend_hash_find_ptr(EG(class_table), key);
+               zend_string_release(key);
+               if (!p) {
+                       *kind = "Unknown parent ";
+                       *name = ZSTR_VAL(ce->parent_name);
+                       return;
+               }
+               if (!(p->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
+                       *kind = "Parent with unresolved initializers ";
+                       *name = ZSTR_VAL(ce->parent_name);
+                       return;
+               }
+               if (!(p->ce_flags & ZEND_ACC_PROPERTY_TYPES_RESOLVED)) {
+                       *kind = "Parent with unresolved property types ";
+                       *name = ZSTR_VAL(ce->parent_name);
+                       return;
+               }
+       }
+
+       if (ce->num_interfaces) {
+               uint32_t i;
+               for (i = 0; i < ce->num_interfaces; i++) {
+                       p = zend_hash_find_ptr(EG(class_table), ce->interface_names[i].lc_name);
+                       if (!p) {
+                               *kind = "Unknown interface ";
+                               *name = ZSTR_VAL(ce->interface_names[i].name);
+                               return;
+                       }
+               }
+       }
+
+       if (ce->num_traits) {
+               uint32_t i;
+               for (i = 0; i < ce->num_traits; i++) {
+                       p = zend_hash_find_ptr(EG(class_table), ce->trait_names[i].lc_name);
+                       if (!p) {
+                               *kind = "Unknown trait ";
+                               *name = ZSTR_VAL(ce->trait_names[i].name);
+                               return;
+                       }
+               }
+       }
+
+       if (!preload_all_types_known(ce)) {
+               *kind = "Unknown type dependencies";
+               return;
+       }
+}
+
 static zend_bool preload_try_resolve_constants(zend_class_entry *ce)
 {
        zend_bool ok, changed;
@@ -3650,9 +3707,12 @@ static void preload_link(void)
                                        E_WARNING, ZSTR_VAL(ce->info.user.filename), ce->info.user.line_start,
                                        "Can't preload already declared class %s", ZSTR_VAL(ce->name));
                        } else {
+                               const char *kind, *name;
+                               get_unlinked_dependency(ce, &kind, &name);
                                zend_error_at(
                                        E_WARNING, ZSTR_VAL(ce->info.user.filename), ce->info.user.line_start,
-                                       "Can't preload unlinked class %s", ZSTR_VAL(ce->name));
+                                       "Can't preload unlinked class %s: %s%s",
+                                       ZSTR_VAL(ce->name), kind, name);
                        }
                        zend_string_release(key);
                } else if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
index 234d33ae27ac0a2e16d1ee6fb637a2c8e8869b1c..14f205e7b890e121935a70e3164517083e877aea 100644 (file)
@@ -16,7 +16,7 @@ $c = new C;
 var_dump($c->foo());
 ?>
 --EXPECTF--
-Warning: Can't preload unlinked class C in %s on line %d
+Warning: Can't preload unlinked class C: Parent with unresolved initializers B in %s on line %d
 
 Warning: Can't preload class B with unresolved initializer for constant X in %s on line %d
 
index 438cd805001a17e3c851a4f5d2dab1cb2e477349..32863398a952f2fefb48678f6210162e85e8eef5 100644 (file)
@@ -22,9 +22,9 @@ $g = new G;
 ?>
 ===DONE===
 --EXPECTF--
-Warning: Can't preload unlinked class H in %s on line %d
+Warning: Can't preload unlinked class H: Unknown type dependencies in %s on line %d
 
-Warning: Can't preload unlinked class B in %s on line %d
+Warning: Can't preload unlinked class B: Unknown type dependencies in %s on line %d
 
-Warning: Can't preload unlinked class A in %s on line %d
+Warning: Can't preload unlinked class A: Unknown type dependencies in %s on line %d
 ===DONE===