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

Generated by: LCOV version 1.10

Generated at Tue, 26 Jul 2016 17:07:30 +0000 (2 hours ago)

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