Check class linking in VERIFY_RETURN_TYPE optimization
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 25 Oct 2019 09:24:32 +0000 (11:24 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 25 Oct 2019 09:24:32 +0000 (11:24 +0200)
instanceof_function() requires linked classes. I'm not reusing
unlinked_instanceof() here, because it performs class loading,
which wouldn't be right here, I think.

ext/opcache/Optimizer/dfa_pass.c
ext/opcache/tests/verify_return_instanceof.phpt [new file with mode: 0644]

index 5401c9df6a78c9c6c1eecab8ba6b11dc32912854..4c2162a021076f32dfc060c75ee22a98e8bdb6ce 100644 (file)
@@ -306,6 +306,17 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op
        free_alloca(shiftlist, use_heap);
 }
 
+static zend_bool safe_instanceof(zend_class_entry *ce1, zend_class_entry *ce2) {
+       if (ce1 == ce2) {
+               return 1;
+       }
+       if (!(ce1->ce_flags & ZEND_ACC_LINKED)) {
+               /* This case could be generalized, similarly to unlinked_instanceof */
+               return 0;
+       }
+       return instanceof_function(ce1, ce2);
+}
+
 static inline zend_bool can_elide_return_type_check(
                zend_op_array *op_array, zend_ssa *ssa, zend_ssa_op *ssa_op) {
        zend_arg_info *info = &op_array->arg_info[-1];
@@ -327,7 +338,7 @@ static inline zend_bool can_elide_return_type_check(
        }
 
        if (ZEND_TYPE_IS_CLASS(info->type)) {
-               if (!use_info->ce || !def_info->ce || !instanceof_function(use_info->ce, def_info->ce)) {
+               if (!use_info->ce || !def_info->ce || !safe_instanceof(use_info->ce, def_info->ce)) {
                        return 0;
                }
        }
diff --git a/ext/opcache/tests/verify_return_instanceof.phpt b/ext/opcache/tests/verify_return_instanceof.phpt
new file mode 100644 (file)
index 0000000..14323d5
--- /dev/null
@@ -0,0 +1,19 @@
+--TEST--
+Instanceof checks in VERIFY_RETURN_TYPE optimization may deal with unlinked classes
+--FILE--
+<?php
+interface foo { }
+
+interface biz {}
+
+class qux implements foo {
+    public function bar(): biz {
+        $x = $this;
+        return $x;
+    }
+}
+
+?>
+===DONE===
+--EXPECT--
+===DONE===