]> granicus.if.org Git - php/commitdiff
Fixed bug #77631
authorTyson Andre <tysonandre775@hotmail.com>
Mon, 18 Feb 2019 14:35:45 +0000 (09:35 -0500)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 19 Feb 2019 09:07:40 +0000 (10:07 +0100)
Do not include unbound anonymous classes in get_declared_classes().

Note that earlier PHP versions would include the anonymous class in
get_declared_classes(), and return false until the class was bound,
but would not crash.

UPGRADING
Zend/zend_builtin_functions.c
ext/reflection/tests/ReflectionClass_isSubclassOf_error2.phpt [new file with mode: 0644]

index c1a3c19ff62586882b93b8ed1b898d65a55c5fbb..38c53cc87febf7e212ddbb6ae3a19d0983550a32 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -25,6 +25,8 @@ PHP 7.4 UPGRADE NOTES
   . Referencing parent:: inside a class that does not have a parent will now
     generate a compile-time error. Previously the error was only emitted at
     run-time.
+  . get_declared_classes() no longer returns anonymous classes that haven't
+    been instantiated yet.
 
 - Curl:
   . Attempting to serialize a CURLFile class will now generate an exception.
index 2b16991d1cb2067272721e2edc1351c81e455d3c..f588229affd94866a8f64edb8f0b14070685ec20 100644 (file)
@@ -1796,7 +1796,8 @@ ZEND_FUNCTION(get_declared_classes)
        ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), key, ce) {
                if (key
                 && ZSTR_VAL(key)[0] != 0
-                && !(ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT))) {
+                && !(ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT))
+                && (ce->ce_flags & ZEND_ACC_LINKED)) {
                        copy_class_or_interface_name(return_value, key, ce);
                }
        } ZEND_HASH_FOREACH_END();
diff --git a/ext/reflection/tests/ReflectionClass_isSubclassOf_error2.phpt b/ext/reflection/tests/ReflectionClass_isSubclassOf_error2.phpt
new file mode 100644 (file)
index 0000000..8671c25
--- /dev/null
@@ -0,0 +1,35 @@
+--TEST--
+ReflectionClass::isSubclassOf() - fixed crash for unbound anonymous class
+--FILE--
+<?php
+class X {
+    public static function main() {
+        return new class() extends Base {};
+    }
+}
+class Base {}
+$check = function () {
+    $base = Base::class;
+    foreach (get_declared_classes() as $class) {
+        if (strpos($class, 'class@anonymous') === false) {
+            continue;
+        }
+        echo "Checking for $class\n";
+        flush();
+        $rc = new ReflectionClass($class);
+        var_export($rc->isSubclassOf($base));
+        echo "\n";
+    }
+};
+// Should not show up in get_declared_classes until the anonymous class is bound.
+$check();
+echo "After first check\n";
+X::main();
+$check();
+echo "Done\n";
+?>
+--EXPECTF--
+After first check
+Checking for class@%s
+true
+Done