PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - Zend - zend_object_handlers.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 780 837 93.2 %
Date: 2016-09-27 Functions: 34 34 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 2.00 of the Zend license,     |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.zend.com/license/2_00.txt.                                |
      11             :    | If you did not receive a copy of the Zend license and are unable to  |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@zend.com so we can mail you a copy immediately.              |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Andi Gutmans <andi@zend.com>                                |
      16             :    |          Zeev Suraski <zeev@zend.com>                                |
      17             :    |          Dmitry Stogov <dmitry@zend.com>                             |
      18             :    +----------------------------------------------------------------------+
      19             : */
      20             : 
      21             : /* $Id$ */
      22             : 
      23             : #include "zend.h"
      24             : #include "zend_globals.h"
      25             : #include "zend_variables.h"
      26             : #include "zend_API.h"
      27             : #include "zend_objects.h"
      28             : #include "zend_objects_API.h"
      29             : #include "zend_object_handlers.h"
      30             : #include "zend_interfaces.h"
      31             : #include "zend_exceptions.h"
      32             : #include "zend_closures.h"
      33             : #include "zend_compile.h"
      34             : #include "zend_hash.h"
      35             : 
      36             : #define DEBUG_OBJECT_HANDLERS 0
      37             : 
      38             : /* guard flags */
      39             : #define IN_GET          (1<<0)
      40             : #define IN_SET          (1<<1)
      41             : #define IN_UNSET        (1<<2)
      42             : #define IN_ISSET        (1<<3)
      43             : 
      44             : #define Z_OBJ_PROTECT_RECURSION(zval_p) \
      45             :         do { \
      46             :                 if (Z_OBJ_APPLY_COUNT_P(zval_p) >= 3) { \
      47             :                         zend_error_noreturn(E_ERROR, "Nesting level too deep - recursive dependency?"); \
      48             :                 } \
      49             :                 Z_OBJ_INC_APPLY_COUNT_P(zval_p); \
      50             :         } while (0)
      51             : 
      52             : 
      53             : #define Z_OBJ_UNPROTECT_RECURSION(zval_p) \
      54             :         Z_OBJ_DEC_APPLY_COUNT_P(zval_p)
      55             : 
      56             : /*
      57             :   __X accessors explanation:
      58             : 
      59             :   if we have __get and property that is not part of the properties array is
      60             :   requested, we call __get handler. If it fails, we return uninitialized.
      61             : 
      62             :   if we have __set and property that is not part of the properties array is
      63             :   set, we call __set handler. If it fails, we do not change the array.
      64             : 
      65             :   for both handlers above, when we are inside __get/__set, no further calls for
      66             :   __get/__set for this property of this object will be made, to prevent endless
      67             :   recursion and enable accessors to change properties array.
      68             : 
      69             :   if we have __call and method which is not part of the class function table is
      70             :   called, we cal __call handler.
      71             : */
      72             : 
      73      629764 : ZEND_API void rebuild_object_properties(zend_object *zobj) /* {{{ */
      74             : {
      75      629764 :         if (!zobj->properties) {
      76             :                 zend_property_info *prop_info;
      77      629764 :                 zend_class_entry *ce = zobj->ce;
      78             : 
      79      629764 :                 ALLOC_HASHTABLE(zobj->properties);
      80      629764 :                 zend_hash_init(zobj->properties, ce->default_properties_count, NULL, ZVAL_PTR_DTOR, 0);
      81      629764 :                 if (ce->default_properties_count) {
      82       12313 :                         zend_hash_real_init(zobj->properties, 0);
      83       12313 :                         zobj->properties->nInternalPointer = 0;
      84       47293 :                         ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
      85       17488 :                                 if (/*prop_info->ce == ce &&*/
      86       17488 :                                     (prop_info->flags & ZEND_ACC_STATIC) == 0) {
      87             : 
      88       34922 :                                         if (UNEXPECTED(Z_TYPE_P(OBJ_PROP(zobj, prop_info->offset)) == IS_UNDEF)) {
      89          13 :                                                 zobj->properties->u.v.flags |= HASH_FLAG_HAS_EMPTY_IND;
      90             :                                         }
      91             : 
      92       17461 :                                         _zend_hash_append_ind(zobj->properties, prop_info->name, 
      93             :                                                 OBJ_PROP(zobj, prop_info->offset));
      94             :                                 }
      95             :                         } ZEND_HASH_FOREACH_END();
      96       25629 :                         while (ce->parent && ce->parent->default_properties_count) {
      97        1003 :                                 ce = ce->parent;
      98        9705 :                                 ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop_info) {
      99       12764 :                                         if (prop_info->ce == ce &&
     100        4212 :                                             (prop_info->flags & ZEND_ACC_STATIC) == 0 &&
     101        4201 :                                             (prop_info->flags & ZEND_ACC_PRIVATE) != 0) {
     102             :                                                 zval zv;
     103             : 
     104        3040 :                                                 if (UNEXPECTED(Z_TYPE_P(OBJ_PROP(zobj, prop_info->offset)) == IS_UNDEF)) {
     105           2 :                                                         zobj->properties->u.v.flags |= HASH_FLAG_HAS_EMPTY_IND;
     106             :                                                 }
     107             : 
     108        1520 :                                                 ZVAL_INDIRECT(&zv, OBJ_PROP(zobj, prop_info->offset));
     109        1520 :                                                 zend_hash_add(zobj->properties, prop_info->name, &zv);
     110             :                                         }
     111             :                                 } ZEND_HASH_FOREACH_END();
     112             :                         }
     113             :                 }
     114             :         }
     115      629764 : }
     116             : /* }}} */
     117             : 
     118      487100 : ZEND_API HashTable *zend_std_get_properties(zval *object) /* {{{ */
     119             : {
     120             :         zend_object *zobj;
     121      487100 :         zobj = Z_OBJ_P(object);
     122      487100 :         if (!zobj->properties) {
     123      221242 :                 rebuild_object_properties(zobj);
     124             :         }
     125      487100 :         return zobj->properties;
     126             : }
     127             : /* }}} */
     128             : 
     129     1010210 : ZEND_API HashTable *zend_std_get_gc(zval *object, zval **table, int *n) /* {{{ */
     130             : {
     131     1010210 :         if (Z_OBJ_HANDLER_P(object, get_properties) != zend_std_get_properties) {
     132           0 :                 *table = NULL;
     133           0 :                 *n = 0;
     134           0 :                 return Z_OBJ_HANDLER_P(object, get_properties)(object);
     135             :         } else {
     136     1010210 :                 zend_object *zobj = Z_OBJ_P(object);
     137             : 
     138     1010210 :                 if (zobj->properties) {
     139      410061 :                         *table = NULL;
     140      410061 :                         *n = 0;
     141      410061 :                         return zobj->properties;
     142             :                 } else {
     143      600149 :                         *table = zobj->properties_table;
     144      600149 :                         *n = zobj->ce->default_properties_count;
     145      600149 :                         return NULL;
     146             :                 }
     147             :         }
     148             : }
     149             : /* }}} */
     150             : 
     151        3705 : ZEND_API HashTable *zend_std_get_debug_info(zval *object, int *is_temp) /* {{{ */
     152             : {
     153        3705 :         zend_class_entry *ce = Z_OBJCE_P(object);
     154             :         zval retval;
     155             :         HashTable *ht;
     156             : 
     157        3705 :         if (!ce->__debugInfo) {
     158        3690 :                 *is_temp = 0;
     159        7380 :                 return Z_OBJ_HANDLER_P(object, get_properties)
     160        3690 :                         ? Z_OBJ_HANDLER_P(object, get_properties)(object)
     161             :                         : NULL;
     162             :         }
     163             : 
     164          15 :         zend_call_method_with_0_params(object, ce, &ce->__debugInfo, ZEND_DEBUGINFO_FUNC_NAME, &retval);
     165          15 :         if (Z_TYPE(retval) == IS_ARRAY) {
     166           3 :                 if (Z_IMMUTABLE(retval)) {
     167           0 :                         *is_temp = 1;
     168           0 :                         return zend_array_dup(Z_ARRVAL(retval));
     169           3 :                 } else if (Z_REFCOUNT(retval) <= 1) {
     170           1 :                         *is_temp = 1;
     171           1 :                         ht = Z_ARR(retval);
     172           1 :                         return ht;
     173             :                 } else {
     174           2 :                         *is_temp = 0;
     175           2 :                         zval_ptr_dtor(&retval);
     176           2 :                         return Z_ARRVAL(retval);
     177             :                 }
     178          12 :         } else if (Z_TYPE(retval) == IS_NULL) {
     179           1 :                 *is_temp = 1;
     180           1 :                 ALLOC_HASHTABLE(ht);
     181           1 :                 zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0);
     182           1 :                 return ht;
     183             :         }
     184             : 
     185          11 :         zend_clear_exception();
     186          11 :         zend_error_noreturn(E_ERROR, ZEND_DEBUGINFO_FUNC_NAME "() must return an array");
     187             : 
     188             :         return NULL; /* Compilers are dumb and don't understand that noreturn means that the function does NOT need a return value... */
     189             : }
     190             : /* }}} */
     191             : 
     192         162 : static void zend_std_call_getter(zval *object, zval *member, zval *retval) /* {{{ */
     193             : {
     194         162 :         zend_class_entry *ce = Z_OBJCE_P(object);
     195         162 :         zend_class_entry *orig_fake_scope = EG(fake_scope);
     196             : 
     197         162 :         EG(fake_scope) = NULL;
     198             : 
     199             :         /* __get handler is called with one argument:
     200             :               property name
     201             : 
     202             :            it should return whether the call was successful or not
     203             :         */
     204         162 :         zend_call_method_with_1_params(object, ce, &ce->__get, ZEND_GET_FUNC_NAME, retval, member);
     205             : 
     206         162 :         EG(fake_scope) = orig_fake_scope;
     207         162 : }
     208             : /* }}} */
     209             : 
     210         103 : static int zend_std_call_setter(zval *object, zval *member, zval *value) /* {{{ */
     211             : {
     212             :         zval retval;
     213             :         int result;
     214         103 :         zend_class_entry *ce = Z_OBJCE_P(object);
     215         103 :         zend_class_entry *orig_fake_scope = EG(fake_scope);
     216             : 
     217         103 :         EG(fake_scope) = NULL;
     218             : 
     219             :         /* __set handler is called with two arguments:
     220             :              property name
     221             :              value to be set
     222             : 
     223             :            it should return whether the call was successful or not
     224             :         */
     225         103 :         zend_call_method_with_2_params(object, ce, &ce->__set, ZEND_SET_FUNC_NAME, &retval, member, value);
     226             : 
     227         103 :         if (Z_TYPE(retval) != IS_UNDEF) {
     228         102 :                 result = i_zend_is_true(&retval) ? SUCCESS : FAILURE;
     229         102 :                 zval_ptr_dtor(&retval);
     230         102 :                 EG(fake_scope) = orig_fake_scope;
     231         102 :                 return result;
     232             :         } else {
     233           1 :                 EG(fake_scope) = orig_fake_scope;
     234           1 :                 return FAILURE;
     235             :         }
     236             : }
     237             : /* }}} */
     238             : 
     239           8 : static void zend_std_call_unsetter(zval *object, zval *member) /* {{{ */
     240             : {
     241           8 :         zend_class_entry *ce = Z_OBJCE_P(object);
     242           8 :         zend_class_entry *orig_fake_scope = EG(fake_scope);
     243             : 
     244           8 :         EG(fake_scope) = NULL;
     245             : 
     246             :         /* __unset handler is called with one argument:
     247             :               property name
     248             :         */
     249             : 
     250           8 :         if (Z_REFCOUNTED_P(member)) Z_ADDREF_P(member);
     251             : 
     252           8 :         zend_call_method_with_1_params(object, ce, &ce->__unset, ZEND_UNSET_FUNC_NAME, NULL, member);
     253             : 
     254           8 :         zval_ptr_dtor(member);
     255             : 
     256           8 :         EG(fake_scope) = orig_fake_scope;
     257           8 : }
     258             : /* }}} */
     259             : 
     260          39 : static void zend_std_call_issetter(zval *object, zval *member, zval *retval) /* {{{ */
     261             : {
     262          39 :         zend_class_entry *ce = Z_OBJCE_P(object);
     263          39 :         zend_class_entry *orig_fake_scope = EG(fake_scope);
     264             : 
     265          39 :         EG(fake_scope) = NULL;
     266             : 
     267             :         /* __isset handler is called with one argument:
     268             :               property name
     269             : 
     270             :            it should return whether the property is set or not
     271             :         */
     272             : 
     273          39 :         if (Z_REFCOUNTED_P(member)) Z_ADDREF_P(member);
     274             : 
     275          39 :         zend_call_method_with_1_params(object, ce, &ce->__isset, ZEND_ISSET_FUNC_NAME, retval, member);
     276             : 
     277          39 :         zval_ptr_dtor(member);
     278             : 
     279          39 :         EG(fake_scope) = orig_fake_scope;
     280          39 : }
     281             : /* }}} */
     282             : 
     283             : static zend_always_inline int zend_verify_property_access(zend_property_info *property_info, zend_class_entry *ce) /* {{{ */
     284             : {
     285             :         zend_class_entry *scope;
     286             : 
     287       40650 :         if (property_info->flags & ZEND_ACC_PUBLIC) {
     288       19599 :                 return 1;
     289       21051 :         } else if (property_info->flags & ZEND_ACC_PRIVATE) {
     290        4763 :                 if (EG(fake_scope)) {
     291        3200 :                         scope = EG(fake_scope);
     292             :                 } else {
     293        1563 :                         scope = zend_get_executed_scope();
     294             :                 }
     295        4763 :                 return (ce == scope || property_info->ce == scope);
     296       16288 :         } else if (property_info->flags & ZEND_ACC_PROTECTED) {
     297       16287 :                 if (EG(fake_scope)) {
     298       15489 :                         scope = EG(fake_scope);
     299             :                 } else {
     300         798 :                         scope = zend_get_executed_scope();
     301             :                 }
     302       16287 :                 return zend_check_protected(property_info->ce, scope);
     303             :         }
     304           1 :         return 0;
     305             : }
     306             : /* }}} */
     307             : 
     308             : static zend_always_inline zend_bool is_derived_class(zend_class_entry *child_class, zend_class_entry *parent_class) /* {{{ */
     309             : {
     310        4457 :         child_class = child_class->parent;
     311        6235 :         while (child_class) {
     312        5349 :                 if (child_class == parent_class) {
     313        3571 :                         return 1;
     314             :                 }
     315        1778 :                 child_class = child_class->parent;
     316             :         }
     317             : 
     318         886 :         return 0;
     319             : }
     320             : /* }}} */
     321             : 
     322             : static zend_always_inline uint32_t zend_get_property_offset(zend_class_entry *ce, zend_string *member, int silent, void **cache_slot) /* {{{ */
     323             : {
     324             :         zval *zv;
     325      476094 :         zend_property_info *property_info = NULL;
     326             :         uint32_t flags;
     327             :         zend_class_entry *scope;
     328             : 
     329      476094 :         if (cache_slot && EXPECTED(ce == CACHED_PTR_EX(cache_slot))) {
     330        4561 :                 return (uint32_t)(intptr_t)CACHED_PTR_EX(cache_slot + 1);
     331             :         }
     332             : 
     333      471533 :         if (UNEXPECTED(ZSTR_VAL(member)[0] == '\0' && ZSTR_LEN(member) != 0)) {
     334           7 :                 if (!silent) {
     335           1 :                         zend_throw_error(NULL, "Cannot access property started with '\\0'");
     336             :                 }
     337           7 :                 return ZEND_WRONG_PROPERTY_OFFSET;
     338             :         }
     339             : 
     340      471526 :         if (UNEXPECTED(zend_hash_num_elements(&ce->properties_info) == 0)) {
     341             :                 goto exit_dynamic;
     342             :         }
     343             : 
     344       43997 :         zv = zend_hash_find(&ce->properties_info, member);
     345       43997 :         if (EXPECTED(zv != NULL)) {
     346       42087 :                 property_info = (zend_property_info*)Z_PTR_P(zv);
     347       42087 :                 flags = property_info->flags;
     348       42087 :                 if (UNEXPECTED((flags & ZEND_ACC_SHADOW) != 0)) {
     349             :                         /* if it's a shadow - go to access it's private */
     350        3504 :                         property_info = NULL;
     351             :                 } else {
     352       38583 :                         if (EXPECTED(zend_verify_property_access(property_info, ce) != 0)) {
     353       77044 :                                 if (UNEXPECTED(!(flags & ZEND_ACC_CHANGED))
     354       38541 :                                         || UNEXPECTED((flags & ZEND_ACC_PRIVATE))) {
     355       38482 :                                         if (UNEXPECTED((flags & ZEND_ACC_STATIC) != 0)) {
     356          16 :                                                 if (!silent) {
     357          12 :                                                         zend_error(E_NOTICE, "Accessing static property %s::$%s as non static", ZSTR_VAL(ce->name), ZSTR_VAL(member));
     358             :                                                 }
     359          16 :                                                 return ZEND_DYNAMIC_PROPERTY_OFFSET;
     360             :                                         }
     361             :                                         goto exit;
     362             :                                 }
     363             :                         } else {
     364             :                                 /* Try to look in the scope instead */
     365          80 :                                 property_info = ZEND_WRONG_PROPERTY_INFO;
     366             :                         }
     367             :                 }
     368             :         }
     369             : 
     370        5515 :         if (EG(fake_scope)) {
     371        3609 :                 scope = EG(fake_scope);
     372             :         } else {
     373        1906 :                 scope = zend_get_executed_scope();
     374             :         }
     375             : 
     376       16896 :         if (scope != ce
     377             :                 && scope
     378             :                 && is_derived_class(ce, scope)
     379        3507 :                 && (zv = zend_hash_find(&scope->properties_info, member)) != NULL
     380        3497 :                 && ((zend_property_info*)Z_PTR_P(zv))->flags & ZEND_ACC_PRIVATE) {
     381        3493 :                 property_info = (zend_property_info*)Z_PTR_P(zv);
     382        3493 :                 if (UNEXPECTED((property_info->flags & ZEND_ACC_STATIC) != 0)) {
     383           2 :                         return ZEND_DYNAMIC_PROPERTY_OFFSET;
     384             :                 }
     385        2022 :         } else if (UNEXPECTED(property_info == NULL)) {
     386             : exit_dynamic:
     387      429469 :                 if (cache_slot) {
     388        1944 :                         CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, (void*)(intptr_t)ZEND_DYNAMIC_PROPERTY_OFFSET);
     389             :                 }
     390      429469 :                 return ZEND_DYNAMIC_PROPERTY_OFFSET;
     391          82 :         } else if (UNEXPECTED(property_info == ZEND_WRONG_PROPERTY_INFO)) {
     392             :                 /* Information was available, but we were denied access.  Error out. */
     393          72 :                 if (!silent) {
     394          23 :                         zend_throw_error(NULL, "Cannot access %s property %s::$%s", zend_visibility_string(flags), ZSTR_VAL(ce->name), ZSTR_VAL(member));
     395             :                 }
     396          72 :                 return ZEND_WRONG_PROPERTY_OFFSET;
     397             :         }
     398             : 
     399             : exit:
     400       41967 :         if (cache_slot) {
     401        2858 :                 CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, (void*)(intptr_t)property_info->offset);
     402             :         }
     403       41967 :         return property_info->offset;
     404             : }
     405             : /* }}} */
     406             : 
     407        1005 : ZEND_API zend_property_info *zend_get_property_info(zend_class_entry *ce, zend_string *member, int silent) /* {{{ */
     408             : {
     409             :         zval *zv;
     410        1005 :         zend_property_info *property_info = NULL;
     411             :         uint32_t flags;
     412             :         zend_class_entry *scope;
     413             : 
     414        1005 :         if (UNEXPECTED(ZSTR_VAL(member)[0] == '\0' && ZSTR_LEN(member) != 0)) {
     415           0 :                 if (!silent) {
     416           0 :                         zend_throw_error(NULL, "Cannot access property started with '\\0'");
     417             :                 }
     418           0 :                 return ZEND_WRONG_PROPERTY_INFO;
     419             :         }
     420             : 
     421        1005 :         if (UNEXPECTED(zend_hash_num_elements(&ce->properties_info) == 0)) {
     422         176 :                 goto exit_dynamic;
     423             :         }
     424             : 
     425         829 :         zv = zend_hash_find(&ce->properties_info, member);
     426         829 :         if (EXPECTED(zv != NULL)) {
     427         716 :                 property_info = (zend_property_info*)Z_PTR_P(zv);
     428         716 :                 flags = property_info->flags;
     429         716 :                 if (UNEXPECTED((flags & ZEND_ACC_SHADOW) != 0)) {
     430             :                         /* if it's a shadow - go to access it's private */
     431          41 :                         property_info = NULL;
     432             :                 } else {
     433         675 :                         if (EXPECTED(zend_verify_property_access(property_info, ce) != 0)) {
     434        1199 :                                 if (UNEXPECTED(!(flags & ZEND_ACC_CHANGED))
     435         607 :                                         || UNEXPECTED((flags & ZEND_ACC_PRIVATE))) {
     436         592 :                                         if (UNEXPECTED((flags & ZEND_ACC_STATIC) != 0)) {
     437           0 :                                                 if (!silent) {
     438           0 :                                                         zend_error(E_NOTICE, "Accessing static property %s::$%s as non static", ZSTR_VAL(ce->name), ZSTR_VAL(member));
     439             :                                                 }
     440             :                                         }
     441         592 :                                         goto exit;
     442             :                                 }
     443             :                         } else {
     444             :                                 /* Try to look in the scope instead */
     445          83 :                                 property_info = ZEND_WRONG_PROPERTY_INFO;
     446             :                         }
     447             :                 }
     448             :         }
     449             : 
     450         237 :         if (EG(fake_scope)) {
     451          30 :                 scope = EG(fake_scope);
     452             :         } else {
     453         207 :                 scope = zend_get_executed_scope();
     454             :         }
     455             : 
     456         441 :         if (scope != ce
     457             :                 && scope
     458             :                 && is_derived_class(ce, scope)
     459          56 :                 && (zv = zend_hash_find(&scope->properties_info, member)) != NULL
     460          40 :                 && ((zend_property_info*)Z_PTR_P(zv))->flags & ZEND_ACC_PRIVATE) {
     461          38 :                 property_info = (zend_property_info*)Z_PTR_P(zv);
     462         199 :         } else if (UNEXPECTED(property_info == NULL)) {
     463             : exit_dynamic:
     464         304 :                 return NULL;
     465          71 :         } else if (UNEXPECTED(property_info == ZEND_WRONG_PROPERTY_INFO)) {
     466             :                 /* Information was available, but we were denied access.  Error out. */
     467          71 :                 if (!silent) {
     468           0 :                         zend_throw_error(NULL, "Cannot access %s property %s::$%s", zend_visibility_string(flags), ZSTR_VAL(ce->name), ZSTR_VAL(member));
     469             :                 }
     470          71 :                 return ZEND_WRONG_PROPERTY_INFO;
     471             :         }
     472             : 
     473             : exit:
     474         630 :         return property_info;
     475             : }
     476             : /* }}} */
     477             : 
     478         850 : ZEND_API int zend_check_property_access(zend_object *zobj, zend_string *prop_info_name) /* {{{ */
     479             : {
     480             :         zend_property_info *property_info;
     481         850 :         const char *class_name = NULL;
     482             :         const char *prop_name;
     483             :         zend_string *member;
     484             :         size_t prop_name_len;
     485             : 
     486         850 :         if (ZSTR_VAL(prop_info_name)[0] == 0) {
     487         289 :                 zend_unmangle_property_name_ex(prop_info_name, &class_name, &prop_name, &prop_name_len);
     488         578 :                 member = zend_string_init(prop_name, prop_name_len, 0);
     489             :         } else {
     490         561 :                 member = zend_string_copy(prop_info_name);
     491             :         }
     492         850 :         property_info = zend_get_property_info(zobj->ce, member, 1);
     493             :         zend_string_release(member);
     494         850 :         if (property_info == NULL) {
     495             :                 /* undefined public property */
     496         169 :                 if (class_name && class_name[0] != '*') {
     497             :                         /* we we're looking for a private prop */
     498          16 :                         return FAILURE;
     499             :                 }
     500         153 :                 return SUCCESS;
     501         681 :         } else if (property_info == ZEND_WRONG_PROPERTY_INFO) {
     502          71 :                 return FAILURE;
     503             :         }
     504         610 :         if (class_name && class_name[0] != '*') {
     505          86 :                 if (!(property_info->flags & ZEND_ACC_PRIVATE)) {
     506             :                         /* we we're looking for a private prop but found a non private one of the same name */
     507           0 :                         return FAILURE;
     508          86 :                 } else if (strcmp(ZSTR_VAL(prop_info_name)+1, ZSTR_VAL(property_info->name)+1)) {
     509             :                         /* we we're looking for a private prop but found a private one of the same name but another class */
     510          11 :                         return FAILURE;
     511             :                 }
     512             :         }
     513        1198 :         return zend_verify_property_access(property_info, zobj->ce) ? SUCCESS : FAILURE;
     514             : }
     515             : /* }}} */
     516             : 
     517           2 : static void zend_property_guard_dtor(zval *el) /* {{{ */ {
     518           2 :         uint32_t *ptr = (uint32_t*)Z_PTR_P(el);
     519           2 :         if (EXPECTED(!(((zend_uintptr_t)ptr) & 1))) {
     520           1 :                 efree_size(ptr, sizeof(uint32_t));
     521             :         }
     522           2 : }
     523             : /* }}} */
     524             : 
     525         398 : ZEND_API uint32_t *zend_get_property_guard(zend_object *zobj, zend_string *member) /* {{{ */
     526             : {
     527             :         HashTable *guards;
     528             :         zval *zv;
     529             :         uint32_t *ptr;
     530             : 
     531             :         ZEND_ASSERT(GC_FLAGS(zobj) & IS_OBJ_USE_GUARDS);
     532         398 :         zv = zobj->properties_table + zobj->ce->default_properties_count;
     533         398 :         if (EXPECTED(Z_TYPE_P(zv) == IS_STRING)) {
     534         307 :                 zend_string *str = Z_STR_P(zv);
     535         431 :                 if (EXPECTED(str == member) ||
     536             :                      /* hash values are always pred-calculated here */
     537         100 :                     (EXPECTED(ZSTR_H(str) == ZSTR_H(member)) &&
     538          13 :                      EXPECTED(ZSTR_LEN(str) == ZSTR_LEN(member)) &&
     539          11 :                      EXPECTED(memcmp(ZSTR_VAL(str), ZSTR_VAL(member), ZSTR_LEN(member)) == 0))) {
     540         210 :                         return &zv->u2.property_guard;
     541          97 :                 } else if (EXPECTED(zv->u2.property_guard == 0)) {
     542          96 :                         zend_string_release(Z_STR_P(zv));
     543          96 :                         ZVAL_STR_COPY(zv, member);
     544          96 :                         return &zv->u2.property_guard;
     545             :                 } else {
     546           1 :                         ALLOC_HASHTABLE(guards);
     547           1 :                         zend_hash_init(guards, 8, NULL, zend_property_guard_dtor, 0);
     548             :                         /* mark pointer as "special" using low bit */
     549           1 :                         zend_hash_add_new_ptr(guards, member,
     550           1 :                                 (void*)(((zend_uintptr_t)&zv->u2.property_guard) | 1));
     551           1 :                         zend_string_release(Z_STR_P(zv));
     552           1 :                         ZVAL_ARR(zv, guards);
     553             :                 }
     554          91 :         } else if (EXPECTED(Z_TYPE_P(zv) == IS_ARRAY)) {
     555           0 :                 guards = Z_ARRVAL_P(zv);
     556             :                 ZEND_ASSERT(guards != NULL);
     557           0 :                 zv = zend_hash_find(guards, member);
     558           0 :                 if (zv != NULL) {
     559           0 :                         return (uint32_t*)(((zend_uintptr_t)Z_PTR_P(zv)) & ~1);
     560             :                 }
     561             :         } else {
     562             :                 ZEND_ASSERT(Z_TYPE_P(zv) == IS_UNDEF);
     563          91 :                 GC_FLAGS(zobj) |= IS_OBJ_HAS_GUARDS;
     564          91 :                 ZVAL_STR_COPY(zv, member);
     565          91 :                 zv->u2.property_guard = 0;
     566          91 :                 return &zv->u2.property_guard;
     567             :         }
     568             :         /* we have to allocate uint32_t separately because ht->arData may be reallocated */
     569           1 :         ptr = (uint32_t*)emalloc(sizeof(uint32_t));
     570           1 :         *ptr = 0;
     571           1 :         return (uint32_t*)zend_hash_add_new_ptr(guards, member, ptr);
     572             : }
     573             : /* }}} */
     574             : 
     575       11092 : zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) /* {{{ */
     576             : {
     577             :         zend_object *zobj;
     578             :         zval tmp_member;
     579             :         zval *retval;
     580             :         uint32_t property_offset;
     581             : 
     582       11092 :         zobj = Z_OBJ_P(object);
     583             : 
     584       11092 :         ZVAL_UNDEF(&tmp_member);
     585       11092 :         if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
     586          45 :                 ZVAL_STR(&tmp_member, zval_get_string(member));
     587          22 :                 member = &tmp_member;
     588          22 :                 cache_slot = NULL;
     589             :         }
     590             : 
     591             : #if DEBUG_OBJECT_HANDLERS
     592             :         fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
     593             : #endif
     594             : 
     595             :         /* make zend_get_property_info silent if we have getter - we may want to use it */
     596       22182 :         property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), (type == BP_VAR_IS) || (zobj->ce->__get != NULL), cache_slot);
     597             : 
     598       11091 :         if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
     599       11058 :                 if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) {
     600        8989 :                         retval = OBJ_PROP(zobj, property_offset);
     601        8989 :                         if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) {
     602        8965 :                                 goto exit;
     603             :                         }
     604        2069 :                 } else if (EXPECTED(zobj->properties != NULL)) {
     605        1763 :                         retval = zend_hash_find(zobj->properties, Z_STR_P(member));
     606        1763 :                         if (EXPECTED(retval)) goto exit;
     607             :                 }
     608          33 :         } else if (UNEXPECTED(EG(exception))) {
     609           9 :                 retval = &EG(uninitialized_zval);
     610           9 :                 goto exit;
     611             :         }
     612             : 
     613             :         /* magic isset */
     614         471 :         if ((type == BP_VAR_IS) && zobj->ce->__isset) {
     615             :                 zval tmp_object, tmp_result;
     616           9 :                 uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member));
     617             : 
     618           9 :                 if (!((*guard) & IN_ISSET)) {
     619           9 :                         ZVAL_COPY(&tmp_object, object);
     620           9 :                         ZVAL_UNDEF(&tmp_result);
     621             : 
     622           9 :                         *guard |= IN_ISSET;
     623           9 :                         zend_std_call_issetter(&tmp_object, member, &tmp_result);
     624           9 :                         *guard &= ~IN_ISSET;
     625             :         
     626           9 :                         if (!zend_is_true(&tmp_result)) {
     627           5 :                                 retval = &EG(uninitialized_zval);
     628           5 :                                 zval_ptr_dtor(&tmp_object);
     629           5 :                                 zval_ptr_dtor(&tmp_result);
     630           5 :                                 goto exit;
     631             :                         }
     632             : 
     633           4 :                         zval_ptr_dtor(&tmp_object);
     634           4 :                         zval_ptr_dtor(&tmp_result);
     635             :                 }
     636             :         }
     637             : 
     638             :         /* magic get */
     639         466 :         if (zobj->ce->__get) {
     640         173 :                 uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member));
     641         173 :                 if (!((*guard) & IN_GET)) {
     642             :                         zval tmp_object;
     643             : 
     644             :                         /* have getter - try with it! */
     645         161 :                         ZVAL_COPY(&tmp_object, object);
     646         161 :                         *guard |= IN_GET; /* prevent circular getting */
     647         161 :                         zend_std_call_getter(&tmp_object, member, rv);
     648         161 :                         *guard &= ~IN_GET;
     649             : 
     650         161 :                         if (Z_TYPE_P(rv) != IS_UNDEF) {
     651         151 :                                 retval = rv;
     652         151 :                                 if (!Z_ISREF_P(rv) &&
     653             :                                     (type == BP_VAR_W || type == BP_VAR_RW  || type == BP_VAR_UNSET)) {
     654          44 :                                         SEPARATE_ZVAL(rv);
     655          22 :                                         if (UNEXPECTED(Z_TYPE_P(rv) != IS_OBJECT)) {
     656          14 :                                                 zend_error(E_NOTICE, "Indirect modification of overloaded property %s::$%s has no effect", ZSTR_VAL(zobj->ce->name), Z_STRVAL_P(member));
     657             :                                         }
     658             :                                 }
     659             :                         } else {
     660          10 :                                 retval = &EG(uninitialized_zval);
     661             :                         }
     662         161 :                         zval_ptr_dtor(&tmp_object);
     663         161 :                         goto exit;
     664             :                 } else {
     665          12 :                         if (Z_STRVAL_P(member)[0] == '\0' && Z_STRLEN_P(member) != 0) {
     666           1 :                                 zend_throw_error(NULL, "Cannot access property started with '\\0'");
     667           1 :                                 retval = &EG(uninitialized_zval);
     668           1 :                                 goto exit;
     669             :                         }
     670             :                 }
     671             :         }
     672         304 :         if ((type != BP_VAR_IS)) {
     673          58 :                 zend_error(E_NOTICE,"Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), Z_STRVAL_P(member));
     674             :         }
     675         304 :         retval = &EG(uninitialized_zval);
     676             : 
     677             : exit:
     678       11091 :         if (UNEXPECTED(Z_REFCOUNTED(tmp_member))) {
     679          21 :                 zval_ptr_dtor(&tmp_member);
     680             :         }
     681             : 
     682       11091 :         return retval;
     683             : }
     684             : /* }}} */
     685             : 
     686      459384 : ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, void **cache_slot) /* {{{ */
     687             : {
     688             :         zend_object *zobj;
     689             :         zval tmp_member;
     690             :         zval *variable_ptr;
     691             :         uint32_t property_offset;
     692             : 
     693      459384 :         zobj = Z_OBJ_P(object);
     694             : 
     695      459384 :         ZVAL_UNDEF(&tmp_member);
     696      459384 :         if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
     697           6 :                 ZVAL_STR(&tmp_member, zval_get_string(member));
     698           3 :                 member = &tmp_member;
     699           3 :                 cache_slot = NULL;
     700             :         }
     701             : 
     702      918768 :         property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), (zobj->ce->__set != NULL), cache_slot);
     703             : 
     704      459384 :         if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
     705      459362 :                 if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) {
     706       32500 :                         variable_ptr = OBJ_PROP(zobj, property_offset);
     707       32500 :                         if (Z_TYPE_P(variable_ptr) != IS_UNDEF) {
     708       32479 :                                 goto found;
     709             :                         }
     710      426862 :                 } else if (EXPECTED(zobj->properties != NULL)) {
     711       30493 :                         if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
     712           2 :                                 if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
     713           2 :                                         GC_REFCOUNT(zobj->properties)--;
     714             :                                 }
     715           2 :                                 zobj->properties = zend_array_dup(zobj->properties);
     716             :                         }
     717       30493 :                         if ((variable_ptr = zend_hash_find(zobj->properties, Z_STR_P(member))) != NULL) {
     718             : found:
     719             :                                 zend_assign_to_variable(variable_ptr, value, IS_CV);
     720       32534 :                                 goto exit;
     721             :                         }
     722             :                 }
     723          22 :         } else if (UNEXPECTED(EG(exception))) {
     724          11 :                 goto exit;
     725             :         }
     726             : 
     727             :         /* magic set */
     728      426839 :         if (zobj->ce->__set) {
     729         124 :                 uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member));
     730             : 
     731         124 :             if (!((*guard) & IN_SET)) {
     732             :                         zval tmp_object;
     733             : 
     734         103 :                         ZVAL_COPY(&tmp_object, object);
     735         103 :                         (*guard) |= IN_SET; /* prevent circular setting */
     736         103 :                         if (zend_std_call_setter(&tmp_object, member, value) != SUCCESS) {
     737             :                                 /* for now, just ignore it - __set should take care of warnings, etc. */
     738             :                         }
     739         103 :                         (*guard) &= ~IN_SET;
     740         103 :                         zval_ptr_dtor(&tmp_object);
     741          21 :                 } else if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
     742          19 :                         goto write_std_property;
     743             :                 } else {
     744           2 :                         if (Z_STRVAL_P(member)[0] == '\0' && Z_STRLEN_P(member) != 0) {
     745           1 :                                 zend_throw_error(NULL, "Cannot access property started with '\\0'");
     746           1 :                                 goto exit;
     747             :                         }
     748             :                 }
     749      426715 :         } else if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
     750             :                 zval tmp;
     751             : 
     752             : write_std_property:
     753      426734 :                 if (Z_REFCOUNTED_P(value)) {
     754      416218 :                         if (Z_ISREF_P(value)) {
     755             :                                 /* if we assign referenced variable, we should separate it */
     756           0 :                                 ZVAL_COPY(&tmp, Z_REFVAL_P(value));
     757           0 :                                 value = &tmp;
     758             :                         } else {
     759             :                                 Z_ADDREF_P(value);
     760             :                         }
     761             :                 }
     762      426734 :                 if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) {
     763          15 :                         ZVAL_COPY_VALUE(OBJ_PROP(zobj, property_offset), value);
     764             :                 } else {
     765      426719 :                         if (!zobj->properties) {
     766      396290 :                                 rebuild_object_properties(zobj);
     767             :                         }
     768      426719 :                         zend_hash_add_new(zobj->properties, Z_STR_P(member), value);
     769             :                 }
     770             :         }
     771             : 
     772             : exit:
     773      459384 :         if (UNEXPECTED(Z_REFCOUNTED(tmp_member))) {
     774           3 :                 zval_ptr_dtor(&tmp_member);
     775             :         }
     776      459384 : }
     777             : /* }}} */
     778             : 
     779         514 : zval *zend_std_read_dimension(zval *object, zval *offset, int type, zval *rv) /* {{{ */
     780             : {
     781         514 :         zend_class_entry *ce = Z_OBJCE_P(object);
     782             :         zval tmp;
     783             : 
     784         514 :         if (EXPECTED(instanceof_function_ex(ce, zend_ce_arrayaccess, 1) != 0)) {
     785         509 :                 if (offset == NULL) {
     786             :                         /* [] construct */
     787           2 :                         ZVAL_NULL(&tmp);
     788           2 :                         offset = &tmp;
     789             :                 } else {
     790         507 :                         SEPARATE_ARG_IF_REF(offset);
     791             :                 }
     792             : 
     793         509 :                 if (type == BP_VAR_IS) {
     794           9 :                         zend_call_method_with_1_params(object, ce, NULL, "offsetexists", rv, offset);
     795           9 :                         if (UNEXPECTED(Z_ISUNDEF_P(rv))) {
     796           0 :                                 return NULL;
     797             :                         }
     798           9 :                         if (!i_zend_is_true(rv)) {
     799           5 :                                 zval_ptr_dtor(rv);
     800           5 :                                 return &EG(uninitialized_zval);
     801             :                         }
     802           4 :                         zval_ptr_dtor(rv);
     803             :                 }
     804             : 
     805         504 :                 zend_call_method_with_1_params(object, ce, NULL, "offsetget", rv, offset);
     806             : 
     807         504 :                 zval_ptr_dtor(offset);
     808             : 
     809         504 :                 if (UNEXPECTED(Z_TYPE_P(rv) == IS_UNDEF)) {
     810           5 :                         if (UNEXPECTED(!EG(exception))) {
     811           0 :                                 zend_throw_error(NULL, "Undefined offset for object of type %s used as array", ZSTR_VAL(ce->name));
     812             :                         }
     813           5 :                         return NULL;
     814             :                 }
     815         499 :                 return rv;
     816             :         } else {
     817           5 :                 zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(ce->name));
     818           5 :                 return NULL;
     819             :         }
     820             : }
     821             : /* }}} */
     822             : 
     823        1344 : static void zend_std_write_dimension(zval *object, zval *offset, zval *value) /* {{{ */
     824             : {
     825        1344 :         zend_class_entry *ce = Z_OBJCE_P(object);
     826             :         zval tmp;
     827             : 
     828        1344 :         if (EXPECTED(instanceof_function_ex(ce, zend_ce_arrayaccess, 1) != 0)) {
     829        1343 :                 if (!offset) {
     830          11 :                         ZVAL_NULL(&tmp);
     831          11 :                         offset = &tmp;
     832             :                 } else {
     833        1332 :                         SEPARATE_ARG_IF_REF(offset);
     834             :                 }
     835        1343 :                 zend_call_method_with_2_params(object, ce, NULL, "offsetset", NULL, offset, value);
     836        1343 :                 zval_ptr_dtor(offset);
     837             :         } else {
     838           1 :                 zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(ce->name));
     839             :         }
     840        1344 : }
     841             : /* }}} */
     842             : 
     843        1079 : static int zend_std_has_dimension(zval *object, zval *offset, int check_empty) /* {{{ */
     844             : {
     845        1079 :         zend_class_entry *ce = Z_OBJCE_P(object);
     846             :         zval retval;
     847             :         int result;
     848             : 
     849        1079 :         if (EXPECTED(instanceof_function_ex(ce, zend_ce_arrayaccess, 1) != 0)) {
     850        1079 :                 SEPARATE_ARG_IF_REF(offset);
     851        1079 :                 zend_call_method_with_1_params(object, ce, NULL, "offsetexists", &retval, offset);
     852        1079 :                 if (EXPECTED(Z_TYPE(retval) != IS_UNDEF)) {
     853        1077 :                         result = i_zend_is_true(&retval);
     854        1077 :                         zval_ptr_dtor(&retval);
     855        1077 :                         if (check_empty && result && EXPECTED(!EG(exception))) {
     856           8 :                                 zend_call_method_with_1_params(object, ce, NULL, "offsetget", &retval, offset);
     857           8 :                                 if (EXPECTED(Z_TYPE(retval) != IS_UNDEF)) {
     858           8 :                                         result = i_zend_is_true(&retval);
     859           8 :                                         zval_ptr_dtor(&retval);
     860             :                                 }
     861             :                         }
     862             :                 } else {
     863           2 :                         result = 0;
     864             :                 }
     865        1079 :                 zval_ptr_dtor(offset);
     866             :         } else {
     867           0 :                 zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(ce->name));
     868           0 :                 return 0;
     869             :         }
     870        1079 :         return result;
     871             : }
     872             : /* }}} */
     873             : 
     874        4999 : static zval *zend_std_get_property_ptr_ptr(zval *object, zval *member, int type, void **cache_slot) /* {{{ */
     875             : {
     876             :         zend_object *zobj;
     877             :         zend_string *name;
     878        4999 :         zval *retval = NULL;
     879             :         uint32_t property_offset;
     880             : 
     881        4999 :         zobj = Z_OBJ_P(object);
     882        4999 :         if (EXPECTED(Z_TYPE_P(member) == IS_STRING)) {
     883        4999 :                 name = Z_STR_P(member);
     884             :         } else {
     885           0 :                 name = zval_get_string(member);
     886             :         }
     887             : 
     888             : #if DEBUG_OBJECT_HANDLERS
     889             :         fprintf(stderr, "Ptr object #%d property: %s\n", Z_OBJ_HANDLE_P(object), ZSTR_VAL(name));
     890             : #endif
     891             : 
     892        9998 :         property_offset = zend_get_property_offset(zobj->ce, name, (zobj->ce->__get != NULL), cache_slot);
     893             : 
     894        4999 :         if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
     895        4991 :                 if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) {
     896        4507 :                         retval = OBJ_PROP(zobj, property_offset);
     897        4507 :                         if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
     898           0 :                                 if (EXPECTED(!zobj->ce->__get) ||
     899           0 :                                     UNEXPECTED((*zend_get_property_guard(zobj, name)) & IN_GET)) {
     900           0 :                                         ZVAL_NULL(retval);
     901             :                                         /* Notice is thrown after creation of the property, to avoid EG(std_property_info)
     902             :                                          * being overwritten in an error handler. */
     903           0 :                                         if (UNEXPECTED(type == BP_VAR_RW || type == BP_VAR_R)) {
     904           0 :                                                 zend_error(E_NOTICE, "Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name));
     905             :                                         }
     906             :                                 } else {
     907             :                                         /* we do have getter - fail and let it try again with usual get/set */
     908           0 :                                         retval = NULL;
     909             :                                 }
     910             :                         }
     911             :                 } else {
     912         484 :                         if (EXPECTED(zobj->properties)) {
     913         371 :                                 if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
     914           4 :                                         if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
     915           4 :                                                 GC_REFCOUNT(zobj->properties)--;
     916             :                                         }
     917           4 :                                         zobj->properties = zend_array_dup(zobj->properties);
     918             :                                 }
     919         371 :                             if (EXPECTED((retval = zend_hash_find(zobj->properties, name)) != NULL)) {
     920         133 :                                         if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
     921             :                                                 zend_string_release(name);
     922             :                                         }
     923         133 :                                         return retval;
     924             :                             }
     925             :                         }
     926         393 :                         if (EXPECTED(!zobj->ce->__get) ||
     927          42 :                             UNEXPECTED((*zend_get_property_guard(zobj, name)) & IN_GET)) {
     928         309 :                                 if (UNEXPECTED(!zobj->properties)) {
     929          72 :                                         rebuild_object_properties(zobj);
     930             :                                 }
     931         309 :                                 retval = zend_hash_update(zobj->properties, name, &EG(uninitialized_zval));
     932             :                                 /* Notice is thrown after creation of the property, to avoid EG(std_property_info)
     933             :                                  * being overwritten in an error handler. */
     934         309 :                                 if (UNEXPECTED(type == BP_VAR_RW || type == BP_VAR_R)) {
     935          15 :                                         zend_error(E_NOTICE, "Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), ZSTR_VAL(name));
     936             :                                 }
     937             :                         }
     938             :                 }
     939             :         }
     940             : 
     941        4866 :         if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
     942             :                 zend_string_release(name);
     943             :         }
     944        4866 :         return retval;
     945             : }
     946             : /* }}} */
     947             : 
     948         185 : static void zend_std_unset_property(zval *object, zval *member, void **cache_slot) /* {{{ */
     949             : {
     950             :         zend_object *zobj;
     951             :         zval tmp_member;
     952             :         uint32_t property_offset;
     953             : 
     954         185 :         zobj = Z_OBJ_P(object);
     955             : 
     956         185 :         ZVAL_UNDEF(&tmp_member);
     957         185 :         if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
     958           0 :                 ZVAL_STR(&tmp_member, zval_get_string(member));
     959           0 :                 member = &tmp_member;
     960           0 :                 cache_slot = NULL;
     961             :         }
     962             : 
     963         370 :         property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), (zobj->ce->__unset != NULL), cache_slot);
     964             : 
     965         185 :         if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
     966         182 :                 if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) {
     967          62 :                         zval *slot = OBJ_PROP(zobj, property_offset);
     968             : 
     969          62 :                         if (Z_TYPE_P(slot) != IS_UNDEF) {
     970          62 :                                 zval_ptr_dtor(slot);
     971          62 :                                 ZVAL_UNDEF(slot);
     972          62 :                                 if (zobj->properties) {
     973          20 :                                         zobj->properties->u.v.flags |= HASH_FLAG_HAS_EMPTY_IND;
     974             :                                 }
     975          62 :                                 goto exit;
     976             :                         }
     977         120 :                 } else if (EXPECTED(zobj->properties != NULL)) {
     978         111 :                         if (UNEXPECTED(GC_REFCOUNT(zobj->properties) > 1)) {
     979           1 :                                 if (EXPECTED(!(GC_FLAGS(zobj->properties) & IS_ARRAY_IMMUTABLE))) {
     980           1 :                                         GC_REFCOUNT(zobj->properties)--;
     981             :                                 }
     982           1 :                                 zobj->properties = zend_array_dup(zobj->properties);
     983             :                         }
     984         111 :                         if (EXPECTED(zend_hash_del(zobj->properties, Z_STR_P(member)) != FAILURE)) {
     985         105 :                                 goto exit;
     986             :                         }
     987             :                 }
     988           3 :         } else if (UNEXPECTED(EG(exception))) {
     989           1 :                 goto exit;
     990             :         }
     991             : 
     992             :         /* magic unset */
     993          17 :         if (zobj->ce->__unset) {
     994           9 :                 uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member));
     995           9 :                 if (!((*guard) & IN_UNSET)) {
     996             :                         zval tmp_object;
     997             : 
     998             :                         /* have unseter - try with it! */
     999           8 :                         ZVAL_COPY(&tmp_object, object);
    1000           8 :                         (*guard) |= IN_UNSET; /* prevent circular unsetting */
    1001           8 :                         zend_std_call_unsetter(&tmp_object, member);
    1002           8 :                         (*guard) &= ~IN_UNSET;
    1003           8 :                         zval_ptr_dtor(&tmp_object);
    1004             :                 } else {
    1005           1 :                         if (Z_STRVAL_P(member)[0] == '\0' && Z_STRLEN_P(member) != 0) {
    1006           1 :                                 zend_throw_error(NULL, "Cannot access property started with '\\0'");
    1007             :                                 goto exit;
    1008             :                         }
    1009             :                 }
    1010             :         }
    1011             : 
    1012             : exit:
    1013         185 :         if (UNEXPECTED(Z_REFCOUNTED(tmp_member))) {
    1014           0 :                 zval_ptr_dtor(&tmp_member);
    1015             :         }
    1016         185 : }
    1017             : /* }}} */
    1018             : 
    1019          27 : static void zend_std_unset_dimension(zval *object, zval *offset) /* {{{ */
    1020             : {
    1021          27 :         zend_class_entry *ce = Z_OBJCE_P(object);
    1022             : 
    1023          27 :         if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1)) {
    1024          27 :                 SEPARATE_ARG_IF_REF(offset);
    1025          27 :                 zend_call_method_with_1_params(object, ce, NULL, "offsetunset", NULL, offset);
    1026          27 :                 zval_ptr_dtor(offset);
    1027             :         } else {
    1028           0 :                 zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(ce->name));
    1029             :         }
    1030          27 : }
    1031             : /* }}} */
    1032             : 
    1033             : /* Ensures that we're allowed to call a private method.
    1034             :  * Returns the function address that should be called, or NULL
    1035             :  * if no such function exists.
    1036             :  */
    1037         225 : static inline zend_function *zend_check_private_int(zend_function *fbc, zend_class_entry *ce, zend_string *function_name) /* {{{ */
    1038             : {
    1039             :     zval *func;
    1040             :     zend_class_entry *scope;
    1041             : 
    1042         225 :         if (!ce) {
    1043          10 :                 return 0;
    1044             :         }
    1045             : 
    1046             :         /* We may call a private function if:
    1047             :          * 1.  The class of our object is the same as the scope, and the private
    1048             :          *     function (EX(fbc)) has the same scope.
    1049             :          * 2.  One of our parent classes are the same as the scope, and it contains
    1050             :          *     a private function with the same name that has the same scope.
    1051             :          */
    1052         215 :         scope = zend_get_executed_scope();
    1053         215 :         if (fbc->common.scope == ce && scope == ce) {
    1054             :                 /* rule #1 checks out ok, allow the function call */
    1055         162 :                 return fbc;
    1056             :         }
    1057             : 
    1058             : 
    1059             :         /* Check rule #2 */
    1060          53 :         ce = ce->parent;
    1061         124 :         while (ce) {
    1062          30 :                 if (ce == scope) {
    1063          12 :                         if ((func = zend_hash_find(&ce->function_table, function_name))) {
    1064          12 :                                 fbc = Z_FUNC_P(func);
    1065          24 :                                 if (fbc->common.fn_flags & ZEND_ACC_PRIVATE
    1066          24 :                                         && fbc->common.scope == scope) {
    1067          10 :                                         return fbc;
    1068             :                                 }
    1069             :                         }
    1070           2 :                         break;
    1071             :                 }
    1072          18 :                 ce = ce->parent;
    1073             :         }
    1074          43 :         return NULL;
    1075             : }
    1076             : /* }}} */
    1077             : 
    1078          47 : ZEND_API int zend_check_private(zend_function *fbc, zend_class_entry *ce, zend_string *function_name) /* {{{ */
    1079             : {
    1080          47 :         return zend_check_private_int(fbc, ce, function_name) != NULL;
    1081             : }
    1082             : /* }}} */
    1083             : 
    1084             : /* Ensures that we're allowed to call a protected method.
    1085             :  */
    1086       16568 : ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope) /* {{{ */
    1087             : {
    1088       16568 :         zend_class_entry *fbc_scope = ce;
    1089             : 
    1090             :         /* Is the context that's calling the function, the same as one of
    1091             :          * the function's parents?
    1092             :          */
    1093       35655 :         while (fbc_scope) {
    1094       16797 :                 if (fbc_scope==scope) {
    1095       14278 :                         return 1;
    1096             :                 }
    1097        2519 :                 fbc_scope = fbc_scope->parent;
    1098             :         }
    1099             : 
    1100             :         /* Is the function's scope the same as our current object context,
    1101             :          * or any of the parents of our context?
    1102             :          */
    1103        7516 :         while (scope) {
    1104        5094 :                 if (scope==ce) {
    1105        2158 :                         return 1;
    1106             :                 }
    1107        2936 :                 scope = scope->parent;
    1108             :         }
    1109         132 :         return 0;
    1110             : }
    1111             : /* }}} */
    1112             : 
    1113        3530 : ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend_string *method_name, int is_static) /* {{{ */
    1114             : {
    1115             :         size_t mname_len;
    1116             :         zend_op_array *func;
    1117        3530 :         zend_function *fbc = is_static ? ce->__callstatic : ce->__call;
    1118             : 
    1119             :         ZEND_ASSERT(fbc);
    1120             : 
    1121        3530 :         if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
    1122        3529 :                 func = &EG(trampoline).op_array;
    1123             :         } else {
    1124           1 :                 func = ecalloc(1, sizeof(zend_op_array));
    1125             :         }
    1126             : 
    1127        3530 :         func->type = ZEND_USER_FUNCTION;
    1128        3530 :         func->arg_flags[0] = 0;
    1129        3530 :         func->arg_flags[1] = 0;
    1130        3530 :         func->arg_flags[2] = 0;
    1131        3530 :         func->fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_PUBLIC;
    1132        3530 :         if (is_static) {
    1133          55 :                 func->fn_flags |= ZEND_ACC_STATIC;
    1134             :         }
    1135        3530 :         func->opcodes = &EG(call_trampoline_op);
    1136             : 
    1137        3530 :         func->prototype = fbc;
    1138        3530 :         func->scope = fbc->common.scope;
    1139             :         /* reserve space for arguments, local and temorary variables */
    1140        3530 :         func->T = (fbc->type == ZEND_USER_FUNCTION)? MAX(fbc->op_array.last_var + fbc->op_array.T, 2) : 2;
    1141        3530 :         func->filename = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.filename : ZSTR_EMPTY_ALLOC();
    1142        3530 :         func->line_start = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_start : 0;
    1143        3530 :         func->line_end = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_end : 0;
    1144             : 
    1145             :         //??? keep compatibility for "\0" characters
    1146             :         //??? see: Zend/tests/bug46238.phpt
    1147        3530 :         if (UNEXPECTED((mname_len = strlen(ZSTR_VAL(method_name))) != ZSTR_LEN(method_name))) {
    1148          10 :                 func->function_name = zend_string_init(ZSTR_VAL(method_name), mname_len, 0);
    1149             :         } else {
    1150        3525 :                 func->function_name = zend_string_copy(method_name);
    1151             :         }
    1152             : 
    1153        3530 :         return (zend_function*)func;
    1154             : }
    1155             : /* }}} */
    1156             : 
    1157             : static zend_always_inline zend_function *zend_get_user_call_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */
    1158             : {
    1159        3472 :         return zend_get_call_trampoline_func(ce, method_name, 0);
    1160             : }
    1161             : /* }}} */
    1162             : 
    1163       28825 : static union _zend_function *zend_std_get_method(zend_object **obj_ptr, zend_string *method_name, const zval *key) /* {{{ */
    1164             : {
    1165       28825 :         zend_object *zobj = *obj_ptr;
    1166             :         zval *func;
    1167             :         zend_function *fbc;
    1168             :         zend_string *lc_method_name;
    1169       28825 :         zend_class_entry *scope = NULL;
    1170             :         ALLOCA_FLAG(use_heap);
    1171             : 
    1172       28825 :         if (EXPECTED(key != NULL)) {
    1173       28387 :                 lc_method_name = Z_STR_P(key);
    1174             : #ifdef ZEND_ALLOCA_MAX_SIZE
    1175       28387 :                 use_heap = 0;
    1176             : #endif
    1177             :         } else {
    1178         876 :                 ZSTR_ALLOCA_ALLOC(lc_method_name, ZSTR_LEN(method_name), use_heap);
    1179         438 :                 zend_str_tolower_copy(ZSTR_VAL(lc_method_name), ZSTR_VAL(method_name), ZSTR_LEN(method_name));
    1180             :         }
    1181             : 
    1182       28825 :         if (UNEXPECTED((func = zend_hash_find(&zobj->ce->function_table, lc_method_name)) == NULL)) {
    1183        4888 :                 if (UNEXPECTED(!key)) {
    1184         266 :                         ZSTR_ALLOCA_FREE(lc_method_name, use_heap);
    1185             :                 }
    1186        4888 :                 if (zobj->ce->__call) {
    1187        6850 :                         return zend_get_user_call_function(zobj->ce, method_name);
    1188             :                 } else {
    1189        1463 :                         return NULL;
    1190             :                 }
    1191             :         }
    1192             : 
    1193       23937 :         fbc = Z_FUNC_P(func);
    1194             :         /* Check access level */
    1195       23937 :         if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
    1196             :                 zend_function *updated_fbc;
    1197             : 
    1198             :                 /* Ensure that if we're calling a private function, we're allowed to do so.
    1199             :                  * If we're not and __call() handler exists, invoke it, otherwise error out.
    1200             :                  */
    1201         161 :                 updated_fbc = zend_check_private_int(fbc, zobj->ce, lc_method_name);
    1202         161 :                 if (EXPECTED(updated_fbc != NULL)) {
    1203         148 :                         fbc = updated_fbc;
    1204             :                 } else {
    1205          13 :                         if (zobj->ce->__call) {
    1206          10 :                                 fbc = zend_get_user_call_function(zobj->ce, method_name);
    1207             :                         } else {
    1208           8 :                                 scope = zend_get_executed_scope();
    1209           8 :                                 zend_throw_error(NULL, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), ZSTR_VAL(method_name), scope ? ZSTR_VAL(scope->name) : "");
    1210           8 :                                 fbc = NULL;
    1211             :                         }
    1212             :                 }
    1213             :         } else {
    1214             :                 /* Ensure that we haven't overridden a private function and end up calling
    1215             :                  * the overriding public function...
    1216             :                  */
    1217       23776 :                 if (fbc->op_array.fn_flags & (ZEND_ACC_CHANGED|ZEND_ACC_PROTECTED)) {
    1218          49 :                         scope = zend_get_executed_scope();
    1219             :                 }
    1220       23776 :                 if (fbc->op_array.fn_flags & ZEND_ACC_CHANGED) {
    1221          21 :                         if (scope && is_derived_class(fbc->common.scope, scope)) {
    1222           8 :                                 if ((func = zend_hash_find(&scope->function_table, lc_method_name)) != NULL) {
    1223           8 :                                         zend_function *priv_fbc = Z_FUNC_P(func);
    1224          16 :                                         if (priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE
    1225          16 :                                                 && priv_fbc->common.scope == scope) {
    1226           6 :                                                 fbc = priv_fbc;
    1227             :                                         }
    1228             :                                 }
    1229             :                         }
    1230             :                 }
    1231       23776 :                 if (fbc->common.fn_flags & ZEND_ACC_PROTECTED) {
    1232             :                         /* Ensure that if we're calling a protected function, we're allowed to do so.
    1233             :                          * If we're not and __call() handler exists, invoke it, otherwise error out.
    1234             :                          */
    1235          38 :                         if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fbc), scope))) {
    1236          14 :                                 if (zobj->ce->__call) {
    1237           6 :                                         fbc = zend_get_user_call_function(zobj->ce, method_name);
    1238             :                                 } else {
    1239          11 :                                         zend_throw_error(NULL, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), ZSTR_VAL(method_name), scope ? ZSTR_VAL(scope->name) : "");
    1240          11 :                                         fbc = NULL;
    1241             :                                 }
    1242             :                         }
    1243             :                 }
    1244             :         }
    1245             : 
    1246       23937 :         if (UNEXPECTED(!key)) {
    1247         172 :                 ZSTR_ALLOCA_FREE(lc_method_name, use_heap);
    1248             :         }
    1249       23937 :         return fbc;
    1250             : }
    1251             : /* }}} */
    1252             : 
    1253             : static zend_always_inline zend_function *zend_get_user_callstatic_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */
    1254             : {
    1255          55 :         return zend_get_call_trampoline_func(ce, method_name, 1);
    1256             : }
    1257             : /* }}} */
    1258             : 
    1259        4418 : ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_string *function_name, const zval *key) /* {{{ */
    1260             : {
    1261        4418 :         zend_function *fbc = NULL;
    1262             :         char *lc_class_name;
    1263             :         zend_string *lc_function_name;
    1264             :         zend_object *object;
    1265             :         zend_class_entry *scope;
    1266             : 
    1267        4418 :         if (EXPECTED(key != NULL)) {
    1268        4258 :                 lc_function_name = Z_STR_P(key);
    1269             :         } else {
    1270         160 :                 lc_function_name = zend_string_tolower(function_name);
    1271             :         }
    1272             : 
    1273        4418 :         if (ZSTR_LEN(function_name) == ZSTR_LEN(ce->name) && ce->constructor) {
    1274          52 :                 lc_class_name = zend_str_tolower_dup(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name));
    1275             :                 /* Only change the method to the constructor if the constructor isn't called __construct
    1276             :                  * we check for __ so we can be binary safe for lowering, we should use ZEND_CONSTRUCTOR_FUNC_NAME
    1277             :                  */
    1278          52 :                 if (!memcmp(lc_class_name, ZSTR_VAL(lc_function_name), ZSTR_LEN(function_name)) && memcmp(ZSTR_VAL(ce->constructor->common.function_name), "__", sizeof("__") - 1)) {
    1279           5 :                         fbc = ce->constructor;
    1280             :                 }
    1281          52 :                 efree(lc_class_name);
    1282             :         }
    1283             : 
    1284        4418 :         if (EXPECTED(!fbc)) {
    1285        4413 :                 zval *func = zend_hash_find(&ce->function_table, lc_function_name);
    1286        4413 :                 if (EXPECTED(func != NULL)) {
    1287        4298 :                         fbc = Z_FUNC_P(func);
    1288             :                 } else {
    1289         115 :                         if (UNEXPECTED(!key)) {
    1290             :                                 zend_string_release(lc_function_name);
    1291             :                         }
    1292         225 :                         if (ce->__call &&
    1293          70 :                                 (object = zend_get_this_object(EG(current_execute_data))) != NULL &&
    1294          40 :                             instanceof_function(object->ce, ce)) {
    1295             :                                 /* Call the top-level defined __call().
    1296             :                                  * see: tests/classes/__call_004.phpt  */
    1297             : 
    1298          39 :                                 zend_class_entry *call_ce = object->ce;
    1299             : 
    1300          78 :                                 while (!call_ce->__call) {
    1301           0 :                                         call_ce = call_ce->parent;
    1302             :                                 }
    1303          39 :                                 return zend_get_user_call_function(call_ce, function_name);
    1304          76 :                         } else if (ce->__callstatic) {
    1305          53 :                                 return zend_get_user_callstatic_function(ce, function_name);
    1306             :                         } else {
    1307          23 :                                 return NULL;
    1308             :                         }
    1309             :                 }
    1310             :         }
    1311             : 
    1312             : #if MBO_0
    1313             :         /* right now this function is used for non static method lookup too */
    1314             :         /* Is the function static */
    1315             :         if (UNEXPECTED(!(fbc->common.fn_flags & ZEND_ACC_STATIC))) {
    1316             :                 zend_error_noreturn(E_ERROR, "Cannot call non static method %s::%s() without object", ZEND_FN_SCOPE_NAME(fbc), ZSTR_VAL(fbc->common.function_name));
    1317             :         }
    1318             : #endif
    1319        4303 :         if (fbc->op_array.fn_flags & ZEND_ACC_PUBLIC) {
    1320             :                 /* No further checks necessary, most common case */
    1321          45 :         } else if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
    1322             :                 zend_function *updated_fbc;
    1323             : 
    1324             :                 /* Ensure that if we're calling a private function, we're allowed to do so.
    1325             :                  */
    1326          17 :                 scope = zend_get_executed_scope();
    1327          17 :                 updated_fbc = zend_check_private_int(fbc, scope, lc_function_name);
    1328          17 :                 if (EXPECTED(updated_fbc != NULL)) {
    1329          10 :                         fbc = updated_fbc;
    1330             :                 } else {
    1331           7 :                         if (ce->__callstatic) {
    1332           1 :                                 fbc = zend_get_user_callstatic_function(ce, function_name);
    1333             :                         } else {
    1334           6 :                                 zend_throw_error(NULL, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), ZSTR_VAL(function_name), scope ? ZSTR_VAL(scope->name) : "");
    1335           6 :                                 fbc = NULL;
    1336             :                         }
    1337             :                 }
    1338          28 :         } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
    1339             :                 /* Ensure that if we're calling a protected function, we're allowed to do so.
    1340             :                  */
    1341          28 :                 scope = zend_get_executed_scope();
    1342          28 :                 if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fbc), scope))) {
    1343           3 :                         if (ce->__callstatic) {
    1344           1 :                                 fbc = zend_get_user_callstatic_function(ce, function_name);
    1345             :                         } else {
    1346           2 :                                 zend_throw_error(NULL, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), ZSTR_VAL(function_name), scope ? ZSTR_VAL(scope->name) : "");
    1347           2 :                                 fbc = NULL;
    1348             :                         }
    1349             :                 }
    1350             :         }
    1351             : 
    1352        4303 :         if (UNEXPECTED(!key)) {
    1353             :                 zend_string_release(lc_function_name);
    1354             :         }
    1355             : 
    1356        4303 :         return fbc;
    1357             : }
    1358             : /* }}} */
    1359             : 
    1360         816 : ZEND_API zval *zend_std_get_static_property(zend_class_entry *ce, zend_string *property_name, zend_bool silent) /* {{{ */
    1361             : {
    1362        1632 :         zend_property_info *property_info = zend_hash_find_ptr(&ce->properties_info, property_name);
    1363             :         zval *ret;
    1364             : 
    1365         816 :         if (UNEXPECTED(property_info == NULL)) {
    1366          23 :                 goto undeclared_property;
    1367             :         }
    1368             : 
    1369         793 :         if (UNEXPECTED(!zend_verify_property_access(property_info, ce))) {
    1370          29 :                 if (!silent) {
    1371           4 :                         zend_throw_error(NULL, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ZSTR_VAL(ce->name), ZSTR_VAL(property_name));
    1372             :                 }
    1373          29 :                 return NULL;
    1374             :         }
    1375             : 
    1376         764 :         if (UNEXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0)) {
    1377           0 :                 goto undeclared_property;
    1378             :         }
    1379             : 
    1380         764 :         if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED))) {
    1381          16 :                 if (UNEXPECTED(zend_update_class_constants(ce)) != SUCCESS) {
    1382           0 :                         return NULL;
    1383             :                 }
    1384             :         }
    1385         764 :         ret = CE_STATIC_MEMBERS(ce) + property_info->offset;
    1386             : 
    1387             :         /* check if static properties were destoyed */
    1388         764 :         if (UNEXPECTED(CE_STATIC_MEMBERS(ce) == NULL)) {
    1389             : undeclared_property:
    1390          23 :                 if (!silent) {
    1391          16 :                         zend_throw_error(NULL, "Access to undeclared static property: %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(property_name));
    1392             :                 }
    1393          23 :                 ret = NULL;
    1394             :         }
    1395             : 
    1396         787 :         return ret;
    1397             : }
    1398             : /* }}} */
    1399             : 
    1400           1 : ZEND_API ZEND_COLD zend_bool zend_std_unset_static_property(zend_class_entry *ce, zend_string *property_name) /* {{{ */
    1401             : {
    1402           1 :         zend_throw_error(NULL, "Attempt to unset static property %s::$%s", ZSTR_VAL(ce->name), ZSTR_VAL(property_name));
    1403           1 :         return 0;
    1404             : }
    1405             : /* }}} */
    1406             : 
    1407      783693 : ZEND_API union _zend_function *zend_std_get_constructor(zend_object *zobj) /* {{{ */
    1408             : {
    1409      783693 :         zend_function *constructor = zobj->ce->constructor;
    1410             :         zend_class_entry *scope;
    1411             : 
    1412      783693 :         if (constructor) {
    1413      588432 :                 if (constructor->op_array.fn_flags & ZEND_ACC_PUBLIC) {
    1414             :                         /* No further checks necessary */
    1415          21 :                 } else if (constructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
    1416             :                         /* Ensure that if we're calling a private function, we're allowed to do so.
    1417             :                          */
    1418          13 :                         if (EG(fake_scope)) {
    1419           2 :                                 scope = EG(fake_scope);
    1420             :                         } else {
    1421          11 :                                 scope = zend_get_executed_scope();
    1422             :                         }
    1423          13 :                         if (UNEXPECTED(constructor->common.scope != scope)) {
    1424           4 :                                 if (scope) {
    1425           1 :                                         zend_throw_error(NULL, "Call to private %s::%s() from context '%s'", ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name), ZSTR_VAL(scope->name));
    1426           1 :                                         constructor = NULL;
    1427             :                                 } else {
    1428           3 :                                         zend_throw_error(NULL, "Call to private %s::%s() from invalid context", ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name));
    1429           3 :                                         constructor = NULL;
    1430             :                                 }
    1431             :                         }
    1432           8 :                 } else if ((constructor->common.fn_flags & ZEND_ACC_PROTECTED)) {
    1433             :                         /* Ensure that if we're calling a protected function, we're allowed to do so.
    1434             :                          * Constructors only have prototype if they are defined by an interface but
    1435             :                          * it is the compilers responsibility to take care of the prototype.
    1436             :                          */
    1437           8 :                         if (EG(fake_scope)) {
    1438           2 :                                 scope = EG(fake_scope);
    1439             :                         } else {
    1440           6 :                                 scope = zend_get_executed_scope();
    1441             :                         }
    1442           8 :                         if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(constructor), scope))) {
    1443           2 :                                 if (scope) {
    1444           1 :                                         zend_throw_error(NULL, "Call to protected %s::%s() from context '%s'", ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name), ZSTR_VAL(scope->name));
    1445           1 :                                         constructor = NULL;
    1446             :                                 } else {
    1447           1 :                                         zend_throw_error(NULL, "Call to protected %s::%s() from invalid context", ZSTR_VAL(constructor->common.scope->name), ZSTR_VAL(constructor->common.function_name));
    1448           1 :                                         constructor = NULL;
    1449             :                                 }
    1450             :                         }
    1451             :                 }
    1452             :         }
    1453             : 
    1454      783693 :         return constructor;
    1455             : }
    1456             : /* }}} */
    1457             : 
    1458         545 : static int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */
    1459             : {
    1460             :         zend_object *zobj1, *zobj2;
    1461             : 
    1462         545 :         zobj1 = Z_OBJ_P(o1);
    1463         545 :         zobj2 = Z_OBJ_P(o2);
    1464             : 
    1465         545 :         if (zobj1->ce != zobj2->ce) {
    1466          33 :                 return 1; /* different classes */
    1467             :         }
    1468         512 :         if (!zobj1->properties && !zobj2->properties) {
    1469             :                 zval *p1, *p2, *end;
    1470             : 
    1471         194 :                 if (!zobj1->ce->default_properties_count) {
    1472          20 :                         return 0;
    1473             :                 }
    1474         174 :                 p1 = zobj1->properties_table;
    1475         174 :                 p2 = zobj2->properties_table;
    1476         174 :                 end = p1 + zobj1->ce->default_properties_count;
    1477         174 :                 Z_OBJ_PROTECT_RECURSION(o1);
    1478         173 :                 Z_OBJ_PROTECT_RECURSION(o2);
    1479             :                 do {
    1480         191 :                         if (Z_TYPE_P(p1) != IS_UNDEF) {
    1481         190 :                                 if (Z_TYPE_P(p2) != IS_UNDEF) {
    1482             :                                         zval result;
    1483             : 
    1484         190 :                                         if (compare_function(&result, p1, p2)==FAILURE) {
    1485           0 :                                                 Z_OBJ_UNPROTECT_RECURSION(o1);
    1486           0 :                                                 Z_OBJ_UNPROTECT_RECURSION(o2);
    1487           0 :                                                 return 1;
    1488             :                                         }
    1489         187 :                                         if (Z_LVAL(result) != 0) {
    1490         170 :                                                 Z_OBJ_UNPROTECT_RECURSION(o1);
    1491         170 :                                                 Z_OBJ_UNPROTECT_RECURSION(o2);
    1492         170 :                                                 return Z_LVAL(result);
    1493             :                                         }
    1494             :                                 } else {
    1495           0 :                                         Z_OBJ_UNPROTECT_RECURSION(o1);
    1496           0 :                                         Z_OBJ_UNPROTECT_RECURSION(o2);
    1497           0 :                                         return 1;
    1498             :                                 }
    1499             :                         } else {
    1500           1 :                                 if (Z_TYPE_P(p2) != IS_UNDEF) {
    1501           0 :                                         Z_OBJ_UNPROTECT_RECURSION(o1);
    1502           0 :                                         Z_OBJ_UNPROTECT_RECURSION(o2);
    1503           0 :                                         return 1;
    1504             :                                 }
    1505             :                         }
    1506          18 :                         p1++;
    1507          18 :                         p2++;
    1508          18 :                 } while (p1 != end);
    1509           0 :                 Z_OBJ_UNPROTECT_RECURSION(o1);
    1510           0 :                 Z_OBJ_UNPROTECT_RECURSION(o2);
    1511           0 :                 return 0;
    1512             :         } else {
    1513         318 :                 if (!zobj1->properties) {
    1514           1 :                         rebuild_object_properties(zobj1);
    1515             :                 }
    1516         318 :                 if (!zobj2->properties) {
    1517           2 :                         rebuild_object_properties(zobj2);
    1518             :                 }
    1519         318 :                 return zend_compare_symbol_tables(zobj1->properties, zobj2->properties);
    1520             :         }
    1521             : }
    1522             : /* }}} */
    1523             : 
    1524         435 : static int zend_std_has_property(zval *object, zval *member, int has_set_exists, void **cache_slot) /* {{{ */
    1525             : {
    1526             :         zend_object *zobj;
    1527             :         int result;
    1528         435 :         zval *value = NULL;
    1529             :         zval tmp_member;
    1530             :         uint32_t property_offset;
    1531             : 
    1532         435 :         zobj = Z_OBJ_P(object);
    1533             : 
    1534         435 :         ZVAL_UNDEF(&tmp_member);
    1535         435 :         if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
    1536         108 :                 ZVAL_STR(&tmp_member, zval_get_string(member));
    1537          54 :                 member = &tmp_member;
    1538          54 :                 cache_slot = NULL;
    1539             :         }
    1540             : 
    1541         870 :         property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), 1, cache_slot);
    1542             : 
    1543         435 :         if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
    1544         422 :                 if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) {
    1545         148 :                         value = OBJ_PROP(zobj, property_offset);
    1546         148 :                         if (Z_TYPE_P(value) != IS_UNDEF) {
    1547         113 :                                 goto found;
    1548             :                         }
    1549         442 :                 } else if (EXPECTED(zobj->properties != NULL) &&
    1550         168 :                            (value = zend_hash_find(zobj->properties, Z_STR_P(member))) != NULL) {
    1551             : found:
    1552         209 :                         switch (has_set_exists) {
    1553             :                                 case 0:
    1554         112 :                                         ZVAL_DEREF(value);
    1555         112 :                                         result = (Z_TYPE_P(value) != IS_NULL);
    1556         112 :                                         break;
    1557             :                                 default:
    1558          24 :                                         result = zend_is_true(value);
    1559          24 :                                         break;
    1560             :                                 case 2:
    1561          73 :                                         result = 1;
    1562             :                                         break;
    1563             :                         }
    1564         209 :                         goto exit;
    1565             :                 }
    1566          13 :         } else if (UNEXPECTED(EG(exception))) {
    1567           0 :                 result = 0;
    1568           0 :                 goto exit;
    1569             :         }
    1570             : 
    1571         226 :         result = 0;
    1572         226 :         if ((has_set_exists != 2) && zobj->ce->__isset) {
    1573          41 :                 uint32_t *guard = zend_get_property_guard(zobj, Z_STR_P(member));
    1574             : 
    1575          41 :                 if (!((*guard) & IN_ISSET)) {
    1576             :                         zval rv;
    1577             :                         zval tmp_object;
    1578             : 
    1579             :                         /* have issetter - try with it! */
    1580          30 :                         ZVAL_COPY(&tmp_object, object);
    1581          30 :                         (*guard) |= IN_ISSET; /* prevent circular getting */
    1582          30 :                         zend_std_call_issetter(&tmp_object, member, &rv);
    1583          30 :                         if (Z_TYPE(rv) != IS_UNDEF) {
    1584          30 :                                 result = zend_is_true(&rv);
    1585          30 :                                 zval_ptr_dtor(&rv);
    1586          30 :                                 if (has_set_exists && result) {
    1587           3 :                                         if (EXPECTED(!EG(exception)) && zobj->ce->__get && !((*guard) & IN_GET)) {
    1588           1 :                                                 (*guard) |= IN_GET;
    1589           1 :                                                 zend_std_call_getter(&tmp_object, member, &rv);
    1590           1 :                                                 (*guard) &= ~IN_GET;
    1591           1 :                                                 if (Z_TYPE(rv) != IS_UNDEF) {
    1592           1 :                                                         result = i_zend_is_true(&rv);
    1593           1 :                                                         zval_ptr_dtor(&rv);
    1594             :                                                 } else {
    1595           0 :                                                         result = 0;
    1596             :                                                 }
    1597             :                                         } else {
    1598           1 :                                                 result = 0;
    1599             :                                         }
    1600             :                                 }
    1601             :                         }
    1602          30 :                         (*guard) &= ~IN_ISSET;
    1603          30 :                         zval_ptr_dtor(&tmp_object);
    1604             :                 }
    1605             :         }
    1606             : 
    1607             : exit:
    1608         435 :         if (UNEXPECTED(Z_REFCOUNTED(tmp_member))) {
    1609          50 :                 zval_ptr_dtor(&tmp_member);
    1610             :         }
    1611         435 :         return result;
    1612             : }
    1613             : /* }}} */
    1614             : 
    1615        4406 : zend_string *zend_std_object_get_class_name(const zend_object *zobj) /* {{{ */
    1616             : {
    1617        8812 :         return zend_string_copy(zobj->ce->name);
    1618             : }
    1619             : /* }}} */
    1620             : 
    1621      467305 : ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type) /* {{{ */
    1622             : {
    1623             :         zval retval;
    1624             :         zend_class_entry *ce;
    1625             : 
    1626      467305 :         switch (type) {
    1627             :                 case IS_STRING:
    1628      304422 :                         ce = Z_OBJCE_P(readobj);
    1629      608440 :                         if (ce->__tostring &&
    1630      304018 :                                 (zend_call_method_with_0_params(readobj, ce, &ce->__tostring, "__tostring", &retval) || EG(exception))) {
    1631      304018 :                                 if (UNEXPECTED(EG(exception) != NULL)) {
    1632             :                                         zval *msg, ex, rv;
    1633           5 :                                         zval_ptr_dtor(&retval);
    1634           5 :                                         ZVAL_OBJ(&ex, EG(exception));
    1635           5 :                                         EG(exception) = NULL;
    1636           5 :                                         msg = zend_read_property(Z_OBJCE(ex), &ex, "message", sizeof("message") - 1, 1, &rv);
    1637           5 :                                         if (UNEXPECTED(Z_TYPE_P(msg) != IS_STRING)) {
    1638           0 :                                                 ZVAL_EMPTY_STRING(&rv);
    1639           0 :                                                 msg = &rv;
    1640             :                                         }
    1641          15 :                                         zend_error_noreturn(E_ERROR,
    1642             :                                                         "Method %s::__toString() must not throw an exception, caught %s: %s",
    1643          15 :                                                         ZSTR_VAL(ce->name), ZSTR_VAL(Z_OBJCE(ex)->name), Z_STRVAL_P(msg));
    1644             :                                         return FAILURE;
    1645             :                                 }
    1646      304013 :                                 if (EXPECTED(Z_TYPE(retval) == IS_STRING)) {
    1647      304009 :                                         if (readobj == writeobj) {
    1648           0 :                                                 zval_ptr_dtor(readobj);
    1649             :                                         }
    1650      304009 :                                         ZVAL_COPY_VALUE(writeobj, &retval);
    1651      304009 :                                         return SUCCESS;
    1652             :                                 } else {
    1653           4 :                                         zval_ptr_dtor(&retval);
    1654           4 :                                         if (readobj == writeobj) {
    1655           0 :                                                 zval_ptr_dtor(readobj);
    1656             :                                         }
    1657           4 :                                         ZVAL_EMPTY_STRING(writeobj);
    1658           4 :                                         zend_error(E_RECOVERABLE_ERROR, "Method %s::__toString() must return a string value", ZSTR_VAL(ce->name));
    1659           4 :                                         return SUCCESS;
    1660             :                                 }
    1661             :                         }
    1662         404 :                         return FAILURE;
    1663             :                 case _IS_BOOL:
    1664      162643 :                         ZVAL_BOOL(writeobj, 1);
    1665      162643 :                         return SUCCESS;
    1666             :                 case IS_LONG:
    1667         138 :                         ce = Z_OBJCE_P(readobj);
    1668         138 :                         zend_error(E_NOTICE, "Object of class %s could not be converted to int", ZSTR_VAL(ce->name));
    1669         138 :                         if (readobj == writeobj) {
    1670             :                                 zval_dtor(readobj);
    1671             :                         }
    1672         138 :                         ZVAL_LONG(writeobj, 1);
    1673         138 :                         return SUCCESS;
    1674             :                 case IS_DOUBLE:
    1675          42 :                         ce = Z_OBJCE_P(readobj);
    1676          42 :                         zend_error(E_NOTICE, "Object of class %s could not be converted to float", ZSTR_VAL(ce->name));
    1677          42 :                         if (readobj == writeobj) {
    1678             :                                 zval_dtor(readobj);
    1679             :                         }
    1680          42 :                         ZVAL_DOUBLE(writeobj, 1);
    1681          42 :                         return SUCCESS;
    1682             :                 default:
    1683          60 :                         ZVAL_NULL(writeobj);
    1684             :                         break;
    1685             :         }
    1686          60 :         return FAILURE;
    1687             : }
    1688             : /* }}} */
    1689             : 
    1690          86 : int zend_std_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr) /* {{{ */
    1691             : {
    1692             :         zval *func;
    1693             :         zend_class_entry *ce;
    1694             : 
    1695          86 :         if (Z_TYPE_P(obj) != IS_OBJECT) {
    1696           0 :                 return FAILURE;
    1697             :         }
    1698             : 
    1699          86 :         ce = Z_OBJCE_P(obj);
    1700             : 
    1701          86 :         if ((func = zend_hash_find(&ce->function_table, CG(known_strings)[ZEND_STR_MAGIC_INVOKE])) == NULL) {
    1702          60 :                 return FAILURE;
    1703             :         }
    1704          26 :         *fptr_ptr = Z_FUNC_P(func);
    1705             : 
    1706          26 :         *ce_ptr = ce;
    1707          26 :         if ((*fptr_ptr)->common.fn_flags & ZEND_ACC_STATIC) {
    1708           1 :                 if (obj_ptr) {
    1709           1 :                         *obj_ptr = NULL;
    1710             :                 }
    1711             :         } else {
    1712          25 :                 if (obj_ptr) {
    1713          25 :                         *obj_ptr = Z_OBJ_P(obj);
    1714             :                 }
    1715             :         }
    1716          26 :         return SUCCESS;
    1717             : }
    1718             : /* }}} */
    1719             : 
    1720             : ZEND_API zend_object_handlers std_object_handlers = {
    1721             :         0,                                                                              /* offset */
    1722             : 
    1723             :         zend_object_std_dtor,                                   /* free_obj */
    1724             :         zend_objects_destroy_object,                    /* dtor_obj */
    1725             :         zend_objects_clone_obj,                                 /* clone_obj */
    1726             : 
    1727             :         zend_std_read_property,                                 /* read_property */
    1728             :         zend_std_write_property,                                /* write_property */
    1729             :         zend_std_read_dimension,                                /* read_dimension */
    1730             :         zend_std_write_dimension,                               /* write_dimension */
    1731             :         zend_std_get_property_ptr_ptr,                  /* get_property_ptr_ptr */
    1732             :         NULL,                                                                   /* get */
    1733             :         NULL,                                                                   /* set */
    1734             :         zend_std_has_property,                                  /* has_property */
    1735             :         zend_std_unset_property,                                /* unset_property */
    1736             :         zend_std_has_dimension,                                 /* has_dimension */
    1737             :         zend_std_unset_dimension,                               /* unset_dimension */
    1738             :         zend_std_get_properties,                                /* get_properties */
    1739             :         zend_std_get_method,                                    /* get_method */
    1740             :         NULL,                                                                   /* call_method */
    1741             :         zend_std_get_constructor,                               /* get_constructor */
    1742             :         zend_std_object_get_class_name,                 /* get_class_name */
    1743             :         zend_std_compare_objects,                               /* compare_objects */
    1744             :         zend_std_cast_object_tostring,                  /* cast_object */
    1745             :         NULL,                                                                   /* count_elements */
    1746             :         zend_std_get_debug_info,                                /* get_debug_info */
    1747             :         zend_std_get_closure,                                   /* get_closure */
    1748             :         zend_std_get_gc,                                                /* get_gc */
    1749             :         NULL,                                                                   /* do_operation */
    1750             :         NULL,                                                                   /* compare */
    1751             : };
    1752             : 
    1753             : /*
    1754             :  * Local variables:
    1755             :  * tab-width: 4
    1756             :  * c-basic-offset: 4
    1757             :  * indent-tabs-mode: t
    1758             :  * End:
    1759             :  */

Generated by: LCOV version 1.10

Generated at Tue, 27 Sep 2016 10:25:52 +0000 (2 days ago)

Copyright © 2005-2016 The PHP Group
All rights reserved.