]> granicus.if.org Git - php/commitdiff
Fix infinite recursion in unlinked_instanceof
authorNikita Popov <nikita.ppv@gmail.com>
Tue, 5 Jan 2021 12:02:30 +0000 (13:02 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 5 Jan 2021 12:03:41 +0000 (13:03 +0100)
I suspect this is only a partial fix for the issue, it's probably
possible to recurse through a more complex pathway as well.

Fixes oss-fuzz #28961.

Zend/tests/type_declarations/variance/infinite_recursion.phpt [new file with mode: 0644]
Zend/zend_inheritance.c

diff --git a/Zend/tests/type_declarations/variance/infinite_recursion.phpt b/Zend/tests/type_declarations/variance/infinite_recursion.phpt
new file mode 100644 (file)
index 0000000..6eab6ff
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+Infinite recursion in unlinked_instanceof()
+--FILE--
+<?php
+interface I {}
+spl_autoload_register(function() {
+    class X {
+        function test(): I {}
+    }
+    class Y extends X {
+        function test(): C {}
+    }
+});
+class C extends Z implements C {}
+?>
+--EXPECTF--
+Fatal error: Declaration of Y::test(): C must be compatible with X::test(): I in %s on line %d
index 882738b75858134df06269c11f2aa036fa27042e..4b161692af7dd0fafd1ce448eec7ceb47b08d2e8 100644 (file)
@@ -311,7 +311,8 @@ static zend_bool unlinked_instanceof(zend_class_entry *ce1, zend_class_entry *ce
                                zend_class_entry *ce = zend_lookup_class_ex(
                                        ce1->interface_names[i].name, ce1->interface_names[i].lc_name,
                                        ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
-                               if (ce && unlinked_instanceof(ce, ce2)) {
+                               /* Avoid recursing if class implements ifself. */
+                               if (ce && ce != ce1 && unlinked_instanceof(ce, ce2)) {
                                        return 1;
                                }
                        }