]> granicus.if.org Git - php/commitdiff
Fixed bug #78344
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 29 Jul 2019 09:12:00 +0000 (11:12 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 29 Jul 2019 09:12:00 +0000 (11:12 +0200)
When performing a constant visibility check during compilation we
might be dealing with unlinked classes and as such should account
for the possibility of unresolved parents.

NEWS
Zend/tests/bug78344.phpt [new file with mode: 0644]
Zend/zend_compile.c

diff --git a/NEWS b/NEWS
index d04416d3471e9b2615c24b4c39ec4a786d502896..952071d36ffcb243f945c4328d14523d561c82d5 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ PHP                                                                        NEWS
 - Core:
   . Fixed bug #78340 (Include of stream wrapper not reading whole file).
     (Nikita)
+  . Fixed bug #78344 (Segmentation fault on zend_check_protected). (Nikita)
 
 - Iconv:
   . Fixed bug #78342 (Bus error in configure test for iconv //IGNORE). (Rainer
diff --git a/Zend/tests/bug78344.phpt b/Zend/tests/bug78344.phpt
new file mode 100644 (file)
index 0000000..c1ff5e0
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+Bug #78344: Segmentation fault on zend_check_protected
+--FILE--
+<?php
+
+class A {
+    protected const FOO = 1;
+}
+
+class B {}
+class C extends B {
+    public function method() {
+        var_dump(A::FOO);
+    }
+}
+(new C)->method();
+
+?>
+--EXPECTF--
+Fatal error: Uncaught Error: Cannot access protected const A::FOO in %s:%d
+Stack trace:
+#0 %s(%d): C->method()
+#1 {main}
+  thrown in %s on line %d
index 40b29058bc9a4ef765f7f2d74cf3e54b7d54b683..10a6b294f7acc3bb86095cc43279d1b170356356 100644 (file)
@@ -1410,6 +1410,36 @@ static zend_bool zend_try_compile_const_expr_resolve_class_name(zval *zv, zend_a
 }
 /* }}} */
 
+/* We don't use zend_verify_const_access because we need to deal with unlinked classes. */
+static zend_bool zend_verify_ct_const_access(zend_class_constant *c, zend_class_entry *scope)
+{
+       if (Z_ACCESS_FLAGS(c->value) & ZEND_ACC_PUBLIC) {
+               return 1;
+       } else if (Z_ACCESS_FLAGS(c->value) & ZEND_ACC_PRIVATE) {
+               return c->ce == scope;
+       } else {
+               zend_class_entry *ce = c->ce;
+               while (1) {
+                       if (ce == scope) {
+                               return 1;
+                       }
+                       if (!ce->parent) {
+                               break;
+                       }
+                       if (ce->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
+                               ce = ce->parent;
+                       } else {
+                               ce = zend_hash_find_ptr_lc(CG(class_table), ZSTR_VAL(ce->parent_name), ZSTR_LEN(ce->parent_name));
+                               if (!ce) {
+                                       break;
+                               }
+                       }
+               }
+               /* Reverse case cannot be true during compilation */
+               return 0;
+       }
+}
+
 static zend_bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, zend_string *name) /* {{{ */
 {
        uint32_t fetch_type = zend_get_class_fetch_type(class_name);
@@ -1433,7 +1463,7 @@ static zend_bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name,
                return 0;
        }
 
-       if (!cc || !zend_verify_const_access(cc, CG(active_class_entry))) {
+       if (!cc || !zend_verify_ct_const_access(cc, CG(active_class_entry))) {
                return 0;
        }