diff options
Diffstat (limited to 'ext')
77 files changed, 1798 insertions, 712 deletions
diff --git a/ext/com_dotnet/com_handlers.c b/ext/com_dotnet/com_handlers.c index 9c58732e0b..fd70a98ef7 100644 --- a/ext/com_dotnet/com_handlers.c +++ b/ext/com_dotnet/com_handlers.c @@ -58,7 +58,7 @@ static zval *com_property_read(zval *object, zval *member, int type, void **cahc return rv; } -static void com_property_write(zval *object, zval *member, zval *value, void **cache_slot) +static zval *com_property_write(zval *object, zval *member, zval *value, void **cache_slot) { php_com_dotnet_object *obj; VARIANT v; @@ -76,6 +76,7 @@ static void com_property_write(zval *object, zval *member, zval *value, void **c } else { php_com_throw_exception(E_INVALIDARG, "this variant has no properties"); } + return value; } static zval *com_read_dimension(zval *object, zval *offset, int type, zval *rv) diff --git a/ext/com_dotnet/com_saproxy.c b/ext/com_dotnet/com_saproxy.c index e5b390bca6..abdca04334 100644 --- a/ext/com_dotnet/com_saproxy.c +++ b/ext/com_dotnet/com_saproxy.c @@ -69,7 +69,7 @@ static inline void clone_indices(php_com_saproxy *dest, php_com_saproxy *src, in } } -static zval *saproxy_property_read(zval *object, zval *member, int type, void **cahce_slot, zval *rv) +static zval *saproxy_property_read(zval *object, zval *member, int type, void **cache_slot, zval *rv) { ZVAL_NULL(rv); diff --git a/ext/curl/multi.c b/ext/curl/multi.c index cacda1aef4..1a891a4ebc 100644 --- a/ext/curl/multi.c +++ b/ext/curl/multi.c @@ -265,7 +265,7 @@ PHP_FUNCTION(curl_multi_exec) ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_RESOURCE(z_mh) - Z_PARAM_ZVAL_DEREF(z_still_running) + Z_PARAM_ZVAL(z_still_running) ZEND_PARSE_PARAMETERS_END(); if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) { @@ -290,8 +290,7 @@ PHP_FUNCTION(curl_multi_exec) still_running = zval_get_long(z_still_running); error = curl_multi_perform(mh->multi, &still_running); - zval_ptr_dtor(z_still_running); - ZVAL_LONG(z_still_running, still_running); + ZEND_TRY_ASSIGN_LONG(z_still_running, still_running); SAVE_CURLM_ERROR(mh, error); RETURN_LONG((zend_long) error); @@ -338,7 +337,7 @@ PHP_FUNCTION(curl_multi_info_read) ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_RESOURCE(z_mh) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_DEREF(zmsgs_in_queue) + Z_PARAM_ZVAL(zmsgs_in_queue) ZEND_PARSE_PARAMETERS_END(); if ((mh = (php_curlm *)zend_fetch_resource(Z_RES_P(z_mh), le_curl_multi_handle_name, le_curl_multi_handle)) == NULL) { @@ -349,9 +348,9 @@ PHP_FUNCTION(curl_multi_info_read) if (tmp_msg == NULL) { RETURN_FALSE; } + if (zmsgs_in_queue) { - zval_ptr_dtor(zmsgs_in_queue); - ZVAL_LONG(zmsgs_in_queue, queued_msgs); + ZEND_TRY_ASSIGN_LONG(zmsgs_in_queue, queued_msgs); } array_init(return_value); diff --git a/ext/date/php_date.c b/ext/date/php_date.c index f40ec15e07..eb56deb558 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -660,10 +660,10 @@ static HashTable *date_object_get_debug_info_timezone(zval *object, int *is_temp static void php_timezone_to_string(php_timezone_obj *tzobj, zval *zv); zval *date_interval_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv); -void date_interval_write_property(zval *object, zval *member, zval *value, void **cache_slot); +zval *date_interval_write_property(zval *object, zval *member, zval *value, void **cache_slot); static zval *date_interval_get_property_ptr_ptr(zval *object, zval *member, int type, void **cache_slot); static zval *date_period_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv); -static void date_period_write_property(zval *object, zval *member, zval *value, void **cache_slot); +static zval *date_period_write_property(zval *object, zval *member, zval *value, void **cache_slot); /* {{{ Module struct */ zend_module_entry date_module_entry = { @@ -4211,7 +4211,7 @@ zval *date_interval_read_property(zval *object, zval *member, int type, void **c /* }}} */ /* {{{ date_interval_write_property */ -void date_interval_write_property(zval *object, zval *member, zval *value, void **cache_slot) +zval *date_interval_write_property(zval *object, zval *member, zval *value, void **cache_slot) { php_interval_obj *obj; zval tmp_member; @@ -4225,17 +4225,17 @@ void date_interval_write_property(zval *object, zval *member, zval *value, void obj = Z_PHPINTERVAL_P(object); if (!obj->initialized) { - zend_std_write_property(object, member, value, cache_slot); + value = zend_std_write_property(object, member, value, cache_slot); if (member == &tmp_member) { zval_ptr_dtor_str(&tmp_member); } - return; + return value; } #define SET_VALUE_FROM_STRUCT(n,m) \ if (strcmp(Z_STRVAL_P(member), m) == 0) { \ obj->diff->n = zval_get_long(value); \ - break; \ + break; \ } do { @@ -4251,12 +4251,14 @@ void date_interval_write_property(zval *object, zval *member, zval *value, void } SET_VALUE_FROM_STRUCT(invert, "invert"); /* didn't find any */ - zend_std_write_property(object, member, value, cache_slot); + value = zend_std_write_property(object, member, value, cache_slot); } while(0); if (member == &tmp_member) { zval_ptr_dtor_str(&tmp_member); } + + return value; } /* }}} */ @@ -5295,9 +5297,10 @@ static zval *date_period_read_property(zval *object, zval *member, int type, voi /* }}} */ /* {{{ date_period_write_property */ -static void date_period_write_property(zval *object, zval *member, zval *value, void **cache_slot) +static zval *date_period_write_property(zval *object, zval *member, zval *value, void **cache_slot) { zend_throw_error(NULL, "Writing to DatePeriod properties is unsupported"); + return value; } /* }}} */ diff --git a/ext/date/tests/DateInterval_write_property_return.phpt b/ext/date/tests/DateInterval_write_property_return.phpt new file mode 100644 index 0000000000..9c2c5c9137 --- /dev/null +++ b/ext/date/tests/DateInterval_write_property_return.phpt @@ -0,0 +1,14 @@ +--TEST-- +Test that return value handling for DateInterval property writes do not corrupt RHS +--FILE-- +<?php + +$interval = new DateInterval('P2Y4DT6H8M'); +$f = 0.5; +var_dump($interval->f = $f); +var_dump($f); + +?> +--EXPECT-- +float(0.5) +float(0.5) diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c index 72ae3c3ffe..a25a185e01 100644 --- a/ext/dom/php_dom.c +++ b/ext/dom/php_dom.c @@ -356,7 +356,7 @@ zval *dom_read_property(zval *object, zval *member, int type, void **cache_slot, /* }}} */ /* {{{ dom_write_property */ -void dom_write_property(zval *object, zval *member, zval *value, void **cache_slot) +zval *dom_write_property(zval *object, zval *member, zval *value, void **cache_slot) { dom_object *obj = Z_DOMOBJ_P(object); zend_string *member_str = zval_get_string(member); @@ -368,10 +368,12 @@ void dom_write_property(zval *object, zval *member, zval *value, void **cache_sl if (hnd) { hnd->write_func(obj, value); } else { - zend_std_write_property(object, member, value, cache_slot); + value = zend_std_write_property(object, member, value, cache_slot); } zend_string_release_ex(member_str, 0); + + return value; } /* }}} */ diff --git a/ext/enchant/enchant.c b/ext/enchant/enchant.c index 6b778092f9..595d41e9d4 100644 --- a/ext/enchant/enchant.c +++ b/ext/enchant/enchant.c @@ -711,13 +711,15 @@ PHP_FUNCTION(enchant_dict_quick_check) size_t wordlen; enchant_dict *pdict; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|z/", &dict, &word, &wordlen, &sugg) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|z", &dict, &word, &wordlen, &sugg) == FAILURE) { RETURN_FALSE; } if (sugg) { - zval_ptr_dtor(sugg); - array_init(sugg); + sugg = zend_try_array_init(sugg); + if (!sugg) { + return; + } } PHP_ENCHANT_GET_DICT; diff --git a/ext/exif/exif.c b/ext/exif/exif.c index 48e9372161..d37a61f83d 100644 --- a/ext/exif/exif.c +++ b/ext/exif/exif.c @@ -4606,9 +4606,9 @@ PHP_FUNCTION(exif_thumbnail) ZEND_PARSE_PARAMETERS_START(1, 4) Z_PARAM_ZVAL(stream) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_DEREF(z_width) - Z_PARAM_ZVAL_DEREF(z_height) - Z_PARAM_ZVAL_DEREF(z_imagetype) + Z_PARAM_ZVAL(z_width) + Z_PARAM_ZVAL(z_height) + Z_PARAM_ZVAL(z_imagetype) ZEND_PARSE_PARAMETERS_END(); memset(&ImageInfo, 0, sizeof(ImageInfo)); @@ -4653,14 +4653,11 @@ PHP_FUNCTION(exif_thumbnail) if (!ImageInfo.Thumbnail.width || !ImageInfo.Thumbnail.height) { exif_scan_thumbnail(&ImageInfo); } - zval_ptr_dtor(z_width); - zval_ptr_dtor(z_height); - ZVAL_LONG(z_width, ImageInfo.Thumbnail.width); - ZVAL_LONG(z_height, ImageInfo.Thumbnail.height); + ZEND_TRY_ASSIGN_LONG(z_width, ImageInfo.Thumbnail.width); + ZEND_TRY_ASSIGN_LONG(z_height, ImageInfo.Thumbnail.height); } if (arg_c >= 4) { - zval_ptr_dtor(z_imagetype); - ZVAL_LONG(z_imagetype, ImageInfo.Thumbnail.filetype); + ZEND_TRY_ASSIGN_LONG(z_imagetype, ImageInfo.Thumbnail.filetype); } #ifdef EXIF_DEBUG diff --git a/ext/ftp/php_ftp.c b/ext/ftp/php_ftp.c index 4b3a0fb306..5be151cb59 100644 --- a/ext/ftp/php_ftp.c +++ b/ext/ftp/php_ftp.c @@ -677,7 +677,7 @@ PHP_FUNCTION(ftp_alloc) zend_long size, ret; zend_string *response = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl|z/", &z_ftp, &size, &zresponse) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl|z", &z_ftp, &size, &zresponse) == FAILURE) { RETURN_FALSE; } @@ -686,9 +686,9 @@ PHP_FUNCTION(ftp_alloc) } ret = ftp_alloc(ftp, size, zresponse ? &response : NULL); + if (response) { - zval_ptr_dtor(zresponse); - ZVAL_STR(zresponse, response); + ZEND_TRY_ASSIGN_STR(zresponse, response); } if (!ret) { diff --git a/ext/intl/formatter/formatter_parse.c b/ext/intl/formatter/formatter_parse.c index 347f929cbd..4ee14b3ce3 100644 --- a/ext/intl/formatter/formatter_parse.c +++ b/ext/intl/formatter/formatter_parse.c @@ -51,7 +51,7 @@ PHP_FUNCTION( numfmt_parse ) FORMATTER_METHOD_INIT_VARS; /* Parse parameters. */ - if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Os|lz/!", + if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Os|lz!", &object, NumberFormatter_ce_ptr, &str, &str_len, &type, &zposition ) == FAILURE ) { intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, @@ -60,6 +60,11 @@ PHP_FUNCTION( numfmt_parse ) RETURN_FALSE; } + if(zposition) { + position = (int32_t) zval_get_long(zposition); + position_p = &position; + } + /* Fetch the object. */ FORMATTER_METHOD_FETCH_OBJECT; @@ -67,12 +72,6 @@ PHP_FUNCTION( numfmt_parse ) intl_convert_utf8_to_utf16(&sstr, &sstr_len, str, str_len, &INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "String conversion to UTF-16 failed" ); - if(zposition) { - ZVAL_DEREF(zposition); - position = (int32_t)zval_get_long( zposition ); - position_p = &position; - } - #if ICU_LOCALE_BUG && defined(LC_NUMERIC) /* need to copy here since setlocale may change it later */ oldlocale = estrdup(setlocale(LC_NUMERIC, NULL)); @@ -106,8 +105,7 @@ PHP_FUNCTION( numfmt_parse ) efree(oldlocale); #endif if(zposition) { - zval_ptr_dtor(zposition); - ZVAL_LONG(zposition, position); + ZEND_TRY_ASSIGN_LONG(zposition, position); } if (sstr) { @@ -138,7 +136,7 @@ PHP_FUNCTION( numfmt_parse_currency ) FORMATTER_METHOD_INIT_VARS; /* Parse parameters. */ - if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Osz/|z/!", + if( zend_parse_method_parameters( ZEND_NUM_ARGS(), getThis(), "Osz/|z!", &object, NumberFormatter_ce_ptr, &str, &str_len, &zcurrency, &zposition ) == FAILURE ) { intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, @@ -155,15 +153,13 @@ PHP_FUNCTION( numfmt_parse_currency ) INTL_METHOD_CHECK_STATUS( nfo, "String conversion to UTF-16 failed" ); if(zposition) { - ZVAL_DEREF(zposition); - position = (int32_t)zval_get_long( zposition ); + position = (int32_t) zval_get_long(zposition); position_p = &position; } number = unum_parseDoubleCurrency(FORMATTER_OBJECT(nfo), sstr, sstr_len, position_p, currency, &INTL_DATA_ERROR_CODE(nfo)); if(zposition) { - zval_ptr_dtor(zposition); - ZVAL_LONG(zposition, position); + ZEND_TRY_ASSIGN_LONG(zposition, position); } if (sstr) { efree(sstr); diff --git a/ext/intl/idn/idn.c b/ext/intl/idn/idn.c index 305a944cce..d717d46ee2 100644 --- a/ext/intl/idn/idn.c +++ b/ext/intl/idn/idn.c @@ -259,7 +259,7 @@ static void php_intl_idn_handoff(INTERNAL_FUNCTION_PARAMETERS, int mode) intl_error_reset(NULL); - if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|llz/", + if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|llz", &domain, &option, &variant, &idna_info) == FAILURE) { php_intl_bad_args("bad arguments"); RETURN_NULL(); /* don't set FALSE because that's not the way it was before... */ @@ -291,8 +291,10 @@ static void php_intl_idn_handoff(INTERNAL_FUNCTION_PARAMETERS, int mode) "4 arguments were provided, but INTL_IDNA_VARIANT_2003 only " "takes 3 - extra argument ignored"); } else { - zval_ptr_dtor(idna_info); - array_init(idna_info); + idna_info = zend_try_array_init(idna_info); + if (!idna_info) { + return; + } } } diff --git a/ext/intl/transliterator/transliterator_class.c b/ext/intl/transliterator/transliterator_class.c index e06ebd5c25..0f5d8cbf21 100644 --- a/ext/intl/transliterator/transliterator_class.c +++ b/ext/intl/transliterator/transliterator_class.c @@ -255,8 +255,7 @@ static zval *Transliterator_read_property( zval *object, zval *member, int type, /* }}} */ /* {{{ write_property handler */ -static void Transliterator_write_property( zval *object, zval *member, zval *value, - void **cache_slot ) +static zval *Transliterator_write_property( zval *object, zval *member, zval *value, void **cache_slot ) { zend_class_entry *scope; TRANSLITERATOR_PROPERTY_HANDLER_PROLOG; @@ -274,10 +273,12 @@ static void Transliterator_write_property( zval *object, zval *member, zval *val } else { - zend_std_write_property( object, member, value, cache_slot ); + value = zend_std_write_property( object, member, value, cache_slot ); } TRANSLITERATOR_PROPERTY_HANDLER_EPILOG; + + return value; } /* }}} */ diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c index 1ddf1a77ca..0528ea08d7 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -576,7 +576,11 @@ static void _php_ldap_controls_to_array(LDAP *ld, LDAPControl** ctrls, zval* arr zval tmp1; LDAPControl **ctrlp; - array_init(array); + array = zend_try_array_init(array); + if (!array) { + return; + } + if (ctrls == NULL) { return; } @@ -2975,7 +2979,7 @@ PHP_FUNCTION(ldap_get_option) ldap_linkdata *ld; zend_long option; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlz/", &link, &option, &retval) != SUCCESS) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlz", &link, &option, &retval) != SUCCESS) { return; } @@ -3017,8 +3021,7 @@ PHP_FUNCTION(ldap_get_option) if (ldap_get_option(ld->link, option, &val)) { RETURN_FALSE; } - zval_ptr_dtor(retval); - ZVAL_LONG(retval, val); + ZEND_TRY_ASSIGN_LONG(retval, val); } break; #ifdef LDAP_OPT_NETWORK_TIMEOUT case LDAP_OPT_NETWORK_TIMEOUT: @@ -3034,8 +3037,7 @@ PHP_FUNCTION(ldap_get_option) if (!timeout) { RETURN_FALSE; } - zval_ptr_dtor(retval); - ZVAL_LONG(retval, timeout->tv_sec); + ZEND_TRY_ASSIGN_LONG(retval, timeout->tv_sec); ldap_memfree(timeout); } break; #elif defined(LDAP_X_OPT_CONNECT_TIMEOUT) @@ -3046,8 +3048,7 @@ PHP_FUNCTION(ldap_get_option) if (ldap_get_option(ld->link, LDAP_X_OPT_CONNECT_TIMEOUT, &timeout)) { RETURN_FALSE; } - zval_ptr_dtor(retval); - ZVAL_LONG(retval, (timeout / 1000)); + ZEND_TRY_ASSIGN_LONG(retval, (timeout / 1000)); } break; #endif #ifdef LDAP_OPT_TIMEOUT @@ -3064,8 +3065,7 @@ PHP_FUNCTION(ldap_get_option) if (!timeout) { RETURN_FALSE; } - zval_ptr_dtor(retval); - ZVAL_LONG(retval, timeout->tv_sec); + ZEND_TRY_ASSIGN_LONG(retval, timeout->tv_sec); ldap_memfree(timeout); } break; #endif @@ -3112,8 +3112,7 @@ PHP_FUNCTION(ldap_get_option) } RETURN_FALSE; } - zval_ptr_dtor(retval); - ZVAL_STRING(retval, val); + ZEND_TRY_ASSIGN_STRING(retval, val); ldap_memfree(val); } break; case LDAP_OPT_SERVER_CONTROLS: @@ -3333,7 +3332,7 @@ PHP_FUNCTION(ldap_parse_result) char *lmatcheddn, *lerrmsg; int rc, lerrcode, myargcount = ZEND_NUM_ARGS(); - if (zend_parse_parameters(myargcount, "rrz/|z/z/z/z/", &link, &result, &errcode, &matcheddn, &errmsg, &referrals, &serverctrls) != SUCCESS) { + if (zend_parse_parameters(myargcount, "rrz|zzzz", &link, &result, &errcode, &matcheddn, &errmsg, &referrals, &serverctrls) != SUCCESS) { return; } @@ -3356,16 +3355,17 @@ PHP_FUNCTION(ldap_parse_result) RETURN_FALSE; } - zval_ptr_dtor(errcode); - ZVAL_LONG(errcode, lerrcode); + ZEND_TRY_ASSIGN_LONG(errcode, lerrcode); /* Reverse -> fall through */ switch (myargcount) { case 7: _php_ldap_controls_to_array(ld->link, lserverctrls, serverctrls, 0); case 6: - zval_ptr_dtor(referrals); - array_init(referrals); + referrals = zend_try_array_init(referrals); + if (!referrals) { + return; + } if (lreferrals != NULL) { refp = lreferrals; while (*refp) { @@ -3375,19 +3375,17 @@ PHP_FUNCTION(ldap_parse_result) ldap_memvfree((void**)lreferrals); } case 5: - zval_ptr_dtor(errmsg); if (lerrmsg == NULL) { - ZVAL_EMPTY_STRING(errmsg); + ZEND_TRY_ASSIGN_EMPTY_STRING(errmsg); } else { - ZVAL_STRING(errmsg, lerrmsg); + ZEND_TRY_ASSIGN_STRING(errmsg, lerrmsg); ldap_memfree(lerrmsg); } case 4: - zval_ptr_dtor(matcheddn); if (lmatcheddn == NULL) { - ZVAL_EMPTY_STRING(matcheddn); + ZEND_TRY_ASSIGN_EMPTY_STRING(matcheddn); } else { - ZVAL_STRING(matcheddn, lmatcheddn); + ZEND_TRY_ASSIGN_STRING(matcheddn, lmatcheddn); ldap_memfree(lmatcheddn); } } @@ -3398,7 +3396,7 @@ PHP_FUNCTION(ldap_parse_result) /* {{{ Extended operation response parsing, Pierangelo Masarati */ #ifdef HAVE_LDAP_PARSE_EXTENDED_RESULT -/* {{{ proto bool ldap_parse_exop(resource link, resource result [, string retdata [, string retoid]]) +/* {{{ proto bool ldap_parse_exop(resource link, resource result [, string &retdata [, string &retoid]]) Extract information from extended operation result */ PHP_FUNCTION(ldap_parse_exop) { @@ -3409,7 +3407,7 @@ PHP_FUNCTION(ldap_parse_exop) struct berval *lretdata; int rc, myargcount = ZEND_NUM_ARGS(); - if (zend_parse_parameters(myargcount, "rr|z/z/", &link, &result, &retdata, &retoid) != SUCCESS) { + if (zend_parse_parameters(myargcount, "rr|zz", &link, &result, &retdata, &retoid) != SUCCESS) { WRONG_PARAM_COUNT; } @@ -3433,20 +3431,18 @@ PHP_FUNCTION(ldap_parse_exop) /* Reverse -> fall through */ switch (myargcount) { case 4: - zval_ptr_dtor(retoid); if (lretoid == NULL) { - ZVAL_EMPTY_STRING(retoid); + ZEND_TRY_ASSIGN_EMPTY_STRING(retoid); } else { - ZVAL_STRING(retoid, lretoid); + ZEND_TRY_ASSIGN_STRING(retoid, lretoid); ldap_memfree(lretoid); } case 3: /* use arg #3 as the data returned by the server */ - zval_ptr_dtor(retdata); if (lretdata == NULL) { - ZVAL_EMPTY_STRING(retdata); + ZEND_TRY_ASSIGN_EMPTY_STRING(retdata); } else { - ZVAL_STRINGL(retdata, lretdata->bv_val, lretdata->bv_len); + ZEND_TRY_ASSIGN_STRINGL(retdata, lretdata->bv_val, lretdata->bv_len); ldap_memfree(lretdata->bv_val); ldap_memfree(lretdata); } @@ -3524,7 +3520,7 @@ PHP_FUNCTION(ldap_next_reference) /* }}} */ #ifdef HAVE_LDAP_PARSE_REFERENCE -/* {{{ proto bool ldap_parse_reference(resource link, resource reference_entry, array referrals) +/* {{{ proto bool ldap_parse_reference(resource link, resource reference_entry, array &referrals) Extract information from reference entry */ PHP_FUNCTION(ldap_parse_reference) { @@ -3533,7 +3529,7 @@ PHP_FUNCTION(ldap_parse_reference) ldap_resultentry *resultentry; char **lreferrals, **refp; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rrz/", &link, &result_entry, &referrals) != SUCCESS) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rrz", &link, &result_entry, &referrals) != SUCCESS) { return; } @@ -3549,8 +3545,11 @@ PHP_FUNCTION(ldap_parse_reference) RETURN_FALSE; } - zval_ptr_dtor(referrals); - array_init(referrals); + referrals = zend_try_array_init(referrals); + if (!referrals) { + return; + } + if (lreferrals != NULL) { refp = lreferrals; while (*refp) { @@ -4015,7 +4014,7 @@ PHP_FUNCTION(ldap_control_paged_result_response) ber_tag_t tag; int rc, lerrcode, myargcount = ZEND_NUM_ARGS(); - if (zend_parse_parameters(myargcount, "rr|z/z/", &link, &result, &cookie, &estimated) != SUCCESS) { + if (zend_parse_parameters(myargcount, "rr|zz", &link, &result, &cookie, &estimated) != SUCCESS) { return; } @@ -4082,15 +4081,13 @@ PHP_FUNCTION(ldap_control_paged_result_response) ldap_controls_free(lserverctrls); if (myargcount == 4) { - zval_ptr_dtor(estimated); - ZVAL_LONG(estimated, lestimated); + ZEND_TRY_ASSIGN_LONG(estimated, lestimated); } - zval_ptr_dtor(cookie); if (lcookie.bv_len == 0) { - ZVAL_EMPTY_STRING(cookie); + ZEND_TRY_ASSIGN_EMPTY_STRING(cookie); } else { - ZVAL_STRINGL(cookie, lcookie.bv_val, lcookie.bv_len); + ZEND_TRY_ASSIGN_STRINGL(cookie, lcookie.bv_val, lcookie.bv_len); } ldap_memfree(lcookie.bv_val); @@ -4115,7 +4112,7 @@ PHP_FUNCTION(ldap_exop) LDAPControl **lserverctrls = NULL; int rc, msgid; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS|S!a!z/z/", &link, &reqoid, &reqdata, &serverctrls, &retdata, &retoid) != SUCCESS) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS|S!a!zz", &link, &reqoid, &reqdata, &serverctrls, &retdata, &retoid) != SUCCESS) { return; } @@ -4153,22 +4150,20 @@ PHP_FUNCTION(ldap_exop) } if (retoid) { - zval_ptr_dtor(retoid); if (lretoid) { - ZVAL_STRING(retoid, lretoid); + ZEND_TRY_ASSIGN_STRING(retoid, lretoid); ldap_memfree(lretoid); } else { - ZVAL_EMPTY_STRING(retoid); + ZEND_TRY_ASSIGN_EMPTY_STRING(retoid); } } - zval_ptr_dtor(retdata); if (lretdata) { - ZVAL_STRINGL(retdata, lretdata->bv_val, lretdata->bv_len); + ZEND_TRY_ASSIGN_STRINGL(retdata, lretdata->bv_val, lretdata->bv_len); ldap_memfree(lretdata->bv_val); ldap_memfree(lretdata); } else { - ZVAL_EMPTY_STRING(retdata); + ZEND_TRY_ASSIGN_EMPTY_STRING(retdata); } RETVAL_TRUE; @@ -4219,7 +4214,7 @@ PHP_FUNCTION(ldap_exop_passwd) int rc, myargcount = ZEND_NUM_ARGS(), msgid, err; char* errmsg; - if (zend_parse_parameters(myargcount, "r|zzzz/", &link, &user, &oldpw, &newpw, &serverctrls) == FAILURE) { + if (zend_parse_parameters(myargcount, "r|zzzz", &link, &user, &oldpw, &newpw, &serverctrls) == FAILURE) { WRONG_PARAM_COUNT; } diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index cdca12b00e..264c6020ca 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -2131,14 +2131,15 @@ PHP_FUNCTION(mb_parse_str) const mbfl_encoding *detected; track_vars_array = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|z/", &encstr, &encstr_len, &track_vars_array) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|z", &encstr, &encstr_len, &track_vars_array) == FAILURE) { return; } if (track_vars_array != NULL) { - /* Clear out the array */ - zval_ptr_dtor(track_vars_array); - array_init(track_vars_array); + track_vars_array = zend_try_array_init(track_vars_array); + if (!track_vars_array) { + return; + } } encstr = estrndup(encstr, encstr_len); diff --git a/ext/mbstring/php_mbregex.c b/ext/mbstring/php_mbregex.c index cc96e04f39..d443999f74 100644 --- a/ext/mbstring/php_mbregex.c +++ b/ext/mbstring/php_mbregex.c @@ -863,13 +863,15 @@ static void _php_mb_regex_ereg_exec(INTERNAL_FUNCTION_PARAMETERS, int icase) OnigOptionType options; char *str; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs|z/", &arg_pattern, &string, &string_len, &array) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs|z", &arg_pattern, &string, &string_len, &array) == FAILURE) { RETURN_FALSE; } if (array != NULL) { - zval_ptr_dtor(array); - array_init(array); + array = zend_try_array_init(array); + if (!array) { + return; + } } if (!php_mb_check_encoding( diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c index f3d5e82309..b33ee41336 100644 --- a/ext/mysqli/mysqli.c +++ b/ext/mysqli/mysqli.c @@ -333,7 +333,7 @@ zval *mysqli_read_property(zval *object, zval *member, int type, void **cache_sl /* }}} */ /* {{{ mysqli_write_property */ -void mysqli_write_property(zval *object, zval *member, zval *value, void **cache_slot) +zval *mysqli_write_property(zval *object, zval *member, zval *value, void **cache_slot) { zval tmp_member; mysqli_object *obj; @@ -353,12 +353,14 @@ void mysqli_write_property(zval *object, zval *member, zval *value, void **cache if (hnd) { hnd->write_func(obj, value); } else { - zend_std_write_property(object, member, value, cache_slot); + value = zend_std_write_property(object, member, value, cache_slot); } if (member == &tmp_member) { zval_ptr_dtor_str(&tmp_member); } + + return value; } /* }}} */ diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c index 40c7d2982d..e805da9fa7 100644 --- a/ext/mysqli/mysqli_api.c +++ b/ext/mysqli/mysqli_api.c @@ -967,17 +967,11 @@ void mysqli_stmt_fetch_libmysql(INTERNAL_FUNCTION_PARAMETERS) zval *result; /* it must be a reference, isn't it? */ if (Z_ISREF(stmt->result.vars[i])) { - result = Z_REFVAL(stmt->result.vars[i]); + result = stmt->result.vars[i]; } else { - result = &stmt->result.vars[i]; + continue; // but be safe ... } - /* - QQ: Isn't it quite better to call zval_dtor(). What if the user has - assigned a resource, or an array to the bound variable? We are going - to leak probably. zval_dtor() will handle also Unicode/Non-unicode mode. - */ /* Even if the string is of length zero there is one byte alloced so efree() in all cases */ - zval_ptr_dtor(result); if (!stmt->result.is_null[i]) { switch (stmt->result.buf[i].type) { case IS_LONG: @@ -998,16 +992,16 @@ void mysqli_stmt_fetch_libmysql(INTERNAL_FUNCTION_PARAMETERS) } while (--j > 0); tmp[10]= '\0'; /* unsigned int > INT_MAX is 10 digits - ALWAYS */ - ZVAL_STRINGL(result, tmp, 10); + ZEND_TRY_ASSIGN_STRINGL(result, tmp, 10); efree(tmp); break; } #endif } if (stmt->stmt->fields[i].flags & UNSIGNED_FLAG) { - ZVAL_LONG(result, *(unsigned int *)stmt->result.buf[i].val); + ZEND_TRY_ASSIGN_LONG(result, *(unsigned int *)stmt->result.buf[i].val); } else { - ZVAL_LONG(result, *(int *)stmt->result.buf[i].val); + ZEND_TRY_ASSIGN_LONG(result, *(int *)stmt->result.buf[i].val); } break; case IS_DOUBLE: @@ -1024,7 +1018,7 @@ void mysqli_stmt_fetch_libmysql(INTERNAL_FUNCTION_PARAMETERS) dval = *((double *)stmt->result.buf[i].val); } - ZVAL_DOUBLE(result, dval); + ZEND_TRY_ASSIGN_DOUBLE(result, dval); break; } case IS_STRING: @@ -1065,20 +1059,20 @@ void mysqli_stmt_fetch_libmysql(INTERNAL_FUNCTION_PARAMETERS) * use MYSQLI_LL_SPEC. */ snprintf(tmp, sizeof(tmp), (stmt->stmt->fields[i].flags & UNSIGNED_FLAG)? MYSQLI_LLU_SPEC : MYSQLI_LL_SPEC, llval); - ZVAL_STRING(result, tmp); + ZEND_TRY_ASSIGN_STRING(result, tmp); } else { - ZVAL_LONG(result, llval); + ZEND_TRY_ASSIGN_LONG(result, llval); } } else { #if defined(MYSQL_DATA_TRUNCATED) && MYSQL_VERSION_ID > 50002 if (ret == MYSQL_DATA_TRUNCATED && *(stmt->stmt->bind[i].error) != 0) { /* result was truncated */ - ZVAL_STRINGL(result, stmt->result.buf[i].val, stmt->stmt->bind[i].buffer_length); + ZEND_TRY_ASSIGN_STRINGL(result, stmt->result.buf[i].val, stmt->stmt->bind[i].buffer_length); } else { #else { #endif - ZVAL_STRINGL(result, stmt->result.buf[i].val, stmt->result.buf[i].output_len); + ZEND_TRY_ASSIGN_STRINGL(result, stmt->result.buf[i].val, stmt->result.buf[i].output_len); } } break; @@ -1086,7 +1080,7 @@ void mysqli_stmt_fetch_libmysql(INTERNAL_FUNCTION_PARAMETERS) break; } } else { - ZVAL_NULL(result); + ZEND_TRY_ASSIGN_NULL(result); } } } else { diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index d8671b9da0..703c1f050a 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -761,15 +761,11 @@ mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, const unsign } for (i = 0; i < result->field_count; i++) { - zval *result = &stmt->result_bind[i].zv; - - ZVAL_DEREF(result); - /* Clean what we copied last time */ - zval_ptr_dtor(result); /* copy the type */ + zval *resultzv = &stmt->result_bind[i].zv; if (stmt->result_bind[i].bound == TRUE) { DBG_INF_FMT("i=%u type=%u", i, Z_TYPE(current_row[i])); - ZVAL_COPY(result, ¤t_row[i]); + ZEND_TRY_ASSIGN_COPY_EX(resultzv, ¤t_row[i], 0); } } } @@ -849,17 +845,15 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES * result, void * param, const unsi } for (i = 0; i < field_count; i++) { + zval *resultzv = &stmt->result_bind[i].zv; if (stmt->result_bind[i].bound == TRUE) { zval *data = &result->unbuf->last_row_data[i]; - zval *result = &stmt->result_bind[i].zv; if (Z_TYPE_P(data) == IS_STRING && (meta->fields[i].max_length < (zend_ulong) Z_STRLEN_P(data))){ meta->fields[i].max_length = Z_STRLEN_P(data); } - ZVAL_DEREF(result); - zval_ptr_dtor(result); - ZVAL_COPY_VALUE(result, data); + ZEND_TRY_ASSIGN_VALUE_EX(resultzv, data, 0); /* copied data, thus also the ownership. Thus null data */ ZVAL_NULL(data); } @@ -1025,12 +1019,10 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned /* If no result bind, do nothing. We consumed the data */ for (i = 0; i < field_count; i++) { + zval *resultzv = &stmt->result_bind[i].zv; if (stmt->result_bind[i].bound == TRUE) { zval *data = &result->unbuf->last_row_data[i]; - zval *result = &stmt->result_bind[i].zv; - ZVAL_DEREF(result); - zval_ptr_dtor(result); DBG_INF_FMT("i=%u bound_var=%p type=%u refc=%u", i, &stmt->result_bind[i].zv, Z_TYPE_P(data), Z_REFCOUNTED(stmt->result_bind[i].zv)? Z_REFCOUNT(stmt->result_bind[i].zv) : 0); @@ -1040,7 +1032,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned meta->fields[i].max_length = Z_STRLEN_P(data); } - ZVAL_COPY_VALUE(result, data); + ZEND_TRY_ASSIGN_VALUE_EX(resultzv, data, 0); /* copied data, thus also the ownership. Thus null data */ ZVAL_NULL(data); } @@ -1120,28 +1112,6 @@ MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const s, zend_bool * const fe SET_EMPTY_ERROR(stmt->error_info); SET_EMPTY_ERROR(conn->error_info); - DBG_INF_FMT("result_bind=%p separated_once=%u", &stmt->result_bind, stmt->result_zvals_separated_once); - /* - The user might have not bound any variables for result. - Do the binding once she does it. - */ - if (stmt->result_bind && !stmt->result_zvals_separated_once) { - unsigned int i; - /* - mysqlnd_stmt_store_result() has been called free the bind - variables to prevent leaking of their previous content. - */ - for (i = 0; i < stmt->result->field_count; i++) { - if (stmt->result_bind[i].bound == TRUE) { - zval *result = &stmt->result_bind[i].zv; - ZVAL_DEREF(result); - zval_ptr_dtor(result); - ZVAL_NULL(result); - } - } - stmt->result_zvals_separated_once = TRUE; - } - ret = stmt->result->m.fetch_row(stmt->result, (void*)s, 0, fetched_anything); DBG_RETURN(ret); } @@ -1537,7 +1507,6 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const s, } mysqlnd_stmt_separate_result_bind(s); - stmt->result_zvals_separated_once = FALSE; stmt->result_bind = result_bind; for (i = 0; i < stmt->field_count; i++) { /* Prevent from freeing */ diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h index 8a9018356e..a5c1359853 100644 --- a/ext/mysqlnd/mysqlnd_structs.h +++ b/ext/mysqlnd/mysqlnd_structs.h @@ -1309,7 +1309,6 @@ struct st_mysqlnd_stmt_data unsigned char send_types_to_server; MYSQLND_PARAM_BIND *param_bind; MYSQLND_RESULT_BIND *result_bind; - zend_bool result_zvals_separated_once; MYSQLND_UPSERT_STATUS * upsert_status; MYSQLND_UPSERT_STATUS upsert_status_impl; diff --git a/ext/oci8/oci8_interface.c b/ext/oci8/oci8_interface.c index 2e05afa527..8eda816bd5 100644 --- a/ext/oci8/oci8_interface.c +++ b/ext/oci8/oci8_interface.c @@ -1473,7 +1473,7 @@ PHP_FUNCTION(oci_fetch_all) ZEND_PARSE_PARAMETERS_START(2, 5) Z_PARAM_RESOURCE(z_statement) - Z_PARAM_ZVAL_DEREF_EX(array, 0, 1) + Z_PARAM_ZVAL(array) Z_PARAM_OPTIONAL Z_PARAM_LONG(skip) Z_PARAM_LONG(maxrows) @@ -1482,20 +1482,21 @@ PHP_FUNCTION(oci_fetch_all) PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement); - zval_ptr_dtor(array); - while (skip--) { if (php_oci_statement_fetch(statement, nrows)) { - array_init(array); + zend_try_array_init(array); RETURN_LONG(0); } } if (flags & PHP_OCI_FETCHSTATEMENT_BY_ROW) { /* Fetch by Row: array will contain one sub-array per query row */ - array_init(array); - columns = safe_emalloc(statement->ncolumns, sizeof(php_oci_out_column *), 0); + array = zend_try_array_init(array); + if (!array) { + return; + } + columns = safe_emalloc(statement->ncolumns, sizeof(php_oci_out_column *), 0); for (i = 0; i < statement->ncolumns; i++) { columns[ i ] = php_oci_statement_get_column(statement, i + 1, NULL, 0); } @@ -1534,7 +1535,11 @@ PHP_FUNCTION(oci_fetch_all) } else { /* default to BY_COLUMN */ /* Fetch by columns: array will contain one sub-array per query column */ - array_init_size(array, statement->ncolumns); + array = zend_try_array_init_size(array, statement->ncolumns); + if (!array) { + return; + } + columns = safe_emalloc(statement->ncolumns, sizeof(php_oci_out_column *), 0); outarrs = safe_emalloc(statement->ncolumns, sizeof(zval*), 0); diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index b7b67562a4..9156347e83 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -1876,13 +1876,13 @@ PHP_FUNCTION(odbc_fetch_into) #endif /* HAVE_SQL_EXTENDED_FETCH */ #ifdef HAVE_SQL_EXTENDED_FETCH - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|l", &pv_res, &pv_res_arr, &pv_row) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz|l", &pv_res, &pv_res_arr, &pv_row) == FAILURE) { return; } rownum = pv_row; #else - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/", &pv_res, &pv_res_arr) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz", &pv_res, &pv_res_arr) == FAILURE) { return; } #endif /* HAVE_SQL_EXTENDED_FETCH */ @@ -1896,8 +1896,9 @@ PHP_FUNCTION(odbc_fetch_into) RETURN_FALSE; } - if (Z_TYPE_P(pv_res_arr) != IS_ARRAY) { - array_init(pv_res_arr); + pv_res_arr = zend_try_array_init(pv_res_arr); + if (!pv_res_arr) { + return; } #ifdef HAVE_SQL_EXTENDED_FETCH diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c index 9e3a0ab9a1..397458365f 100644 --- a/ext/opcache/Optimizer/compact_literals.c +++ b/ext/opcache/Optimizer/compact_literals.c @@ -108,7 +108,7 @@ static uint32_t add_static_slot(HashTable *hash, ret = Z_LVAL_P(pos); } else { ret = *cache_size; - *cache_size += 2 * sizeof(void *); + *cache_size += (kind == LITERAL_STATIC_PROPERTY ? 3 : 2) * sizeof(void *); ZVAL_LONG(&tmp, ret); zend_hash_add(hash, key, &tmp); } @@ -183,6 +183,8 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx } LITERAL_INFO(opline->op2.constant, LITERAL_CLASS_CONST, 1); break; + case ZEND_ASSIGN_STATIC_PROP: + case ZEND_ASSIGN_STATIC_PROP_REF: case ZEND_FETCH_STATIC_PROP_R: case ZEND_FETCH_STATIC_PROP_W: case ZEND_FETCH_STATIC_PROP_RW: @@ -191,6 +193,11 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx case ZEND_FETCH_STATIC_PROP_FUNC_ARG: case ZEND_UNSET_STATIC_PROP: case ZEND_ISSET_ISEMPTY_STATIC_PROP: + case ZEND_PRE_INC_STATIC_PROP: + case ZEND_PRE_DEC_STATIC_PROP: + case ZEND_POST_INC_STATIC_PROP: + case ZEND_POST_DEC_STATIC_PROP: +literals_handle_static_prop: if (opline->op2_type == IS_CONST) { LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 2); } @@ -210,6 +217,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx } break; case ZEND_ASSIGN_OBJ: + case ZEND_ASSIGN_OBJ_REF: case ZEND_FETCH_OBJ_R: case ZEND_FETCH_OBJ_W: case ZEND_FETCH_OBJ_RW: @@ -238,6 +246,9 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx case ZEND_ASSIGN_BW_OR: case ZEND_ASSIGN_BW_AND: case ZEND_ASSIGN_BW_XOR: + if (opline->extended_value == ZEND_ASSIGN_STATIC_PROP) { + goto literals_handle_static_prop; + } if (opline->op2_type == IS_CONST) { if (opline->extended_value == ZEND_ASSIGN_OBJ) { LITERAL_INFO(opline->op2.constant, LITERAL_PROPERTY, 1); @@ -547,24 +558,48 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx case ZEND_ASSIGN_BW_OR: case ZEND_ASSIGN_BW_AND: case ZEND_ASSIGN_BW_XOR: - if (opline->extended_value != ZEND_ASSIGN_OBJ) { - break; + if (opline->extended_value == ZEND_ASSIGN_STATIC_PROP) { + if (opline->op1_type == IS_CONST) { + // op1 static property + if (opline->op2_type == IS_CONST) { + (opline+1)->extended_value = add_static_slot(&hash, op_array, + opline->op2.constant, + opline->op1.constant, + LITERAL_STATIC_PROPERTY, + &cache_size); + } else { + (opline+1)->extended_value = cache_size; + cache_size += 3 * sizeof(void *); + } + } else if (opline->op2_type == IS_CONST) { + // op2 class + if (class_slot[opline->op2.constant] >= 0) { + (opline+1)->extended_value = class_slot[opline->op2.constant]; + } else { + (opline+1)->extended_value = cache_size; + class_slot[opline->op2.constant] = cache_size; + cache_size += sizeof(void *); + } + } } - if (opline->op2_type == IS_CONST) { - // op2 property - if (opline->op1_type == IS_UNUSED && - property_slot[opline->op2.constant] >= 0) { - (opline+1)->extended_value = property_slot[opline->op2.constant]; - } else { - (opline+1)->extended_value = cache_size; - cache_size += 2 * sizeof(void *); - if (opline->op1_type == IS_UNUSED) { - property_slot[opline->op2.constant] = (opline+1)->extended_value; + if (opline->extended_value == ZEND_ASSIGN_OBJ) { + if (opline->op2_type == IS_CONST) { + // op2 property + if (opline->op1_type == IS_UNUSED && + property_slot[opline->op2.constant] >= 0) { + (opline+1)->extended_value = property_slot[opline->op2.constant]; + } else { + (opline+1)->extended_value = cache_size; + cache_size += 3 * sizeof(void *); + if (opline->op1_type == IS_UNUSED) { + property_slot[opline->op2.constant] = (opline+1)->extended_value; + } } } } break; case ZEND_ASSIGN_OBJ: + case ZEND_ASSIGN_OBJ_REF: case ZEND_FETCH_OBJ_R: case ZEND_FETCH_OBJ_W: case ZEND_FETCH_OBJ_RW: @@ -580,12 +615,12 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx // op2 property if (opline->op1_type == IS_UNUSED && property_slot[opline->op2.constant] >= 0) { - opline->extended_value = property_slot[opline->op2.constant]; + opline->extended_value = property_slot[opline->op2.constant] | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS); } else { - opline->extended_value = cache_size; - cache_size += 2 * sizeof(void *); + opline->extended_value = cache_size | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS); + cache_size += 3 * sizeof(void *); if (opline->op1_type == IS_UNUSED) { - property_slot[opline->op2.constant] = opline->extended_value; + property_slot[opline->op2.constant] = opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS; } } } @@ -598,7 +633,7 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx opline->extended_value = property_slot[opline->op2.constant] | (opline->extended_value & ZEND_ISEMPTY); } else { opline->extended_value = cache_size | (opline->extended_value & ZEND_ISEMPTY); - cache_size += 2 * sizeof(void *); + cache_size += 3 * sizeof(void *); if (opline->op1_type == IS_UNUSED) { property_slot[opline->op2.constant] = opline->extended_value & ~ZEND_ISEMPTY; } @@ -689,6 +724,8 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx cache_size += 2 * sizeof(void *); } break; + case ZEND_ASSIGN_STATIC_PROP: + case ZEND_ASSIGN_STATIC_PROP_REF: case ZEND_FETCH_STATIC_PROP_R: case ZEND_FETCH_STATIC_PROP_W: case ZEND_FETCH_STATIC_PROP_RW: @@ -696,30 +733,11 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx case ZEND_FETCH_STATIC_PROP_UNSET: case ZEND_FETCH_STATIC_PROP_FUNC_ARG: case ZEND_UNSET_STATIC_PROP: - if (opline->op1_type == IS_CONST) { - // op1 static property - if (opline->op2_type == IS_CONST) { - opline->extended_value = add_static_slot(&hash, op_array, - opline->op2.constant, - opline->op1.constant, - LITERAL_STATIC_PROPERTY, - &cache_size); - } else { - opline->extended_value = cache_size; - cache_size += 2 * sizeof(void *); - } - } else if (opline->op2_type == IS_CONST) { - // op2 class - if (class_slot[opline->op2.constant] >= 0) { - opline->extended_value = class_slot[opline->op2.constant]; - } else { - opline->extended_value = cache_size; - cache_size += sizeof(void *); - class_slot[opline->op2.constant] = opline->extended_value; - } - } - break; case ZEND_ISSET_ISEMPTY_STATIC_PROP: + case ZEND_PRE_INC_STATIC_PROP: + case ZEND_PRE_DEC_STATIC_PROP: + case ZEND_POST_INC_STATIC_PROP: + case ZEND_POST_DEC_STATIC_PROP: if (opline->op1_type == IS_CONST) { // op1 static property if (opline->op2_type == IS_CONST) { @@ -727,19 +745,19 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx opline->op2.constant, opline->op1.constant, LITERAL_STATIC_PROPERTY, - &cache_size) | (opline->extended_value & ZEND_ISEMPTY); + &cache_size) | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS); } else { - opline->extended_value = cache_size | (opline->extended_value & ZEND_ISEMPTY); - cache_size += 2 * sizeof(void *); + opline->extended_value = cache_size | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS); + cache_size += 3 * sizeof(void *); } } else if (opline->op2_type == IS_CONST) { // op2 class if (class_slot[opline->op2.constant] >= 0) { - opline->extended_value = class_slot[opline->op2.constant] | (opline->extended_value & ZEND_ISEMPTY); + opline->extended_value = class_slot[opline->op2.constant] | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS); } else { - opline->extended_value = cache_size | (opline->extended_value & ZEND_ISEMPTY); + opline->extended_value = cache_size | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS); + class_slot[opline->op2.constant] = cache_size; cache_size += sizeof(void *); - class_slot[opline->op2.constant] = opline->extended_value & ~ZEND_ISEMPTY; } } break; diff --git a/ext/opcache/Optimizer/dce.c b/ext/opcache/Optimizer/dce.c index 89898393a7..95755d559f 100644 --- a/ext/opcache/Optimizer/dce.c +++ b/ext/opcache/Optimizer/dce.c @@ -330,6 +330,9 @@ static zend_bool try_remove_var_def(context *ctx, int free_var, int use_chain, z case ZEND_ASSIGN_REF: case ZEND_ASSIGN_DIM: case ZEND_ASSIGN_OBJ: + case ZEND_ASSIGN_OBJ_REF: + case ZEND_ASSIGN_STATIC_PROP: + case ZEND_ASSIGN_STATIC_PROP_REF: case ZEND_ASSIGN_ADD: case ZEND_ASSIGN_SUB: case ZEND_ASSIGN_MUL: diff --git a/ext/opcache/Optimizer/escape_analysis.c b/ext/opcache/Optimizer/escape_analysis.c index f88de6202a..a92d773783 100644 --- a/ext/opcache/Optimizer/escape_analysis.c +++ b/ext/opcache/Optimizer/escape_analysis.c @@ -217,6 +217,7 @@ static int is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, in break; case ZEND_ASSIGN_DIM: case ZEND_ASSIGN_OBJ: + case ZEND_ASSIGN_OBJ_REF: if (OP1_INFO() & (MAY_BE_UNDEF | MAY_BE_NULL | MAY_BE_FALSE)) { /* implicit object/array allocation */ return 1; @@ -259,6 +260,7 @@ static int is_local_def(zend_op_array *op_array, zend_ssa *ssa, int def, int var return 1; case ZEND_ASSIGN_DIM: case ZEND_ASSIGN_OBJ: + case ZEND_ASSIGN_OBJ_REF: return 1; case ZEND_ASSIGN_ADD: case ZEND_ASSIGN_SUB: @@ -328,6 +330,7 @@ static int is_escape_use(zend_op_array *op_array, zend_ssa *ssa, int use, int va /* break missing intentionally */ case ZEND_ASSIGN_DIM: case ZEND_ASSIGN_OBJ: + case ZEND_ASSIGN_OBJ_REF: break; case ZEND_PRE_INC_OBJ: case ZEND_PRE_DEC_OBJ: @@ -508,7 +511,8 @@ int zend_ssa_escape_analysis(const zend_script *script, zend_op_array *op_array, if (opline->opcode == ZEND_OP_DATA && ((opline-1)->opcode == ZEND_ASSIGN_DIM || - (opline-1)->opcode == ZEND_ASSIGN_OBJ) && + (opline-1)->opcode == ZEND_ASSIGN_OBJ || + (opline-1)->opcode == ZEND_ASSIGN_OBJ_REF) && op->op1_use == i && (op-1)->op1_use >= 0) { enclosing_root = ees[(op-1)->op1_use]; diff --git a/ext/opcache/Optimizer/sccp.c b/ext/opcache/Optimizer/sccp.c index 08e1584923..69a3e81c6b 100644 --- a/ext/opcache/Optimizer/sccp.c +++ b/ext/opcache/Optimizer/sccp.c @@ -203,6 +203,7 @@ static zend_bool can_replace_op1( case ZEND_ASSIGN_REF: case ZEND_ASSIGN_DIM: case ZEND_ASSIGN_OBJ: + case ZEND_ASSIGN_OBJ_REF: case ZEND_ASSIGN_ADD: case ZEND_ASSIGN_SUB: case ZEND_ASSIGN_MUL: @@ -251,6 +252,9 @@ static zend_bool can_replace_op1( case ZEND_VERIFY_RETURN_TYPE: // TODO: This would require a non-local change ??? return 0; + case ZEND_OP_DATA: + return (opline - 1)->opcode != ZEND_ASSIGN_OBJ_REF && + (opline - 1)->opcode != ZEND_ASSIGN_STATIC_PROP_REF; default: if (ssa_op->op1_def != -1) { ZEND_ASSERT(0); @@ -1400,7 +1404,7 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o if (op2) { SKIP_IF_TOP(op2); } - if (!opline->extended_value) { + if (opline->extended_value == 0) { if (zend_optimizer_eval_binary_op(&zv, zend_compound_assign_to_binary_op(opline->opcode), op1, op2) == SUCCESS) { SET_RESULT(op1, &zv); SET_RESULT(result, &zv); @@ -1494,6 +1498,11 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o zval_ptr_dtor_nogc(&zv); } } + } else if (opline->extended_value == ZEND_ASSIGN_STATIC_PROP) { + SET_RESULT_BOT(result); + break; + } else { + ZEND_ASSERT(0 && "Invalid compound assignment kind"); } SET_RESULT_BOT(result); SET_RESULT_BOT(op1); diff --git a/ext/opcache/Optimizer/zend_dfg.c b/ext/opcache/Optimizer/zend_dfg.c index 4430f193a8..66dd15da00 100644 --- a/ext/opcache/Optimizer/zend_dfg.c +++ b/ext/opcache/Optimizer/zend_dfg.c @@ -52,8 +52,14 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg if (next < end && next->opcode == ZEND_OP_DATA) { if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { var_num = EX_VAR_TO_NUM(next->op1.var); - if (!DFG_ISSET(def, set_size, j, var_num)) { + if (opline->opcode == ZEND_ASSIGN_OBJ_REF + || opline->opcode == ZEND_ASSIGN_STATIC_PROP_REF) { DFG_SET(use, set_size, j, var_num); + DFG_SET(def, set_size, j, var_num); + } else { + if (!DFG_ISSET(def, set_size, j, var_num)) { + DFG_SET(use, set_size, j, var_num); + } } } if (next->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) { @@ -92,6 +98,7 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg case ZEND_UNSET_CV: case ZEND_ASSIGN: case ZEND_ASSIGN_REF: + case ZEND_ASSIGN_OBJ_REF: case ZEND_BIND_GLOBAL: case ZEND_BIND_STATIC: case ZEND_SEND_VAR_EX: diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c index 90107785b7..d5f6c4564b 100644 --- a/ext/opcache/Optimizer/zend_dump.c +++ b/ext/opcache/Optimizer/zend_dump.c @@ -451,6 +451,8 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block * fprintf(stderr, " (dim)"); } else if (opline->extended_value == ZEND_ASSIGN_OBJ) { fprintf(stderr, " (obj)"); + } else if (opline->extended_value == ZEND_ASSIGN_STATIC_PROP) { + fprintf(stderr, " (static prop)"); } } else if (ZEND_VM_EXT_TYPE == (flags & ZEND_VM_EXT_MASK)) { switch (opline->extended_value) { @@ -554,7 +556,7 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block * } else if (ZEND_VM_EXT_SRC == (flags & ZEND_VM_EXT_MASK)) { if (opline->extended_value == ZEND_RETURNS_VALUE) { fprintf(stderr, " (value)"); - } else if (opline->extended_value == ZEND_RETURNS_FUNCTION) { + } else if (opline->extended_value & ZEND_RETURNS_FUNCTION) { fprintf(stderr, " (function)"); } } else { @@ -585,6 +587,16 @@ static void zend_dump_op(const zend_op_array *op_array, const zend_basic_block * fprintf(stderr, " (ref)"); } } + if ((ZEND_VM_EXT_DIM_OBJ_WRITE|ZEND_VM_EXT_FETCH_REF) & flags) { + uint32_t obj_flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS; + if (obj_flags == ZEND_FETCH_REF) { + fprintf(stderr, " (ref)"); + } else if (obj_flags == ZEND_FETCH_DIM_WRITE) { + fprintf(stderr, " (dim write)"); + } else if (obj_flags == ZEND_FETCH_OBJ_WRITE) { + fprintf(stderr, " (obj write)"); + } + } } if (opline->op1_type == IS_CONST) { diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 9f1dfdba20..980f3c5fea 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -2240,6 +2240,24 @@ static inline zend_class_entry *get_class_entry(const zend_script *script, zend_ return NULL; } +static uint32_t zend_convert_type_code_to_may_be(zend_uchar type_code) { + switch (type_code) { + case IS_VOID: + return MAY_BE_NULL; + case IS_CALLABLE: + return MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; + case IS_ITERABLE: + return MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; + case IS_ARRAY: + return MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; + case _IS_BOOL: + return MAY_BE_TRUE|MAY_BE_FALSE; + default: + ZEND_ASSERT(type_code < IS_REFERENCE); + return 1 << type_code; + } +} + static uint32_t zend_fetch_arg_info(const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce) { uint32_t tmp = 0; @@ -2252,22 +2270,7 @@ static uint32_t zend_fetch_arg_info(const zend_script *script, zend_arg_info *ar *pce = get_class_entry(script, lcname); zend_string_release_ex(lcname, 0); } else if (ZEND_TYPE_IS_CODE(arg_info->type)) { - zend_uchar type_hint = ZEND_TYPE_CODE(arg_info->type); - - if (type_hint == IS_VOID) { - tmp |= MAY_BE_NULL; - } else if (type_hint == IS_CALLABLE) { - tmp |= MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; - } else if (type_hint == IS_ITERABLE) { - tmp |= MAY_BE_OBJECT|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; - } else if (type_hint == IS_ARRAY) { - tmp |= MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; - } else if (type_hint == _IS_BOOL) { - tmp |= MAY_BE_TRUE|MAY_BE_FALSE; - } else { - ZEND_ASSERT(type_hint < IS_REFERENCE); - tmp |= 1 << type_hint; - } + tmp |= zend_convert_type_code_to_may_be(ZEND_TYPE_CODE(arg_info->type)); } else { tmp |= MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; } @@ -2277,6 +2280,123 @@ static uint32_t zend_fetch_arg_info(const zend_script *script, zend_arg_info *ar return tmp; } +static zend_property_info *lookup_prop_info(zend_class_entry *ce, zend_string *name, zend_class_entry *scope) { + zend_property_info *prop_info; + + /* If the class is linked, reuse the precise runtime logic. */ + if (ce->ce_flags & ZEND_ACC_LINKED) { + zend_class_entry *prev_scope = EG(fake_scope); + EG(fake_scope) = scope; + prop_info = zend_get_property_info(ce, name, 1); + EG(fake_scope) = prev_scope; + if (prop_info && prop_info != ZEND_WRONG_PROPERTY_INFO) { + return prop_info; + } + return NULL; + } + + /* Otherwise, handle only some safe cases */ + prop_info = zend_hash_find_ptr(&ce->properties_info, name); + if (prop_info && + ((prop_info->ce == scope) || + (!scope && (prop_info->flags & ZEND_ACC_PUBLIC))) + ) { + return prop_info; + } + return NULL; +} + +static zend_property_info *zend_fetch_prop_info(const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, int i) +{ + zend_property_info *prop_info = NULL; + if (opline->op2_type == IS_CONST) { + zend_class_entry *ce = NULL; + + if (opline->op1_type == IS_UNUSED) { + ce = op_array->scope; + } else if (ssa->ops[i].op1_use >= 0) { + ce = ssa->var_info[ssa->ops[i].op1_use].ce; + } + if (ce) { + prop_info = lookup_prop_info(ce, + Z_STR_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)), + op_array->scope); + if (prop_info && (prop_info->flags & ZEND_ACC_STATIC)) { + prop_info = NULL; + } + } + } + return prop_info; +} + +static zend_property_info *zend_fetch_static_prop_info(const zend_script *script, const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline) +{ + zend_property_info *prop_info = NULL; + if (opline->op1_type == IS_CONST) { + zend_class_entry *ce = NULL; + if (opline->op2_type == IS_UNUSED) { + int fetch_type = opline->op2.num & ZEND_FETCH_CLASS_MASK; + switch (fetch_type) { + case ZEND_FETCH_CLASS_SELF: + case ZEND_FETCH_CLASS_STATIC: + /* We enforce that static property types cannot change during inheritance, so + * handling static the same way as self here is legal. */ + ce = op_array->scope; + break; + case ZEND_FETCH_CLASS_PARENT: + if (op_array->scope) { + ce = op_array->scope->parent; + } + break; + } + } else if (opline->op2_type == IS_CONST) { + zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants); + ce = get_class_entry(script, Z_STR_P(zv + 1)); + } + + if (ce) { + zval *zv = CRT_CONSTANT_EX(op_array, opline, opline->op1, ssa->rt_constants); + prop_info = lookup_prop_info(ce, Z_STR_P(zv), op_array->scope); + if (prop_info && !(prop_info->flags & ZEND_ACC_STATIC)) { + prop_info = NULL; + } + } + } + return prop_info; +} + +static uint32_t zend_fetch_prop_type(const zend_script *script, zend_property_info *prop_info, zend_class_entry **pce) +{ + if (prop_info && ZEND_TYPE_IS_SET(prop_info->type)) { + uint32_t type = ZEND_TYPE_IS_CLASS(prop_info->type) + ? MAY_BE_OBJECT + : zend_convert_type_code_to_may_be(ZEND_TYPE_CODE(prop_info->type)); + + if (ZEND_TYPE_ALLOW_NULL(prop_info->type)) { + type |= MAY_BE_NULL; + } + if (type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { + type |= MAY_BE_RC1 | MAY_BE_RCN; + } + if (pce) { + if (ZEND_TYPE_IS_CE(prop_info->type)) { + *pce = ZEND_TYPE_CE(prop_info->type); + } else if (ZEND_TYPE_IS_NAME(prop_info->type)) { + zend_string *lcname = zend_string_tolower(ZEND_TYPE_NAME(prop_info->type)); + *pce = get_class_entry(script, lcname); + zend_string_release(lcname); + } else { + *pce = NULL; + } + } + return type; + } + if (pce) { + *pce = NULL; + } + return MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_RC1 | MAY_BE_RCN; +} + static int zend_update_type_info(const zend_op_array *op_array, zend_ssa *ssa, const zend_script *script, @@ -2474,13 +2594,14 @@ static int zend_update_type_info(const zend_op_array *op_array, case ZEND_ASSIGN_BW_OR: case ZEND_ASSIGN_BW_AND: case ZEND_ASSIGN_BW_XOR: - case ZEND_ASSIGN_CONCAT: + case ZEND_ASSIGN_CONCAT: { + zend_property_info *prop_info = NULL; orig = 0; tmp = 0; if (opline->extended_value == ZEND_ASSIGN_OBJ) { - tmp |= MAY_BE_REF; + prop_info = zend_fetch_prop_info(op_array, ssa, opline, i); orig = t1; - t1 = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; + t1 = zend_fetch_prop_type(script, prop_info, &ce); t2 = OP1_DATA_INFO(); } else if (opline->extended_value == ZEND_ASSIGN_DIM) { if (t1 & MAY_BE_ARRAY_OF_REF) { @@ -2489,6 +2610,10 @@ static int zend_update_type_info(const zend_op_array *op_array, orig = t1; t1 = zend_array_element_type(t1, 1, 0); t2 = OP1_DATA_INFO(); + } else if (opline->extended_value == ZEND_ASSIGN_STATIC_PROP) { + prop_info = zend_fetch_static_prop_info(script, op_array, ssa, opline); + t1 = zend_fetch_prop_type(script, prop_info, &ce); + t2 = OP1_DATA_INFO(); } else { if (t1 & MAY_BE_REF) { tmp |= MAY_BE_REF; @@ -2524,10 +2649,13 @@ static int zend_update_type_info(const zend_op_array *op_array, UPDATE_SSA_TYPE(orig, ssa_ops[i].op1_def); COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); } + } else if (opline->extended_value == ZEND_ASSIGN_STATIC_PROP) { + /* Nothing to do */ } else { UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); } if (ssa_ops[i].result_def >= 0) { + ce = NULL; if (opline->extended_value == ZEND_ASSIGN_DIM) { if (opline->op2_type == IS_UNUSED) { /* When appending to an array and the LONG_MAX key is already used @@ -2549,10 +2677,25 @@ static int zend_update_type_info(const zend_op_array *op_array, * anything else results in a null return value. */ tmp |= MAY_BE_NULL; } + + /* The return value must also satisfy the property type */ + if (prop_info) { + tmp &= zend_fetch_prop_type(script, prop_info, NULL); + } + } else if (opline->extended_value == ZEND_ASSIGN_STATIC_PROP) { + /* The return value must also satisfy the property type */ + if (prop_info) { + tmp &= zend_fetch_prop_type(script, prop_info, NULL); + } } + tmp &= ~MAY_BE_REF; UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + if (ce) { + UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_ops[i].result_def); + } } break; + } case ZEND_PRE_INC: case ZEND_PRE_DEC: tmp = 0; @@ -2727,9 +2870,13 @@ static int zend_update_type_info(const zend_op_array *op_array, COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); } if (ssa_ops[i].result_def >= 0) { - // TODO: ??? - tmp = MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; + // TODO: If there is no __set we might do better + tmp = zend_fetch_prop_type(script, + zend_fetch_prop_info(op_array, ssa, opline, i), &ce); UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + if (ce) { + UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_ops[i].result_def); + } } if ((opline+1)->op1_type == IS_CV) { opline++; @@ -2827,6 +2974,42 @@ static int zend_update_type_info(const zend_op_array *op_array, UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); } break; + case ZEND_ASSIGN_OBJ_REF: + if (opline->op1_type == IS_CV) { + tmp = t1; + if (t1 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) { + tmp &= ~(MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE); + tmp |= MAY_BE_OBJECT | MAY_BE_RC1 | MAY_BE_RCN; + } + if (tmp & MAY_BE_OBJECT) { + tmp |= MAY_BE_RC1 | MAY_BE_RCN; + } + UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); + } + + t2 = OP1_DATA_INFO(); + if ((opline+1)->op1_type == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION)) { + tmp = (MAY_BE_REF | MAY_BE_RCN | MAY_BE_RC1 | t2) & ~MAY_BE_UNDEF; + } else { + tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_ERROR|MAY_BE_RC1|MAY_BE_RCN); + } + if (t2 & MAY_BE_UNDEF) { + tmp |= MAY_BE_NULL; + } + if (ssa_ops[i].result_def >= 0) { + UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + } + if ((opline+1)->op1_type == IS_CV) { + opline++; + i++; + tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN); + if (t2 & MAY_BE_UNDEF) { + tmp |= MAY_BE_NULL; + } + UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + } + break; case ZEND_BIND_GLOBAL: tmp = MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; @@ -3245,6 +3428,7 @@ static int zend_update_type_info(const zend_op_array *op_array, case ZEND_FETCH_OBJ_RW: case ZEND_FETCH_OBJ_FUNC_ARG: case ZEND_ASSIGN_OBJ: + case ZEND_ASSIGN_OBJ_REF: case ZEND_PRE_INC_OBJ: case ZEND_PRE_DEC_OBJ: case ZEND_POST_INC_OBJ: @@ -3342,14 +3526,31 @@ static int zend_update_type_info(const zend_op_array *op_array, COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); } if (ssa_ops[i].result_def >= 0) { - tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; - if (opline->result_type == IS_TMP_VAR) { - /* can't be REF because of ZVAL_COPY_DEREF() usage */ - tmp |= MAY_BE_RC1 | MAY_BE_RCN; - } else { - tmp |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ERROR; + tmp = zend_fetch_prop_type(script, + zend_fetch_prop_info(op_array, ssa, opline, i), &ce); + if (opline->result_type != IS_TMP_VAR) { + tmp |= MAY_BE_REF | MAY_BE_ERROR; } UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + if (ce) { + UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_ops[i].result_def); + } + } + break; + case ZEND_FETCH_STATIC_PROP_R: + case ZEND_FETCH_STATIC_PROP_IS: + case ZEND_FETCH_STATIC_PROP_RW: + case ZEND_FETCH_STATIC_PROP_W: + case ZEND_FETCH_STATIC_PROP_UNSET: + case ZEND_FETCH_STATIC_PROP_FUNC_ARG: + tmp = zend_fetch_prop_type(script, + zend_fetch_static_prop_info(script, op_array, ssa, opline), &ce); + if (opline->result_type != IS_TMP_VAR) { + tmp |= MAY_BE_REF | MAY_BE_ERROR; + } + UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + if (ce) { + UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_ops[i].result_def); } break; case ZEND_DO_FCALL: @@ -4182,7 +4383,7 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa return 1; } } - } else if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { + } else if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { if (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)) { switch (opline->opcode) { case ZEND_CASE: @@ -4206,9 +4407,9 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa return 1; } } - } + } - if (opline->op2_type == IS_CV) { + if (opline->op2_type == IS_CV) { if (t2 & MAY_BE_UNDEF) { switch (opline->opcode) { case ZEND_ASSIGN_REF: @@ -4228,7 +4429,7 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa return 1; } } - } + } switch (opline->opcode) { case ZEND_NOP: @@ -4390,6 +4591,9 @@ int zend_may_throw(const zend_op *opline, zend_op_array *op_array, zend_ssa *ssa return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)) || (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)); case ZEND_ASSIGN: + if (t1 & MAY_BE_REF) { + return 1; + } case ZEND_UNSET_VAR: return (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)); case ZEND_ASSIGN_DIM: diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index d13b8a000e..42cd5eef8f 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -256,6 +256,14 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array, zval *val) { switch (opline->opcode) { + case ZEND_OP_DATA: + switch ((opline-1)->opcode) { + case ZEND_ASSIGN_OBJ_REF: + case ZEND_ASSIGN_STATIC_PROP_REF: + return 0; + } + opline->op1.constant = zend_optimizer_add_literal(op_array, val); + break; case ZEND_FREE: case ZEND_CHECK_VAR: MAKE_NOP(opline); @@ -312,6 +320,23 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array, } zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val))); break; + case ZEND_ASSIGN_ADD: + case ZEND_ASSIGN_SUB: + case ZEND_ASSIGN_MUL: + case ZEND_ASSIGN_DIV: + case ZEND_ASSIGN_MOD: + case ZEND_ASSIGN_SL: + case ZEND_ASSIGN_SR: + case ZEND_ASSIGN_CONCAT: + case ZEND_ASSIGN_BW_OR: + case ZEND_ASSIGN_BW_AND: + case ZEND_ASSIGN_BW_XOR: + case ZEND_ASSIGN_POW: + if (opline->extended_value != ZEND_ASSIGN_STATIC_PROP) { + break; + } + case ZEND_ASSIGN_STATIC_PROP: + case ZEND_ASSIGN_STATIC_PROP_REF: case ZEND_FETCH_STATIC_PROP_R: case ZEND_FETCH_STATIC_PROP_W: case ZEND_FETCH_STATIC_PROP_RW: @@ -319,21 +344,17 @@ int zend_optimizer_update_op1_const(zend_op_array *op_array, case ZEND_FETCH_STATIC_PROP_UNSET: case ZEND_FETCH_STATIC_PROP_FUNC_ARG: case ZEND_UNSET_STATIC_PROP: - TO_STRING_NOWARN(val); - opline->op1.constant = zend_optimizer_add_literal(op_array, val); - if (opline->op2_type == IS_CONST && opline->extended_value + sizeof(void*) == op_array->cache_size) { - op_array->cache_size += sizeof(void *); - } else { - opline->extended_value = alloc_cache_slots(op_array, 2); - } - break; case ZEND_ISSET_ISEMPTY_STATIC_PROP: + case ZEND_PRE_INC_STATIC_PROP: + case ZEND_PRE_DEC_STATIC_PROP: + case ZEND_POST_INC_STATIC_PROP: + case ZEND_POST_DEC_STATIC_PROP: TO_STRING_NOWARN(val); opline->op1.constant = zend_optimizer_add_literal(op_array, val); - if (opline->op2_type == IS_CONST && (opline->extended_value & ~ZEND_ISEMPTY) + sizeof(void*) == op_array->cache_size) { + if (opline->op2_type == IS_CONST && (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) == op_array->cache_size) { op_array->cache_size += sizeof(void *); } else { - opline->extended_value = alloc_cache_slots(op_array, 2) | (opline->extended_value & ZEND_ISEMPTY); + opline->extended_value = alloc_cache_slots(op_array, 3) | (opline->extended_value & ZEND_FETCH_OBJ_FLAGS); } break; case ZEND_SEND_VAR: @@ -405,6 +426,8 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array, zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val))); opline->result.num = alloc_cache_slots(op_array, 1); break; + case ZEND_ASSIGN_STATIC_PROP: + case ZEND_ASSIGN_STATIC_PROP_REF: case ZEND_FETCH_STATIC_PROP_R: case ZEND_FETCH_STATIC_PROP_W: case ZEND_FETCH_STATIC_PROP_RW: @@ -412,21 +435,17 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array, case ZEND_FETCH_STATIC_PROP_UNSET: case ZEND_FETCH_STATIC_PROP_FUNC_ARG: case ZEND_UNSET_STATIC_PROP: + case ZEND_PRE_INC_STATIC_PROP: + case ZEND_PRE_DEC_STATIC_PROP: + case ZEND_POST_INC_STATIC_PROP: + case ZEND_POST_DEC_STATIC_PROP: +handle_static_prop: REQUIRES_STRING(val); drop_leading_backslash(val); opline->op2.constant = zend_optimizer_add_literal(op_array, val); zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val))); if (opline->op1_type != IS_CONST) { - opline->extended_value = alloc_cache_slots(op_array, 1); - } - break; - case ZEND_ISSET_ISEMPTY_STATIC_PROP: - REQUIRES_STRING(val); - drop_leading_backslash(val); - opline->op2.constant = zend_optimizer_add_literal(op_array, val); - zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val))); - if (opline->op1_type != IS_CONST) { - opline->extended_value = alloc_cache_slots(op_array, 1) | (opline->extended_value & ZEND_ISEMPTY); + opline->extended_value = alloc_cache_slots(op_array, 1) | (opline->extended_value & (ZEND_RETURNS_FUNCTION|ZEND_ISEMPTY|ZEND_FETCH_OBJ_FLAGS)); } break; case ZEND_INIT_FCALL: @@ -477,6 +496,7 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array, } break; case ZEND_ASSIGN_OBJ: + case ZEND_ASSIGN_OBJ_REF: case ZEND_FETCH_OBJ_R: case ZEND_FETCH_OBJ_W: case ZEND_FETCH_OBJ_RW: @@ -490,12 +510,12 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array, case ZEND_POST_DEC_OBJ: TO_STRING_NOWARN(val); opline->op2.constant = zend_optimizer_add_literal(op_array, val); - opline->extended_value = alloc_cache_slots(op_array, 2); + opline->extended_value = alloc_cache_slots(op_array, 3); break; case ZEND_ISSET_ISEMPTY_PROP_OBJ: TO_STRING_NOWARN(val); opline->op2.constant = zend_optimizer_add_literal(op_array, val); - opline->extended_value = alloc_cache_slots(op_array, 2) | (opline->extended_value & ZEND_ISEMPTY); + opline->extended_value = alloc_cache_slots(op_array, 3) | (opline->extended_value & ZEND_ISEMPTY); break; case ZEND_ASSIGN_ADD: case ZEND_ASSIGN_SUB: @@ -512,7 +532,9 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array, if (opline->extended_value == ZEND_ASSIGN_OBJ) { TO_STRING_NOWARN(val); opline->op2.constant = zend_optimizer_add_literal(op_array, val); - (opline+1)->extended_value = alloc_cache_slots(op_array, 2); + (opline+1)->extended_value = alloc_cache_slots(op_array, 3); + } else if (opline->extended_value == ZEND_ASSIGN_STATIC_PROP) { + goto handle_static_prop; } else if (opline->extended_value == ZEND_ASSIGN_DIM) { if (Z_TYPE_P(val) == IS_STRING) { zend_ulong index; diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index ea387bb95f..ad34e7f643 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -642,6 +642,22 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags, //NEW_SSA_VAR(next->op1.var) } break; + case ZEND_ASSIGN_OBJ_REF: + if (opline->op1_type == IS_CV) { + ssa_ops[k].op1_def = ssa_vars_count; + var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count; + ssa_vars_count++; + //NEW_SSA_VAR(opline->op1.var) + } + /* break missing intentionally */ + case ZEND_ASSIGN_STATIC_PROP_REF: + if (next->op1_type == IS_CV) { + ssa_ops[k + 1].op1_def = ssa_vars_count; + var[EX_VAR_TO_NUM(next->op1.var)] = ssa_vars_count; + ssa_vars_count++; + //NEW_SSA_VAR(next->op1.var) + } + break; case ZEND_PRE_INC_OBJ: case ZEND_PRE_DEC_OBJ: case ZEND_POST_INC_OBJ: diff --git a/ext/opcache/tests/opt/prop_types.phpt b/ext/opcache/tests/opt/prop_types.phpt new file mode 100644 index 0000000000..7962b1b893 --- /dev/null +++ b/ext/opcache/tests/opt/prop_types.phpt @@ -0,0 +1,115 @@ +--TEST-- +Property types in inference +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +opcache.opt_debug_level=0x200000 +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php + +class Test { + public bool $public; + protected int $protected; + private float $private; + + public function inTest() { + var_dump($this->public, $this->protected, $this->private); + } + + public function inTestWithTest2(Test2 $test2) { + var_dump($test2->public, $test2->protected, $test2->private); + } +} + +class Test2 extends Test { + private array $private; + + public function inTest2() { + var_dump($this->public, $this->protected, $this->private); + } +} + +function noScope(Test $test) { + var_dump($test->public, $test->protected, $test->private); +} + +?> +--EXPECTF-- +$_main: ; (lines=1, args=0, vars=0, tmps=0, ssa_vars=0, no_loops) + ; (before dfa pass) + ; %s + ; return [long] RANGE[1..1] +BB0: start exit lines=[0-0] + ; level=0 + RETURN int(1) + +noScope: ; (lines=10, args=1, vars=1, tmps=1, ssa_vars=5, no_loops) + ; (before dfa pass) + ; %s + ; return [null] RANGE[0..0] + ; #0.CV0($test) NOVAL [undef] +BB0: start exit lines=[0-9] + ; level=0 + #1.CV0($test) [object (instanceof Test)] = RECV 1 + INIT_FCALL 3 128 string("var_dump") + #2.T1 [bool] = FETCH_OBJ_R #1.CV0($test) [object (instanceof Test)] string("public") + SEND_VAL #2.T1 [bool] 1 + #3.T1 [any] = FETCH_OBJ_R #1.CV0($test) [object (instanceof Test)] string("protected") + SEND_VAL #3.T1 [any] 2 + #4.T1 [any] = FETCH_OBJ_R #1.CV0($test) [object (instanceof Test)] string("private") + SEND_VAL #4.T1 [any] 3 + DO_ICALL + RETURN null + +Test::inTest: ; (lines=9, args=0, vars=0, tmps=1, ssa_vars=3, no_loops) + ; (before dfa pass) + ; %s + ; return [null] RANGE[0..0] +BB0: start exit lines=[0-8] + ; level=0 + INIT_FCALL 3 128 string("var_dump") + #0.T0 [bool] = FETCH_OBJ_R THIS string("public") + SEND_VAL #0.T0 [bool] 1 + #1.T0 [long] = FETCH_OBJ_R THIS string("protected") + SEND_VAL #1.T0 [long] 2 + #2.T0 [double] = FETCH_OBJ_R THIS string("private") + SEND_VAL #2.T0 [double] 3 + DO_ICALL + RETURN null + +Test::inTestWithTest2: ; (lines=10, args=1, vars=1, tmps=1, ssa_vars=5, no_loops) + ; (before dfa pass) + ; %s + ; return [null] RANGE[0..0] + ; #0.CV0($test2) NOVAL [undef] +BB0: start exit lines=[0-9] + ; level=0 + #1.CV0($test2) [object (instanceof Test2)] = RECV 1 + INIT_FCALL 3 128 string("var_dump") + #2.T1 [bool] = FETCH_OBJ_R #1.CV0($test2) [object (instanceof Test2)] string("public") + SEND_VAL #2.T1 [bool] 1 + #3.T1 [long] = FETCH_OBJ_R #1.CV0($test2) [object (instanceof Test2)] string("protected") + SEND_VAL #3.T1 [long] 2 + #4.T1 [double] = FETCH_OBJ_R #1.CV0($test2) [object (instanceof Test2)] string("private") + SEND_VAL #4.T1 [double] 3 + DO_ICALL + RETURN null + +Test2::inTest2: ; (lines=9, args=0, vars=0, tmps=1, ssa_vars=3, no_loops) + ; (before dfa pass) + ; %s + ; return [null] RANGE[0..0] +BB0: start exit lines=[0-8] + ; level=0 + INIT_FCALL 3 128 string("var_dump") + #0.T0 [bool] = FETCH_OBJ_R THIS string("public") + SEND_VAL #0.T0 [bool] 1 + #1.T0 [long] = FETCH_OBJ_R THIS string("protected") + SEND_VAL #1.T0 [long] 2 + #2.T0 [array of [any, ref]] = FETCH_OBJ_R THIS string("private") + SEND_VAL #2.T0 [array of [any, ref]] 3 + DO_ICALL + RETURN null diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index d22cc7ffd7..7b04d0d2df 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -232,6 +232,14 @@ static void zend_hash_clone_prop_info(HashTable *ht) if (IN_ARENA(prop_info->ce)) { prop_info->ce = ARENA_REALLOC(prop_info->ce); } + + if (ZEND_TYPE_IS_CE(prop_info->type)) { + zend_class_entry *ce = ZEND_TYPE_CE(prop_info->type); + if (IN_ARENA(ce)) { + ce = ARENA_REALLOC(ce); + prop_info->type = ZEND_TYPE_ENCODE_CE(ce, ZEND_TYPE_ALLOW_NULL(prop_info->type)); + } + } } } } @@ -304,6 +312,16 @@ static void zend_class_copy_ctor(zend_class_entry **pce) /* constants table */ zend_hash_clone_constants(&ce->constants_table); + if (ce->properties_info_table) { + int i; + ce->properties_info_table = ARENA_REALLOC(ce->properties_info_table); + for (i = 0; i < ce->default_properties_count; i++) { + if (IN_ARENA(ce->properties_info_table[i])) { + ce->properties_info_table[i] = ARENA_REALLOC(ce->properties_info_table[i]); + } + } + } + if (ce->num_interfaces) { zend_class_name *interface_names; diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 86cb8a2e25..92a77ab792 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -577,6 +577,17 @@ static void zend_file_cache_serialize_prop_info(zval *zv, SERIALIZE_STR(prop->doc_comment); } } + if (prop->type) { + if (ZEND_TYPE_IS_NAME(prop->type)) { + zend_string *name = ZEND_TYPE_NAME(prop->type); + SERIALIZE_STR(name); + prop->type = ZEND_TYPE_ENCODE_CLASS(name, ZEND_TYPE_ALLOW_NULL(prop->type)); + } else if (ZEND_TYPE_IS_CE(prop->type)) { + zend_class_entry *ce = ZEND_TYPE_CE(prop->type); + SERIALIZE_PTR(ce); + prop->type = ZEND_TYPE_ENCODE_CE(ce, ZEND_TYPE_ALLOW_NULL(prop->type)); + } + } } } @@ -660,6 +671,19 @@ static void zend_file_cache_serialize_class(zval *zv, SERIALIZE_STR(ce->info.user.doc_comment); zend_file_cache_serialize_hash(&ce->properties_info, script, info, buf, zend_file_cache_serialize_prop_info); + if (ce->properties_info_table) { + uint32_t i; + zend_property_info **table; + + SERIALIZE_PTR(ce->properties_info_table); + table = ce->properties_info_table; + UNSERIALIZE_PTR(table); + + for (i = 0; i < ce->default_properties_count; i++) { + SERIALIZE_PTR(table[i]); + } + } + if (ce->num_interfaces) { uint32_t i; zend_class_name *interface_names; @@ -1246,6 +1270,17 @@ static void zend_file_cache_unserialize_prop_info(zval *zv, UNSERIALIZE_STR(prop->doc_comment); } } + if (prop->type) { + if (ZEND_TYPE_IS_NAME(prop->type)) { + zend_string *name = ZEND_TYPE_NAME(prop->type); + UNSERIALIZE_STR(name); + prop->type = ZEND_TYPE_ENCODE_CLASS(name, ZEND_TYPE_ALLOW_NULL(prop->type)); + } else if (ZEND_TYPE_IS_CE(prop->type)) { + zend_class_entry *ce = ZEND_TYPE_CE(prop->type); + UNSERIALIZE_PTR(ce); + prop->type = ZEND_TYPE_ENCODE_CE(ce, ZEND_TYPE_ALLOW_NULL(prop->type)); + } + } } } @@ -1325,6 +1360,15 @@ static void zend_file_cache_unserialize_class(zval *zv, zend_file_cache_unserialize_hash(&ce->properties_info, script, buf, zend_file_cache_unserialize_prop_info, NULL); + if (ce->properties_info_table) { + uint32_t i; + UNSERIALIZE_PTR(ce->properties_info_table); + + for (i = 0; i < ce->default_properties_count; i++) { + UNSERIALIZE_PTR(ce->properties_info_table[i]); + } + } + if (ce->num_interfaces) { uint32_t i; diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index eba9dd23e4..af9244bbf5 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -746,6 +746,16 @@ static void zend_persist_property_info(zval *zv) prop->doc_comment = NULL; } } + + if (ZEND_TYPE_IS_NAME(prop->type)) { + zend_string *class_name = ZEND_TYPE_NAME(prop->type); + zend_accel_store_interned_string(class_name); + prop->type = ZEND_TYPE_ENCODE_CLASS(class_name, ZEND_TYPE_ALLOW_NULL(prop->type)); + } else if (ZEND_TYPE_IS_CE(prop->type)) { + zend_class_entry *ce = ZEND_TYPE_CE(prop->type); + ce = zend_shared_alloc_get_xlat_entry(ce); + prop->type = ZEND_TYPE_ENCODE_CE(ce, ZEND_TYPE_ALLOW_NULL(prop->type)); + } } static void zend_persist_class_constant(zval *zv) @@ -786,6 +796,16 @@ static void zend_persist_class_constant(zval *zv) } } +static zend_bool has_unresolved_property_types(zend_class_entry *ce) { + zend_property_info *prop; + ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) { + if (ZEND_TYPE_IS_NAME(prop->type)) { + return 1; + } + } ZEND_HASH_FOREACH_END(); + return 0; +} + static void zend_persist_class_entry(zval *zv) { zend_class_entry *ce = Z_PTR_P(zv); @@ -793,6 +813,7 @@ static void zend_persist_class_entry(zval *zv) if (ce->type == ZEND_USER_CLASS) { if ((ce->ce_flags & ZEND_ACC_LINKED) && (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) + && !has_unresolved_property_types(ce) && !ZCG(current_persistent_script)->corrupted) { ZCG(is_immutable_class) = 1; ce = Z_PTR_P(zv) = zend_shared_memdup_put(ce, sizeof(zend_class_entry)); @@ -855,6 +876,19 @@ static void zend_persist_class_entry(zval *zv) zend_hash_persist(&ce->properties_info, zend_persist_property_info); HT_FLAGS(&ce->properties_info) &= (HASH_FLAG_UNINITIALIZED | HASH_FLAG_STATIC_KEYS); + if (ce->properties_info_table) { + int i; + + size_t size = sizeof(zend_property_info *) * ce->default_properties_count; + memcpy(ZCG(arena_mem), ce->properties_info_table, size); + ce->properties_info_table = ZCG(arena_mem); + ZCG(arena_mem) = (void*)((char*)ZCG(arena_mem) + ZEND_ALIGNED_SIZE(size)); + + for (i = 0; i < ce->default_properties_count; i++) { + ce->properties_info_table[i] = zend_shared_alloc_get_xlat_entry(ce->properties_info_table[i]); + } + } + if (ce->num_interfaces && !(ce->ce_flags & ZEND_ACC_LINKED)) { uint32_t i = 0; diff --git a/ext/opcache/zend_persist_calc.c b/ext/opcache/zend_persist_calc.c index 5fd48a224e..a17d7c4627 100644 --- a/ext/opcache/zend_persist_calc.c +++ b/ext/opcache/zend_persist_calc.c @@ -306,6 +306,11 @@ static void zend_persist_property_info_calc(zval *zv) zend_shared_alloc_register_xlat_entry(prop, prop); ADD_SIZE_EX(sizeof(zend_property_info)); ADD_INTERNED_STRING(prop->name); + if (ZEND_TYPE_IS_NAME(prop->type)) { + zend_string *class_name = ZEND_TYPE_NAME(prop->type); + ADD_INTERNED_STRING(class_name); + prop->type = ZEND_TYPE_ENCODE_CLASS(class_name, ZEND_TYPE_ALLOW_NULL(prop->type)); + } if (ZCG(accel_directives).save_comments && prop->doc_comment) { ADD_STRING(prop->doc_comment); } @@ -326,6 +331,16 @@ static void zend_persist_class_constant_calc(zval *zv) } } +static zend_bool has_unresolved_property_types(zend_class_entry *ce) { + zend_property_info *prop; + ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) { + if (ZEND_TYPE_IS_NAME(prop->type)) { + return 1; + } + } ZEND_HASH_FOREACH_END(); + return 0; +} + static void zend_persist_class_entry_calc(zval *zv) { zend_class_entry *ce = Z_PTR_P(zv); @@ -334,6 +349,7 @@ static void zend_persist_class_entry_calc(zval *zv) ZCG(is_immutable_class) = (ce->ce_flags & ZEND_ACC_LINKED) && (ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED) && + !has_unresolved_property_types(ce) && !ZCG(current_persistent_script)->corrupted; ADD_SIZE_EX(sizeof(zend_class_entry)); @@ -371,6 +387,10 @@ static void zend_persist_class_entry_calc(zval *zv) zend_hash_persist_calc(&ce->properties_info, zend_persist_property_info_calc); + if (ce->properties_info_table) { + ADD_ARENA_SIZE(sizeof(zend_property_info *) * ce->default_properties_count); + } + if (ce->num_interfaces) { uint32_t i; diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index e97cd8fda6..115801a380 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -2101,7 +2101,7 @@ PHP_FUNCTION(openssl_x509_export) zend_bool notext = 1; BIO * bio_out; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/|b", &zcert, &zout, ¬ext) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|b", &zcert, &zout, ¬ext) == FAILURE) { return; } RETVAL_FALSE; @@ -2123,9 +2123,8 @@ PHP_FUNCTION(openssl_x509_export) if (PEM_write_bio_X509(bio_out, cert)) { BUF_MEM *bio_buf; - zval_ptr_dtor(zout); BIO_get_mem_ptr(bio_out, &bio_buf); - ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length); + ZEND_TRY_ASSIGN_STRINGL(zout, bio_buf->data, bio_buf->length); RETVAL_TRUE; } else { @@ -2925,7 +2924,7 @@ PHP_FUNCTION(openssl_pkcs12_export) zval * item; STACK_OF(X509) *ca = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/zs|a", &zcert, &zout, &zpkey, &pass, &pass_len, &args) == FAILURE) + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzzs|a", &zcert, &zout, &zpkey, &pass, &pass_len, &args) == FAILURE) return; RETVAL_FALSE; @@ -2965,9 +2964,8 @@ PHP_FUNCTION(openssl_pkcs12_export) if (i2d_PKCS12_bio(bio_out, p12)) { BUF_MEM *bio_buf; - zval_ptr_dtor(zout); BIO_get_mem_ptr(bio_out, &bio_buf); - ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length); + ZEND_TRY_ASSIGN_STRINGL(zout, bio_buf->data, bio_buf->length); RETVAL_TRUE; } else { @@ -3006,7 +3004,7 @@ PHP_FUNCTION(openssl_pkcs12_read) BIO * bio_in = NULL; int i; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/s", &zp12, &zp12_len, &zout, &pass, &pass_len) == FAILURE) + if (zend_parse_parameters(ZEND_NUM_ARGS(), "szs", &zp12, &zp12_len, &zout, &pass, &pass_len) == FAILURE) return; RETVAL_FALSE; @@ -3024,8 +3022,10 @@ PHP_FUNCTION(openssl_pkcs12_read) BIO * bio_out; int cert_num; - zval_ptr_dtor(zout); - array_init(zout); + zout = zend_try_array_init(zout); + if (!zout) { + goto cleanup; + } if (cert) { bio_out = BIO_new(BIO_s_mem()); @@ -3380,7 +3380,7 @@ PHP_FUNCTION(openssl_csr_export) BIO * bio_out; zend_resource *csr_resource; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|b", &zcsr, &zout, ¬ext) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz|b", &zcsr, &zout, ¬ext) == FAILURE) { return; } @@ -3403,8 +3403,7 @@ PHP_FUNCTION(openssl_csr_export) BUF_MEM *bio_buf; BIO_get_mem_ptr(bio_out, &bio_buf); - zval_ptr_dtor(zout); - ZVAL_STRINGL(zout, bio_buf->data, bio_buf->length); + ZEND_TRY_ASSIGN_STRINGL(zout, bio_buf->data, bio_buf->length); RETVAL_TRUE; } else { @@ -3573,7 +3572,7 @@ PHP_FUNCTION(openssl_csr_new) int we_made_the_key = 1; zend_resource *key_resource; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "az/|a!a!", &dn, &out_pkey, &args, &attribs) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "az|a!a!", &dn, &out_pkey, &args, &attribs) == FAILURE) { return; } RETVAL_FALSE; @@ -3581,9 +3580,12 @@ PHP_FUNCTION(openssl_csr_new) PHP_SSL_REQ_INIT(&req); if (PHP_SSL_REQ_PARSE(&req, args) == SUCCESS) { + zval *out_pkey_val = out_pkey; + ZVAL_DEREF(out_pkey_val); + /* Generate or use a private key */ - if (Z_TYPE_P(out_pkey) != IS_NULL) { - req.priv_key = php_openssl_evp_from_zval(out_pkey, 0, NULL, 0, 0, &key_resource); + if (Z_TYPE_P(out_pkey_val) != IS_NULL) { + req.priv_key = php_openssl_evp_from_zval(out_pkey_val, 0, NULL, 0, 0, &key_resource); if (req.priv_key != NULL) { we_made_the_key = 0; } @@ -3621,8 +3623,7 @@ PHP_FUNCTION(openssl_csr_new) if (we_made_the_key) { /* and a resource for the private key */ - zval_ptr_dtor(out_pkey); - ZVAL_RES(out_pkey, zend_register_resource(req.priv_key, le_key)); + ZEND_TRY_ASSIGN_RES(out_pkey, zend_register_resource(req.priv_key, le_key)); req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */ } else if (key_resource != NULL) { req.priv_key = NULL; /* make sure the cleanup code doesn't zap it! */ @@ -4633,7 +4634,7 @@ PHP_FUNCTION(openssl_pkey_export) BIO * bio_out = NULL; const EVP_CIPHER * cipher; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz/|s!a!", &zpkey, &out, &passphrase, &passphrase_len, &args) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|s!a!", &zpkey, &out, &passphrase, &passphrase_len, &args) == FAILURE) { return; } RETVAL_FALSE; @@ -4685,8 +4686,7 @@ PHP_FUNCTION(openssl_pkey_export) RETVAL_TRUE; bio_mem_len = BIO_get_mem_data(bio_out, &bio_mem_ptr); - zval_ptr_dtor(out); - ZVAL_STRINGL(out, bio_mem_ptr, bio_mem_len); + ZEND_TRY_ASSIGN_STRINGL(out, bio_mem_ptr, bio_mem_len); } else { php_openssl_store_errors(); } @@ -5389,7 +5389,7 @@ PHP_FUNCTION(openssl_pkcs7_read) PKCS7 * p7 = NULL; int i; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/", &p7b, &p7b_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &p7b, &p7b_len, &zout) == FAILURE) { return; } @@ -5431,8 +5431,10 @@ PHP_FUNCTION(openssl_pkcs7_read) break; } - zval_ptr_dtor(zout); - array_init(zout); + zout = zend_try_array_init(zout); + if (!zout) { + goto clean_exit; + } if (certs != NULL) { for (i = 0; i < sk_X509_num(certs); i++) { @@ -5686,7 +5688,7 @@ PHP_FUNCTION(openssl_private_encrypt) size_t data_len; zend_long padding = RSA_PKCS1_PADDING; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { return; } RETVAL_FALSE; @@ -5717,9 +5719,8 @@ PHP_FUNCTION(openssl_private_encrypt) } if (successful) { - zval_ptr_dtor(crypted); ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0'; - ZVAL_NEW_STR(crypted, cryptedbuf); + ZEND_TRY_ASSIGN_NEW_STR(crypted, cryptedbuf); cryptedbuf = NULL; RETVAL_TRUE; } else { @@ -5749,7 +5750,7 @@ PHP_FUNCTION(openssl_private_decrypt) char * data; size_t data_len; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { return; } RETVAL_FALSE; @@ -5786,9 +5787,8 @@ PHP_FUNCTION(openssl_private_decrypt) efree(crypttemp); if (successful) { - zval_ptr_dtor(crypted); ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0'; - ZVAL_NEW_STR(crypted, cryptedbuf); + ZEND_TRY_ASSIGN_NEW_STR(crypted, cryptedbuf); cryptedbuf = NULL; RETVAL_TRUE; } else { @@ -5818,7 +5818,7 @@ PHP_FUNCTION(openssl_public_encrypt) char * data; size_t data_len; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) + if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) return; RETVAL_FALSE; @@ -5848,9 +5848,8 @@ PHP_FUNCTION(openssl_public_encrypt) } if (successful) { - zval_ptr_dtor(crypted); ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0'; - ZVAL_NEW_STR(crypted, cryptedbuf); + ZEND_TRY_ASSIGN_NEW_STR(crypted, cryptedbuf); cryptedbuf = NULL; RETVAL_TRUE; } else { @@ -5880,7 +5879,7 @@ PHP_FUNCTION(openssl_public_decrypt) char * data; size_t data_len; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|l", &data, &data_len, &crypted, &key, &padding) == FAILURE) { return; } RETVAL_FALSE; @@ -5919,9 +5918,8 @@ PHP_FUNCTION(openssl_public_decrypt) efree(crypttemp); if (successful) { - zval_ptr_dtor(crypted); ZSTR_VAL(cryptedbuf)[cryptedlen] = '\0'; - ZVAL_NEW_STR(crypted, cryptedbuf); + ZEND_TRY_ASSIGN_NEW_STR(crypted, cryptedbuf); cryptedbuf = NULL; RETVAL_TRUE; } else { @@ -5982,7 +5980,7 @@ PHP_FUNCTION(openssl_sign) zend_long signature_algo = OPENSSL_ALGO_SHA1; const EVP_MD *mdtype; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z|z", &data, &data_len, &signature, &key, &method) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|z", &data, &data_len, &signature, &key, &method) == FAILURE) { return; } pkey = php_openssl_evp_from_zval(key, 0, "", 0, 0, &keyresource); @@ -6015,10 +6013,9 @@ PHP_FUNCTION(openssl_sign) EVP_SignInit(md_ctx, mdtype) && EVP_SignUpdate(md_ctx, data, data_len) && EVP_SignFinal(md_ctx, (unsigned char*)ZSTR_VAL(sigbuf), &siglen, pkey)) { - zval_ptr_dtor(signature); ZSTR_VAL(sigbuf)[siglen] = '\0'; ZSTR_LEN(sigbuf) = siglen; - ZVAL_NEW_STR(signature, sigbuf); + ZEND_TRY_ASSIGN_NEW_STR(signature, sigbuf); RETVAL_TRUE; } else { php_openssl_store_errors(); @@ -6110,7 +6107,7 @@ PHP_FUNCTION(openssl_seal) const EVP_CIPHER *cipher; EVP_CIPHER_CTX *ctx; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z/a|sz/", &data, &data_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "szza|sz", &data, &data_len, &sealdata, &ekeys, &pubkeys, &method, &method_len, &iv) == FAILURE) { return; } @@ -6184,12 +6181,15 @@ PHP_FUNCTION(openssl_seal) } if (len1 + len2 > 0) { - zval_ptr_dtor(sealdata); - ZVAL_NEW_STR(sealdata, zend_string_init((char*)buf, len1 + len2, 0)); + ZEND_TRY_ASSIGN_NEW_STR(sealdata, zend_string_init((char*)buf, len1 + len2, 0)); efree(buf); - zval_ptr_dtor(ekeys); - array_init(ekeys); + ekeys = zend_try_array_init(ekeys); + if (!ekeys) { + EVP_CIPHER_CTX_free(ctx); + goto clean_exit; + } + for (i=0; i<nkeys; i++) { eks[i][eksl[i]] = '\0'; add_next_index_stringl(ekeys, (const char*)eks[i], eksl[i]); @@ -6198,9 +6198,8 @@ PHP_FUNCTION(openssl_seal) } if (iv) { - zval_ptr_dtor(iv); iv_buf[iv_len] = '\0'; - ZVAL_NEW_STR(iv, zend_string_init((char*)iv_buf, iv_len, 0)); + ZEND_TRY_ASSIGN_NEW_STR(iv, zend_string_init((char*)iv_buf, iv_len, 0)); } } else { efree(buf); @@ -6242,7 +6241,7 @@ PHP_FUNCTION(openssl_open) size_t method_len = 0, iv_len = 0; const EVP_CIPHER *cipher; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/sz|ss", &data, &data_len, &opendata, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "szsz|ss", &data, &data_len, &opendata, &ekey, &ekey_len, &privkey, &method, &method_len, &iv, &iv_len) == FAILURE) { return; } @@ -6288,9 +6287,8 @@ PHP_FUNCTION(openssl_open) if (ctx != NULL && EVP_OpenInit(ctx, cipher, (unsigned char *)ekey, (int)ekey_len, iv_buf, pkey) && EVP_OpenUpdate(ctx, buf, &len1, (unsigned char *)data, (int)data_len) && EVP_OpenFinal(ctx, buf + len1, &len2) && (len1 + len2 > 0)) { - zval_ptr_dtor(opendata); buf[len1 + len2] = '\0'; - ZVAL_NEW_STR(opendata, zend_string_init((char*)buf, len1 + len2, 0)); + ZEND_TRY_ASSIGN_NEW_STR(opendata, zend_string_init((char*)buf, len1 + len2, 0)); RETVAL_TRUE; } else { php_openssl_store_errors(); @@ -6642,7 +6640,7 @@ PHP_FUNCTION(openssl_encrypt) zend_string *outbuf; zend_bool free_iv = 0, free_password = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|lsz/sl", &data, &data_len, &method, &method_len, + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|lszsl", &data, &data_len, &method, &method_len, &password, &password_len, &options, &iv, &iv_len, &tag, &aad, &aad_len, &tag_len) == FAILURE) { return; } @@ -6689,10 +6687,9 @@ PHP_FUNCTION(openssl_encrypt) zend_string *tag_str = zend_string_alloc(tag_len, 0); if (EVP_CIPHER_CTX_ctrl(cipher_ctx, mode.aead_get_tag_flag, tag_len, ZSTR_VAL(tag_str)) == 1) { - zval_ptr_dtor(tag); ZSTR_VAL(tag_str)[tag_len] = '\0'; ZSTR_LEN(tag_str) = tag_len; - ZVAL_NEW_STR(tag, tag_str); + ZEND_TRY_ASSIGN_NEW_STR(tag, tag_str); } else { php_error_docref(NULL, E_WARNING, "Retrieving verification tag failed"); zend_string_release_ex(tag_str, 0); @@ -6700,8 +6697,7 @@ PHP_FUNCTION(openssl_encrypt) RETVAL_FALSE; } } else if (tag) { - zval_ptr_dtor(tag); - ZVAL_NULL(tag); + ZEND_TRY_ASSIGN_NULL(tag); php_error_docref(NULL, E_WARNING, "The authenticated tag cannot be provided for cipher that doesn not support AEAD"); } else if (mode.is_aead) { @@ -6848,13 +6844,12 @@ PHP_FUNCTION(openssl_random_pseudo_bytes) zend_string *buffer = NULL; zval *zstrong_result_returned = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|z/", &buffer_length, &zstrong_result_returned) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|z", &buffer_length, &zstrong_result_returned) == FAILURE) { return; } if (zstrong_result_returned) { - zval_ptr_dtor(zstrong_result_returned); - ZVAL_FALSE(zstrong_result_returned); + ZEND_TRY_ASSIGN_FALSE(zstrong_result_returned); } if (buffer_length <= 0 @@ -6872,7 +6867,7 @@ PHP_FUNCTION(openssl_random_pseudo_bytes) if (php_win32_get_random_bytes((unsigned char*)buffer->val, (size_t) buffer_length) == FAILURE){ zend_string_release_ex(buffer, 0); if (zstrong_result_returned) { - ZVAL_FALSE(zstrong_result_returned); + ZEND_TRY_ASSIGN_FALSE(zstrong_result_returned); } zend_throw_exception(zend_ce_exception, "Error reading from source device", 0); return; @@ -6885,7 +6880,7 @@ PHP_FUNCTION(openssl_random_pseudo_bytes) if (RAND_bytes((unsigned char*)ZSTR_VAL(buffer), (int)buffer_length) <= 0) { zend_string_release_ex(buffer, 0); if (zstrong_result_returned) { - ZVAL_FALSE(zstrong_result_returned); + ZEND_TRY_ASSIGN_FALSE(zstrong_result_returned); } zend_throw_exception(zend_ce_exception, "Error reading from source device", 0); return; @@ -6898,7 +6893,7 @@ PHP_FUNCTION(openssl_random_pseudo_bytes) RETVAL_NEW_STR(buffer); if (zstrong_result_returned) { - ZVAL_BOOL(zstrong_result_returned, 1); + ZEND_TRY_ASSIGN_TRUE(zstrong_result_returned); } } /* }}} */ diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index b243b22027..cf53edc7f6 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -663,7 +663,7 @@ PHP_FUNCTION(pcntl_waitpid) struct rusage rusage; #endif - if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz/|lz/", &pid, &z_status, &options, &z_rusage) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz|lz", &pid, &z_status, &options, &z_rusage) == FAILURE) { return; } @@ -671,11 +671,9 @@ PHP_FUNCTION(pcntl_waitpid) #ifdef HAVE_WAIT4 if (z_rusage) { - if (Z_TYPE_P(z_rusage) != IS_ARRAY) { - zval_ptr_dtor(z_rusage); - array_init(z_rusage); - } else { - zend_hash_clean(Z_ARRVAL_P(z_rusage)); + z_rusage = zend_try_array_init(z_rusage); + if (!z_rusage) { + return; } memset(&rusage, 0, sizeof(struct rusage)); @@ -697,8 +695,7 @@ PHP_FUNCTION(pcntl_waitpid) } #endif - zval_ptr_dtor(z_status); - ZVAL_LONG(z_status, status); + ZEND_TRY_ASSIGN_LONG(z_status, status); RETURN_LONG((zend_long) child_id); } @@ -716,18 +713,16 @@ PHP_FUNCTION(pcntl_wait) struct rusage rusage; #endif - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z/|lz/", &z_status, &options, &z_rusage) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|lz", &z_status, &options, &z_rusage) == FAILURE) { return; } status = zval_get_long(z_status); #ifdef HAVE_WAIT3 if (z_rusage) { - if (Z_TYPE_P(z_rusage) != IS_ARRAY) { - zval_ptr_dtor(z_rusage); - array_init(z_rusage); - } else { - zend_hash_clean(Z_ARRVAL_P(z_rusage)); + z_rusage = zend_try_array_init(z_rusage); + if (!z_rusage) { + return; } memset(&rusage, 0, sizeof(struct rusage)); @@ -750,8 +745,7 @@ PHP_FUNCTION(pcntl_wait) } #endif - zval_ptr_dtor(z_status); - ZVAL_LONG(z_status, status); + ZEND_TRY_ASSIGN_LONG(z_status, status); RETURN_LONG((zend_long) child_id); } @@ -1105,7 +1099,7 @@ PHP_FUNCTION(pcntl_sigprocmask) zval *user_set, *user_oldset = NULL, *user_signo; sigset_t set, oldset; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "la|z/", &how, &user_set, &user_oldset) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "la|z", &how, &user_set, &user_oldset) == FAILURE) { return; } @@ -1131,12 +1125,11 @@ PHP_FUNCTION(pcntl_sigprocmask) } if (user_oldset != NULL) { - if (Z_TYPE_P(user_oldset) != IS_ARRAY) { - zval_ptr_dtor(user_oldset); - array_init(user_oldset); - } else { - zend_hash_clean(Z_ARRVAL_P(user_oldset)); + user_oldset = zend_try_array_init(user_oldset); + if (!user_oldset) { + return; } + for (signo = 1; signo < NSIG; ++signo) { if (sigismember(&oldset, signo) != 1) { continue; @@ -1162,11 +1155,11 @@ static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{ struct timespec timeout; if (timedwait) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|z/ll", &user_set, &user_siginfo, &tv_sec, &tv_nsec) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|zll", &user_set, &user_siginfo, &tv_sec, &tv_nsec) == FAILURE) { return; } } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|z/", &user_set, &user_siginfo) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|z", &user_set, &user_siginfo) == FAILURE) { return; } } @@ -1230,12 +1223,11 @@ PHP_FUNCTION(pcntl_sigtimedwait) static void pcntl_siginfo_to_zval(int signo, siginfo_t *siginfo, zval *user_siginfo) /* {{{ */ { if (signo > 0 && user_siginfo) { - if (Z_TYPE_P(user_siginfo) != IS_ARRAY) { - zval_ptr_dtor(user_siginfo); - array_init(user_siginfo); - } else { - zend_hash_clean(Z_ARRVAL_P(user_siginfo)); + user_siginfo = zend_try_array_init(user_siginfo); + if (!user_siginfo) { + return; } + add_assoc_long_ex(user_siginfo, "signo", sizeof("signo")-1, siginfo->si_signo); add_assoc_long_ex(user_siginfo, "errno", sizeof("errno")-1, siginfo->si_errno); add_assoc_long_ex(user_siginfo, "code", sizeof("code")-1, siginfo->si_code); diff --git a/ext/pcre/php_pcre.c b/ext/pcre/php_pcre.c index 16ebedd7ac..8622ea8c65 100644 --- a/ext/pcre/php_pcre.c +++ b/ext/pcre/php_pcre.c @@ -970,7 +970,7 @@ static void php_do_pcre_match(INTERNAL_FUNCTION_PARAMETERS, int global) /* {{{ * Z_PARAM_STR(regex) Z_PARAM_STR(subject) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_DEREF(subpats) + Z_PARAM_ZVAL(subpats) Z_PARAM_LONG(flags) Z_PARAM_LONG(start_offset) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); @@ -1014,8 +1014,10 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, char *subject, size_t sub /* Overwrite the passed-in value for subpatterns with an empty array. */ if (subpats != NULL) { - zval_ptr_dtor(subpats); - array_init(subpats); + subpats = zend_try_array_init(subpats); + if (!subpats) { + return; + } } subpats_order = global ? PREG_PATTERN_ORDER : 0; @@ -2239,7 +2241,7 @@ static void preg_replace_common(INTERNAL_FUNCTION_PARAMETERS, int is_filter) Z_PARAM_ZVAL(subject) Z_PARAM_OPTIONAL Z_PARAM_LONG(limit) - Z_PARAM_ZVAL_DEREF(zcount) + Z_PARAM_ZVAL(zcount) ZEND_PARSE_PARAMETERS_END(); if (Z_TYPE_P(replace) != IS_ARRAY) { @@ -2305,8 +2307,7 @@ static void preg_replace_common(INTERNAL_FUNCTION_PARAMETERS, int is_filter) } if (zcount) { - zval_ptr_dtor(zcount); - ZVAL_LONG(zcount, replace_count); + ZEND_TRY_ASSIGN_LONG(zcount, replace_count); } } /* }}} */ @@ -2336,7 +2337,7 @@ static PHP_FUNCTION(preg_replace_callback) Z_PARAM_ZVAL(subject) Z_PARAM_OPTIONAL Z_PARAM_LONG(limit) - Z_PARAM_ZVAL_DEREF(zcount) + Z_PARAM_ZVAL(zcount) ZEND_PARSE_PARAMETERS_END(); if (!zend_is_callable_ex(replace, NULL, 0, NULL, &fcc, NULL)) { @@ -2353,8 +2354,7 @@ static PHP_FUNCTION(preg_replace_callback) replace_count = preg_replace_func_impl(return_value, regex, &fci, &fcc, subject, limit); if (zcount) { - zval_ptr_dtor(zcount); - ZVAL_LONG(zcount, replace_count); + ZEND_TRY_ASSIGN_LONG(zcount, replace_count); } } /* }}} */ @@ -2376,7 +2376,7 @@ static PHP_FUNCTION(preg_replace_callback_array) Z_PARAM_ZVAL(subject) Z_PARAM_OPTIONAL Z_PARAM_LONG(limit) - Z_PARAM_ZVAL_DEREF(zcount) + Z_PARAM_ZVAL(zcount) ZEND_PARSE_PARAMETERS_END(); fci.size = sizeof(fci); @@ -2421,8 +2421,7 @@ static PHP_FUNCTION(preg_replace_callback_array) } ZEND_HASH_FOREACH_END(); if (zcount) { - zval_ptr_dtor(zcount); - ZVAL_LONG(zcount, replace_count); + ZEND_TRY_ASSIGN_LONG(zcount, replace_count); } } /* }}} */ diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 0b6fc90253..9355d3d3df 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -2176,7 +2176,7 @@ const zend_function_entry pdo_dbstmt_functions[] = { }; /* {{{ overloaded handlers for PDOStatement class */ -static void dbstmt_prop_write(zval *object, zval *member, zval *value, void **cache_slot) +static zval *dbstmt_prop_write(zval *object, zval *member, zval *value, void **cache_slot) { pdo_stmt_t *stmt = Z_PDO_STMT_P(object); @@ -2184,8 +2184,9 @@ static void dbstmt_prop_write(zval *object, zval *member, zval *value, void **ca if (strcmp(Z_STRVAL_P(member), "queryString") == 0) { pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only"); + return value; } else { - zend_std_write_property(object, member, value, cache_slot); + return zend_std_write_property(object, member, value, cache_slot); } } @@ -2499,9 +2500,10 @@ static zval *row_dim_read(zval *object, zval *member, int type, zval *rv) return row_prop_read(object, member, type, NULL, rv); } -static void row_prop_write(zval *object, zval *member, zval *value, void **cache_slot) +static zval *row_prop_write(zval *object, zval *member, zval *value, void **cache_slot) { php_error_docref(NULL, E_WARNING, "This PDORow is not from a writable result set"); + return value; } static void row_dim_write(zval *object, zval *member, zval *value) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 105a87da8b..323a4d2fa4 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -2855,8 +2855,10 @@ ZEND_METHOD(reflection_type, isBuiltin) /* {{{ reflection_type_name */ static zend_string *reflection_type_name(type_reference *param) { - if (ZEND_TYPE_IS_CLASS(param->type)) { + if (ZEND_TYPE_IS_NAME(param->type)) { return zend_string_copy(ZEND_TYPE_NAME(param->type)); + } else if (ZEND_TYPE_IS_CE(param->type)) { + return zend_string_copy(ZEND_TYPE_CE(param->type)->name); } else { char *name = zend_get_type_by_const(ZEND_TYPE_CODE(param->type)); return zend_string_init(name, strlen(name), 0); @@ -3809,7 +3811,7 @@ ZEND_METHOD(reflection_class, getStaticPropertyValue) if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) { return; } - prop = zend_std_get_static_property(ce, name, 1); + prop = zend_std_get_static_property(ce, name, BP_VAR_IS); if (!prop) { if (def_value) { ZVAL_COPY(return_value, def_value); @@ -3830,6 +3832,7 @@ ZEND_METHOD(reflection_class, setStaticPropertyValue) { reflection_object *intern; zend_class_entry *ce; + zend_property_info *prop_info; zend_string *name; zval *variable_ptr, *value; @@ -3842,15 +3845,30 @@ ZEND_METHOD(reflection_class, setStaticPropertyValue) if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) { return; } - variable_ptr = zend_std_get_static_property(ce, name, 1); + variable_ptr = zend_std_get_static_property_with_info(ce, name, BP_VAR_W, &prop_info); if (!variable_ptr) { + zend_clear_exception(); zend_throw_exception_ex(reflection_exception_ptr, 0, "Class %s does not have a property named %s", ZSTR_VAL(ce->name), ZSTR_VAL(name)); return; } - ZVAL_DEREF(variable_ptr); + + if (Z_ISREF_P(variable_ptr)) { + zend_reference *ref = Z_REF_P(variable_ptr); + variable_ptr = Z_REFVAL_P(variable_ptr); + + if (!zend_verify_ref_assignable_zval(ref, value, 0)) { + return; + } + } + + if (prop_info->type && !zend_verify_property_type(prop_info, value, 0)) { + return; + } + zval_ptr_dtor(variable_ptr); ZVAL_COPY(variable_ptr, value); + } /* }}} */ @@ -5463,6 +5481,55 @@ ZEND_METHOD(reflection_property, setValue) } /* }}} */ +/* {{{ proto public mixed ReflectionProperty::isInitialized([stdclass object]) + Returns this property's value */ +ZEND_METHOD(reflection_property, isInitialized) +{ + reflection_object *intern; + property_reference *ref; + zval *object, *name; + zval *member_p = NULL; + + GET_REFLECTION_OBJECT_PTR(ref); + + if (!(ref->prop.flags & ZEND_ACC_PUBLIC) && intern->ignore_visibility == 0) { + name = _default_load_name(getThis()); + zend_throw_exception_ex(reflection_exception_ptr, 0, + "Cannot access non-public member %s::$%s", ZSTR_VAL(intern->ce->name), Z_STRVAL_P(name)); + return; + } + + if (ref->prop.flags & ZEND_ACC_STATIC) { + member_p = zend_read_static_property_ex(intern->ce, ref->unmangled_name, 1); + if (member_p) { + RETURN_BOOL(!Z_ISUNDEF_P(member_p)) + } + RETURN_FALSE; + } else { + zval name_zv; + zend_class_entry *old_scope; + int retval; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &object) == FAILURE) { + return; + } + + if (!instanceof_function(Z_OBJCE_P(object), ref->prop.ce)) { + _DO_THROW("Given object is not an instance of the class this property was declared in"); + /* Returns from this function */ + } + + old_scope = EG(fake_scope); + EG(fake_scope) = intern->ce; + ZVAL_STR(&name_zv, ref->unmangled_name); + retval = Z_OBJ_HT_P(object)->has_property(object, &name_zv, ZEND_PROPERTY_EXISTS, NULL); + EG(fake_scope) = old_scope; + + RETVAL_BOOL(retval); + } +} +/* }}} */ + /* {{{ proto public ReflectionClass ReflectionProperty::getDeclaringClass() Get the declaring class */ ZEND_METHOD(reflection_property, getDeclaringClass) @@ -5530,6 +5597,44 @@ ZEND_METHOD(reflection_property, setAccessible) } /* }}} */ +/* {{{ proto public ReflectionType ReflectionProperty::getType() + Returns the type associated with the property */ +ZEND_METHOD(reflection_property, getType) +{ + reflection_object *intern; + property_reference *ref; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + GET_REFLECTION_OBJECT_PTR(ref); + + if (!ZEND_TYPE_IS_SET(ref->prop.type)) { + RETURN_NULL(); + } + + reflection_type_factory(ref->prop.type, return_value); +} +/* }}} */ + +/* {{{ proto public bool ReflectionProperty::hasType() + Returns whether property has a type */ +ZEND_METHOD(reflection_property, hasType) +{ + reflection_object *intern; + property_reference *ref; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + GET_REFLECTION_OBJECT_PTR(ref); + + RETVAL_BOOL(ZEND_TYPE_IS_SET(ref->prop.type)); +} +/* }}} */ + /* {{{ proto public static mixed ReflectionExtension::export(string name [, bool return]) throws ReflectionException Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */ ZEND_METHOD(reflection_extension, export) @@ -6367,6 +6472,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_property_setValue, 0, 0, 1) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_property_isInitialized, 0, 0, 0) + ZEND_ARG_INFO(0, object) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO(arginfo_reflection_property_setAccessible, 0) ZEND_ARG_INFO(0, visible) ZEND_END_ARG_INFO() @@ -6378,6 +6487,7 @@ static const zend_function_entry reflection_property_functions[] = { ZEND_ME(reflection_property, getName, arginfo_reflection__void, 0) ZEND_ME(reflection_property, getValue, arginfo_reflection_property_getValue, 0) ZEND_ME(reflection_property, setValue, arginfo_reflection_property_setValue, 0) + ZEND_ME(reflection_property, isInitialized, arginfo_reflection_property_isInitialized, 0) ZEND_ME(reflection_property, isPublic, arginfo_reflection__void, 0) ZEND_ME(reflection_property, isPrivate, arginfo_reflection__void, 0) ZEND_ME(reflection_property, isProtected, arginfo_reflection__void, 0) @@ -6387,6 +6497,8 @@ static const zend_function_entry reflection_property_functions[] = { ZEND_ME(reflection_property, getDeclaringClass, arginfo_reflection__void, 0) ZEND_ME(reflection_property, getDocComment, arginfo_reflection__void, 0) ZEND_ME(reflection_property, setAccessible, arginfo_reflection_property_setAccessible, 0) + ZEND_ME(reflection_property, getType, arginfo_reflection__void, 0) + ZEND_ME(reflection_property, hasType, arginfo_reflection__void, 0) PHP_FE_END }; @@ -6516,7 +6628,7 @@ static const zend_function_entry reflection_ext_functions[] = { /* {{{ */ }; /* }}} */ /* {{{ _reflection_write_property */ -static void _reflection_write_property(zval *object, zval *member, zval *value, void **cache_slot) +static zval *_reflection_write_property(zval *object, zval *member, zval *value, void **cache_slot) { if ((Z_TYPE_P(member) == IS_STRING) && zend_hash_exists(&Z_OBJCE_P(object)->properties_info, Z_STR_P(member)) @@ -6525,10 +6637,11 @@ static void _reflection_write_property(zval *object, zval *member, zval *value, { zend_throw_exception_ex(reflection_exception_ptr, 0, "Cannot set read-only property %s::$%s", ZSTR_VAL(Z_OBJCE_P(object)->name), Z_STRVAL_P(member)); + return &EG(uninitialized_zval); } else { - zend_std_write_property(object, member, value, cache_slot); + return zend_std_write_property(object, member, value, cache_slot); } } /* }}} */ diff --git a/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_002.phpt b/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_002.phpt index 14e8382e41..fb472681ca 100644 --- a/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_002.phpt +++ b/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_002.phpt @@ -1,5 +1,5 @@ --TEST-- -ReflectionClass::getStaticPropertyValue() - bad params +ReflectionClass::setStaticPropertyValue() - bad params --CREDITS-- Robin Fernandes <robinf@php.net> Steve Seear <stevseea@php.net> diff --git a/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_003.phpt b/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_003.phpt new file mode 100644 index 0000000000..a83900a123 --- /dev/null +++ b/ext/reflection/tests/ReflectionClass_setStaticPropertyValue_003.phpt @@ -0,0 +1,39 @@ +--TEST-- +ReflectionClass::setStaticPropertyValue() - type constraints must be enforced +--FILE-- +<?php + +class Test { + public static $x; + public static int $y = 2; +} + +$rc = new ReflectionClass('Test'); + +try { + $rc->setStaticPropertyValue("y", "foo"); +} catch (TypeError $e) { echo $e->getMessage(), "\n"; } +var_dump(Test::$y); + +$rc->setStaticPropertyValue("y", "21"); +var_dump(Test::$y); + + +Test::$x =& Test::$y; + +try { + $rc->setStaticPropertyValue("x", "foo"); +} catch (TypeError $e) { echo $e->getMessage(), "\n"; } +var_dump(Test::$y); + +$rc->setStaticPropertyValue("x", "42"); +var_dump(Test::$y); + +?> +--EXPECT-- +Typed property Test::$y must be int, string used +int(2) +int(21) +Cannot assign string to reference held by property Test::$y of type int +int(21) +int(42) diff --git a/ext/reflection/tests/ReflectionProperty_isInitialized.phpt b/ext/reflection/tests/ReflectionProperty_isInitialized.phpt new file mode 100644 index 0000000000..f1f6e53ebd --- /dev/null +++ b/ext/reflection/tests/ReflectionProperty_isInitialized.phpt @@ -0,0 +1,113 @@ +--TEST-- +Test ReflectionProperty::isInitialized() +--FILE-- +<?php + +class A { + public static ?string $ssv = null; + public static ?string $ss; + public static $s; + public ?int $iv = null; + public ?int $i; + public $n; + + private int $p; +} + +class B extends A { } + +echo "Static properties:\n"; +var_dump((new ReflectionProperty(A::class, 'ssv'))->isInitialized()); +var_dump((new ReflectionProperty(A::class, 'ss'))->isInitialized()); +var_dump((new ReflectionProperty(A::class, 's'))->isInitialized()); + +echo "Declared properties:\n"; +$a = new A; +var_dump((new ReflectionProperty($a, 'iv'))->isInitialized($a)); +var_dump((new ReflectionProperty($a, 'i'))->isInitialized($a)); +var_dump((new ReflectionProperty($a, 'n'))->isInitialized($a)); + +echo "Declared properties after unset:\n"; +unset($a->iv); +unset($a->i); +unset($a->n); +var_dump((new ReflectionProperty($a, 'i'))->isInitialized($a)); +var_dump((new ReflectionProperty($a, 'iv'))->isInitialized($a)); +var_dump((new ReflectionProperty($a, 'n'))->isInitialized($a)); + +echo "Dynamic properties:\n"; +$a->d = null; +$rp = new ReflectionProperty($a, 'd'); +var_dump($rp->isInitialized($a)); +unset($a->d); +var_dump($rp->isInitialized($a)); + +echo "Visibility handling:\n"; +$rp = new ReflectionProperty('A', 'p'); +try { + var_dump($rp->isInitialized($a)); +} catch (ReflectionException $e) { + echo $e->getMessage(), "\n"; +} +$rp->setAccessible(true); +var_dump($rp->isInitialized($a)); + +echo "Object type:\n"; +$rp = new ReflectionProperty('B', 'i'); +var_dump($rp->isInitialized($a)); + +try { + var_dump($rp->isInitialized(new stdClass)); +} catch (ReflectionException $e) { + echo $e->getMessage(), "\n"; +} + +class WithMagic { + public $prop; + public int $intProp; + + public function __isset($name) { + echo "__isset($name)\n"; + return true; + } + + public function __get($name) { + echo "__get($name)\n"; + return "foobar"; + } +} + +echo "Class with __isset:\n"; +$obj = new WithMagic; +unset($obj->prop); +$rp = new ReflectionProperty('WithMagic', 'prop'); +var_dump($rp->isInitialized($obj)); +$rp = new ReflectionProperty('WithMagic', 'intProp'); +var_dump($rp->isInitialized($obj)); + +?> +--EXPECT-- +Static properties: +bool(true) +bool(false) +bool(true) +Declared properties: +bool(true) +bool(false) +bool(true) +Declared properties after unset: +bool(false) +bool(false) +bool(false) +Dynamic properties: +bool(true) +bool(false) +Visibility handling: +Cannot access non-public member A::$p +bool(false) +Object type: +bool(false) +Given object is not an instance of the class this property was declared in +Class with __isset: +bool(false) +bool(false) diff --git a/ext/reflection/tests/ReflectionProperty_typed_static.phpt b/ext/reflection/tests/ReflectionProperty_typed_static.phpt new file mode 100644 index 0000000000..77f95d77ef --- /dev/null +++ b/ext/reflection/tests/ReflectionProperty_typed_static.phpt @@ -0,0 +1,51 @@ +--TEST-- +ReflectionProperty::getValue() on typed static property +--FILE-- +<?php + +class Test { + public static int $x = 42; + public static int $y; + public static $z; +} + +$rp = new ReflectionProperty('Test', 'x'); +var_dump($rp->getValue()); + +$rp = new ReflectionProperty('Test', 'y'); +try { + var_dump($rp->getValue()); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +$rp->setValue("24"); +var_dump($rp->getValue()); + +try { + $rp->setValue("foo"); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +var_dump($rp->getValue()); + +Test::$z =& Test::$y; + +$rp = new ReflectionProperty('Test', 'z'); +try { + $rp->setValue("foo"); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +var_dump($rp->getValue()); + + +?> +--EXPECT-- +int(42) +Typed static property Test::$y must not be accessed before initialization +int(24) +Typed property Test::$y must be int, string used +int(24) +Cannot assign string to reference held by property Test::$y of type int +int(24) diff --git a/ext/reflection/tests/ReflectionType_001.phpt b/ext/reflection/tests/ReflectionType_001.phpt index d949e18107..e47a9615ba 100644 --- a/ext/reflection/tests/ReflectionType_001.phpt +++ b/ext/reflection/tests/ReflectionType_001.phpt @@ -74,6 +74,32 @@ foreach ([ } } +echo "\n*** property types\n"; + +class PropTypeTest { + public int $int; + public string $string; + public array $arr; + public iterable $iterable; + public stdClass $std; + public OtherThing $other; + public $mixed; +} + +$reflector = new ReflectionClass(PropTypeTest::class); + +foreach ($reflector->getProperties() as $name => $property) { + if ($property->hasType()) { + printf("public %s $%s;\n", + $property->getType(), $property->getName()); + } else printf("public $%s;\n", $property->getName()); +} + +echo "*** resolved property types\n"; +$obj = new PropTypeTest; +$obj->std = new stdClass; +$r = (new ReflectionProperty($obj, 'std'))->getType(); +var_dump($r->getName()); ?> --EXPECT-- *** functions @@ -185,3 +211,14 @@ bool(true) bool(false) bool(false) string(4) "Test" + +*** property types +public int $int; +public string $string; +public array $arr; +public iterable $iterable; +public stdClass $std; +public OtherThing $other; +public $mixed; +*** resolved property types +string(8) "stdClass" diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 15618244ff..49f2a8a7e6 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -415,7 +415,7 @@ static void change_node_zval(xmlNodePtr node, zval *value) /* {{{ sxe_property_write() */ -static int sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_bool elements, zend_bool attribs, xmlNodePtr *pnewnode) +static zval *sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_bool elements, zend_bool attribs, xmlNodePtr *pnewnode) { php_sxe_object *sxe; xmlNodePtr node; @@ -429,7 +429,6 @@ static int sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_bool int test = 0; int new_value = 0; zend_long cnt = 0; - int retval = SUCCESS; zval tmp_zv, zval_copy; zend_string *trim_str; @@ -442,7 +441,7 @@ static int sxe_prop_dim_write(zval *object, zval *member, zval *value, zend_bool * and this is during runtime. */ zend_throw_error(NULL, "Cannot create unnamed attribute"); - return FAILURE; + return &EG(error_zval); } goto long_dim; } else { @@ -466,7 +465,7 @@ long_dim: if (member == &tmp_zv) { zval_ptr_dtor_str(&tmp_zv); } - return FAILURE; + return &EG(error_zval); } } } @@ -491,7 +490,7 @@ long_dim: * and this is during runtime. */ zend_throw_error(NULL, "Cannot create unnamed attribute"); - return FAILURE; + return &EG(error_zval); } if (attribs && !node && sxe->iter.type == SXE_ITER_ELEMENT) { node = xmlNewChild(mynode, mynode->ns, sxe->iter.name, NULL); @@ -528,7 +527,7 @@ long_dim: zval_ptr_dtor_str(&tmp_zv); } zend_error(E_WARNING, "It is not yet possible to assign complex types to %s", attribs ? "attributes" : "properties"); - return FAILURE; + return &EG(error_zval); } } @@ -566,7 +565,7 @@ long_dim: if (new_value) { zval_ptr_dtor(value); } - return FAILURE; + return &EG(error_zval); } if (sxe->iter.type == SXE_ITER_NONE) { @@ -574,7 +573,7 @@ long_dim: ++counter; if (member && Z_LVAL_P(member) > 0) { php_error_docref(NULL, E_WARNING, "Cannot add element %s number " ZEND_LONG_FMT " when only 0 such elements exist", mynode->name, Z_LVAL_P(member)); - retval = FAILURE; + value = &EG(error_zval); } } else if (member) { newnode = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, &cnt); @@ -611,7 +610,7 @@ next_iter: } } else if (counter > 1) { php_error_docref(NULL, E_WARNING, "Cannot assign to an array of nodes (duplicate subnodes or attr detected)"); - retval = FAILURE; + value = &EG(error_zval); } else if (elements) { if (!node) { if (!member || Z_TYPE_P(member) == IS_LONG) { @@ -622,14 +621,12 @@ next_iter: } else if (!member || Z_TYPE_P(member) == IS_LONG) { if (member && cnt < Z_LVAL_P(member)) { php_error_docref(NULL, E_WARNING, "Cannot add element %s number " ZEND_LONG_FMT " when only " ZEND_LONG_FMT " such elements exist", mynode->name, Z_LVAL_P(member), cnt); - retval = FAILURE; } newnode = xmlNewTextChild(mynode->parent, mynode->ns, mynode->name, value ? (xmlChar *)Z_STRVAL_P(value) : NULL); } } else if (attribs) { if (Z_TYPE_P(member) == IS_LONG) { php_error_docref(NULL, E_WARNING, "Cannot change attribute number " ZEND_LONG_FMT " when only %d attributes exist", Z_LVAL_P(member), nodendx); - retval = FAILURE; } else { newnode = (xmlNodePtr)xmlNewProp(node, (xmlChar *)Z_STRVAL_P(member), value ? (xmlChar *)Z_STRVAL_P(value) : NULL); } @@ -645,15 +642,17 @@ next_iter: if (new_value) { zval_ptr_dtor(value); } - return retval; + return value; } /* }}} */ /* {{{ sxe_property_write() */ -static void sxe_property_write(zval *object, zval *member, zval *value, void **cache_slot) +static zval *sxe_property_write(zval *object, zval *member, zval *value, void **cache_slot) { - sxe_prop_dim_write(object, member, value, 1, 0, NULL); + zval *retval = sxe_prop_dim_write(object, member, value, 1, 0, NULL); + + return retval == &EG(error_zval) ? &EG(uninitialized_zval) : retval; } /* }}} */ @@ -682,7 +681,7 @@ static zval *sxe_property_get_adr(zval *object, zval *member, int fetch_type, vo if (node) { return NULL; } - if (sxe_prop_dim_write(object, member, NULL, 1, 0, &node) != SUCCESS) { + if (sxe_prop_dim_write(object, member, NULL, 1, 0, &node) == &EG(error_zval)) { return NULL; } type = SXE_ITER_NONE; diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c index 7ee8ce416a..375d1556ad 100644 --- a/ext/snmp/snmp.c +++ b/ext/snmp/snmp.c @@ -1949,7 +1949,7 @@ zval *php_snmp_read_property(zval *object, zval *member, int type, void **cache_ /* {{{ php_snmp_write_property(zval *object, zval *member, zval *value[, const zend_literal *key]) Generic object property writer */ -void php_snmp_write_property(zval *object, zval *member, zval *value, void **cache_slot) +zval *php_snmp_write_property(zval *object, zval *member, zval *value, void **cache_slot) { zval tmp_member; php_snmp_object *obj; @@ -1973,12 +1973,14 @@ void php_snmp_write_property(zval *object, zval *member, zval *value, void **cac } */ } else { - zend_std_write_property(object, member, value, cache_slot); + value = zend_std_write_property(object, member, value, cache_slot); } if (member == &tmp_member) { zval_ptr_dtor(member); } + + return value; } /* }}} */ diff --git a/ext/soap/soap.c b/ext/soap/soap.c index c661dbd793..4888309d28 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -2800,7 +2800,7 @@ static void verify_soap_headers_array(HashTable *ht) /* {{{ */ } /* }}} */ -/* {{{ proto mixed SoapClient::__call(string function_name, array arguments [, array options [, array input_headers [, array output_headers]]]) +/* {{{ proto mixed SoapClient::__call(string function_name, array arguments [, array options [, array input_headers [, array &output_headers]]]) Calls a SOAP function */ PHP_METHOD(SoapClient, __call) { @@ -2819,7 +2819,7 @@ PHP_METHOD(SoapClient, __call) zend_bool free_soap_headers = 0; zval *this_ptr; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa|a!zz/", + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa|a!zz", &function, &function_len, &args, &options, &headers, &output_headers) == FAILURE) { return; } @@ -2891,14 +2891,18 @@ PHP_METHOD(SoapClient, __call) } ZEND_HASH_FOREACH_END(); } if (output_headers) { - zval_ptr_dtor(output_headers); - array_init(output_headers); + output_headers = zend_try_array_init(output_headers); + if (!output_headers) { + goto cleanup; + } } + do_soap_call(execute_data, this_ptr, function, function_len, arg_count, real_args, return_value, location, soap_action, uri, soap_headers, output_headers); + +cleanup: if (arg_count > 0) { efree(real_args); } - if (soap_headers && free_soap_headers) { zend_hash_destroy(soap_headers); efree(soap_headers); diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 1f3a4cd4c7..f80075d3d5 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -1313,7 +1313,7 @@ PHP_FUNCTION(socket_getsockname) char *addr_string; socklen_t salen = sizeof(php_sockaddr_storage); - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|z/", &arg1, &addr, &port) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz|z", &arg1, &addr, &port) == FAILURE) { return; } @@ -1337,12 +1337,10 @@ PHP_FUNCTION(socket_getsockname) case AF_INET6: sin6 = (struct sockaddr_in6 *) sa; inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN); - zval_ptr_dtor(addr); - ZVAL_STRING(addr, addr6); + ZEND_TRY_ASSIGN_STRING(addr, addr6); if (port != NULL) { - zval_ptr_dtor(port); - ZVAL_LONG(port, htons(sin6->sin6_port)); + ZEND_TRY_ASSIGN_LONG(port, htons(sin6->sin6_port)); } RETURN_TRUE; break; @@ -1354,12 +1352,10 @@ PHP_FUNCTION(socket_getsockname) addr_string = inet_ntoa(sin->sin_addr); inet_ntoa_lock = 0; - zval_ptr_dtor(addr); - ZVAL_STRING(addr, addr_string); + ZEND_TRY_ASSIGN_STRING(addr, addr_string); if (port != NULL) { - zval_ptr_dtor(port); - ZVAL_LONG(port, htons(sin->sin_port)); + ZEND_TRY_ASSIGN_LONG(port, htons(sin->sin_port)); } RETURN_TRUE; break; @@ -1367,8 +1363,7 @@ PHP_FUNCTION(socket_getsockname) case AF_UNIX: s_un = (struct sockaddr_un *) sa; - zval_ptr_dtor(addr); - ZVAL_STRING(addr, s_un->sun_path); + ZEND_TRY_ASSIGN_STRING(addr, s_un->sun_path); RETURN_TRUE; break; @@ -1396,7 +1391,7 @@ PHP_FUNCTION(socket_getpeername) char *addr_string; socklen_t salen = sizeof(php_sockaddr_storage); - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/|z/", &arg1, &arg2, &arg3) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz|z", &arg1, &arg2, &arg3) == FAILURE) { return; } @@ -1416,12 +1411,11 @@ PHP_FUNCTION(socket_getpeername) case AF_INET6: sin6 = (struct sockaddr_in6 *) sa; inet_ntop(AF_INET6, &sin6->sin6_addr, addr6, INET6_ADDRSTRLEN); - zval_ptr_dtor(arg2); - ZVAL_STRING(arg2, addr6); + + ZEND_TRY_ASSIGN_STRING(arg2, addr6); if (arg3 != NULL) { - zval_ptr_dtor(arg3); - ZVAL_LONG(arg3, htons(sin6->sin6_port)); + ZEND_TRY_ASSIGN_LONG(arg3, htons(sin6->sin6_port)); } RETURN_TRUE; @@ -1434,12 +1428,10 @@ PHP_FUNCTION(socket_getpeername) addr_string = inet_ntoa(sin->sin_addr); inet_ntoa_lock = 0; - zval_ptr_dtor(arg2); - ZVAL_STRING(arg2, addr_string); + ZEND_TRY_ASSIGN_STRING(arg2, addr_string); if (arg3 != NULL) { - zval_ptr_dtor(arg3); - ZVAL_LONG(arg3, htons(sin->sin_port)); + ZEND_TRY_ASSIGN_LONG(arg3, htons(sin->sin_port)); } RETURN_TRUE; @@ -1448,8 +1440,7 @@ PHP_FUNCTION(socket_getpeername) case AF_UNIX: s_un = (struct sockaddr_un *) sa; - zval_ptr_dtor(arg2); - ZVAL_STRING(arg2, s_un->sun_path); + ZEND_TRY_ASSIGN_STRING(arg2, s_un->sun_path); RETURN_TRUE; break; @@ -1703,7 +1694,7 @@ PHP_FUNCTION(socket_recv) int retval; zend_long len, flags; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/ll", &php_sock_res, &buf, &len, &flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rzll", &php_sock_res, &buf, &len, &flags) == FAILURE) { return; } @@ -1720,16 +1711,11 @@ PHP_FUNCTION(socket_recv) if ((retval = recv(php_sock->bsd_socket, ZSTR_VAL(recv_buf), len, flags)) < 1) { zend_string_efree(recv_buf); - - zval_ptr_dtor(buf); - ZVAL_NULL(buf); + ZEND_TRY_ASSIGN_NULL(buf); } else { ZSTR_LEN(recv_buf) = retval; ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0'; - - /* Rebuild buffer zval */ - zval_ptr_dtor(buf); - ZVAL_NEW_STR(buf, recv_buf); + ZEND_TRY_ASSIGN_NEW_STR(buf, recv_buf); } if (retval == -1) { @@ -1793,7 +1779,7 @@ PHP_FUNCTION(socket_recvfrom) char *address; zend_string *recv_buf; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rz/llz/|z/", &arg1, &arg2, &arg3, &arg4, &arg5, &arg6) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rzllz|z", &arg1, &arg2, &arg3, &arg4, &arg5, &arg6) == FAILURE) { return; } @@ -1824,11 +1810,8 @@ PHP_FUNCTION(socket_recvfrom) ZSTR_LEN(recv_buf) = retval; ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0'; - zval_ptr_dtor(arg2); - zval_ptr_dtor(arg5); - - ZVAL_NEW_STR(arg2, recv_buf); - ZVAL_STRING(arg5, s_un.sun_path); + ZEND_TRY_ASSIGN_NEW_STR(arg2, recv_buf); + ZEND_TRY_ASSIGN_STRING(arg5, s_un.sun_path); break; case AF_INET: @@ -1851,15 +1834,11 @@ PHP_FUNCTION(socket_recvfrom) ZSTR_LEN(recv_buf) = retval; ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0'; - zval_ptr_dtor(arg2); - zval_ptr_dtor(arg5); - zval_ptr_dtor(arg6); - address = inet_ntoa(sin.sin_addr); - ZVAL_NEW_STR(arg2, recv_buf); - ZVAL_STRING(arg5, address ? address : "0.0.0.0"); - ZVAL_LONG(arg6, ntohs(sin.sin_port)); + ZEND_TRY_ASSIGN_NEW_STR(arg2, recv_buf); + ZEND_TRY_ASSIGN_STRING(arg5, address ? address : "0.0.0.0"); + ZEND_TRY_ASSIGN_LONG(arg6, ntohs(sin.sin_port)); break; #if HAVE_IPV6 case AF_INET6: @@ -1882,16 +1861,12 @@ PHP_FUNCTION(socket_recvfrom) ZSTR_LEN(recv_buf) = retval; ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0'; - zval_ptr_dtor(arg2); - zval_ptr_dtor(arg5); - zval_ptr_dtor(arg6); - memset(addr6, 0, INET6_ADDRSTRLEN); inet_ntop(AF_INET6, &sin6.sin6_addr, addr6, INET6_ADDRSTRLEN); - ZVAL_NEW_STR(arg2, recv_buf); - ZVAL_STRING(arg5, addr6[0] ? addr6 : "::"); - ZVAL_LONG(arg6, ntohs(sin6.sin6_port)); + ZEND_TRY_ASSIGN_NEW_STR(arg2, recv_buf); + ZEND_TRY_ASSIGN_STRING(arg5, addr6[0] ? addr6 : "::"); + ZEND_TRY_ASSIGN_LONG(arg6, ntohs(sin6.sin6_port)); break; #endif default: @@ -2253,7 +2228,7 @@ PHP_FUNCTION(socket_create_pair) PHP_SOCKET fds_array[2]; zend_long domain, type, protocol; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "lllz/", &domain, &type, &protocol, &fds_array_zval) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "lllz", &domain, &type, &protocol, &fds_array_zval) == FAILURE) { return; } @@ -2282,8 +2257,12 @@ PHP_FUNCTION(socket_create_pair) RETURN_FALSE; } - zval_ptr_dtor(fds_array_zval); - array_init(fds_array_zval); + fds_array_zval = zend_try_array_init(fds_array_zval); + if (!fds_array_zval) { + efree(php_sock[0]); + efree(php_sock[1]); + return; + } php_sock[0]->bsd_socket = fds_array[0]; php_sock[1]->bsd_socket = fds_array[1]; diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 91dec7c09e..748263984a 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -878,16 +878,16 @@ static zval *spl_array_read_property(zval *object, zval *member, int type, void return zend_std_read_property(object, member, type, cache_slot, rv); } /* }}} */ -static void spl_array_write_property(zval *object, zval *member, zval *value, void **cache_slot) /* {{{ */ +static zval *spl_array_write_property(zval *object, zval *member, zval *value, void **cache_slot) /* {{{ */ { spl_array_object *intern = Z_SPLARRAY_P(object); if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0 && !zend_std_has_property(object, member, ZEND_PROPERTY_EXISTS, NULL)) { spl_array_write_dimension(object, member, value); - return; + return value; } - zend_std_write_property(object, member, value, cache_slot); + return zend_std_write_property(object, member, value, cache_slot); } /* }}} */ static zval *spl_array_get_property_ptr_ptr(zval *object, zval *member, int type, void **cache_slot) /* {{{ */ diff --git a/ext/spl/tests/iterator_035.phpt b/ext/spl/tests/iterator_035.phpt index e6d68fbea6..0688635450 100644 --- a/ext/spl/tests/iterator_035.phpt +++ b/ext/spl/tests/iterator_035.phpt @@ -14,7 +14,7 @@ echo "Done\n"; --EXPECTF-- Notice: Indirect modification of overloaded element of ArrayIterator has no effect in %s on line %d -Fatal error: Uncaught Error: Cannot assign by reference to overloaded object in %s:%d +Fatal error: Uncaught Error: Cannot assign by reference to an array dimension of an object in %s:%d Stack trace: #0 {main} thrown in %s on line %d diff --git a/ext/standard/array.c b/ext/standard/array.c index 33ea028602..8088c0da8a 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -1786,9 +1786,11 @@ static zend_long php_extract_if_exists(zend_array *arr, zend_array *symbol_table zend_throw_error(NULL, "Cannot re-assign $this"); return -1; } - ZVAL_DEREF(orig_var); - zval_ptr_dtor(orig_var); - ZVAL_COPY_DEREF(orig_var, entry); + ZVAL_DEREF(entry); + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + return -1; + } count++; } } ZEND_HASH_FOREACH_END(); @@ -1869,9 +1871,11 @@ static zend_long php_extract_overwrite(zend_array *arr, zend_array *symbol_table if (zend_string_equals_literal(var_name, "GLOBALS")) { continue; } - ZVAL_DEREF(orig_var); - zval_ptr_dtor(orig_var); - ZVAL_COPY_DEREF(orig_var, entry); + ZVAL_DEREF(entry); + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + return -1; + } } else { ZVAL_DEREF(entry); Z_TRY_ADDREF_P(entry); @@ -1971,9 +1975,11 @@ static zend_long php_extract_prefix_if_exists(zend_array *arr, zend_array *symbo if (Z_TYPE_P(orig_var) == IS_INDIRECT) { orig_var = Z_INDIRECT_P(orig_var); } - ZVAL_DEREF(orig_var); - zval_ptr_dtor(orig_var); - ZVAL_COPY(orig_var, entry); + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + zend_string_release_ex(Z_STR(final_name), 0); + return -1; + } } else { Z_TRY_ADDREF_P(entry); zend_hash_add_new(symbol_table, Z_STR(final_name), entry); @@ -2097,9 +2103,11 @@ static zend_long php_extract_prefix_same(zend_array *arr, zend_array *symbol_tab if (Z_TYPE_P(orig_var) == IS_INDIRECT) { orig_var = Z_INDIRECT_P(orig_var); } - ZVAL_DEREF(orig_var); - zval_ptr_dtor(orig_var); - ZVAL_COPY(orig_var, entry); + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + zend_string_release_ex(Z_STR(final_name), 0); + return -1; + } } else { Z_TRY_ADDREF_P(entry); zend_hash_add_new(symbol_table, Z_STR(final_name), entry); @@ -2202,9 +2210,11 @@ static zend_long php_extract_prefix_all(zend_array *arr, zend_array *symbol_tabl if (Z_TYPE_P(orig_var) == IS_INDIRECT) { orig_var = Z_INDIRECT_P(orig_var); } - ZVAL_DEREF(orig_var); - zval_ptr_dtor(orig_var); - ZVAL_COPY(orig_var, entry); + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + zend_string_release_ex(Z_STR(final_name), 0); + return -1; + } } else { Z_TRY_ADDREF_P(entry); zend_hash_add_new(symbol_table, Z_STR(final_name), entry); @@ -2309,9 +2319,11 @@ static zend_long php_extract_prefix_invalid(zend_array *arr, zend_array *symbol_ if (Z_TYPE_P(orig_var) == IS_INDIRECT) { orig_var = Z_INDIRECT_P(orig_var); } - ZVAL_DEREF(orig_var); - zval_ptr_dtor(orig_var); - ZVAL_COPY(orig_var, entry); + ZEND_TRY_ASSIGN_COPY_EX(orig_var, entry, 0); + if (UNEXPECTED(EG(exception))) { + zend_string_release_ex(Z_STR(final_name), 0); + return -1; + } } else { Z_TRY_ADDREF_P(entry); zend_hash_add_new(symbol_table, Z_STR(final_name), entry); diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 9026cacc79..38949a6080 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -4376,13 +4376,12 @@ PHP_FUNCTION(getopt) Z_PARAM_STRING(options, options_len) Z_PARAM_OPTIONAL Z_PARAM_ARRAY(p_longopts) - Z_PARAM_ZVAL_DEREF(zoptind) + Z_PARAM_ZVAL(zoptind) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); /* Init zoptind to 1 */ if (zoptind) { - zval_ptr_dtor(zoptind); - ZVAL_LONG(zoptind, 1); + ZEND_TRY_ASSIGN_LONG(zoptind, 1); } /* Get argv from the global symbol table. We calculate argc ourselves @@ -4530,7 +4529,7 @@ PHP_FUNCTION(getopt) /* Set zoptind to php_optind */ if (zoptind) { - ZVAL_LONG(zoptind, php_optind); + ZEND_TRY_ASSIGN_LONG(zoptind, php_optind); } free_longopts(orig_opts); diff --git a/ext/standard/dns.c b/ext/standard/dns.c index 50f81153a5..15005dce0e 100644 --- a/ext/standard/dns.c +++ b/ext/standard/dns.c @@ -816,18 +816,22 @@ PHP_FUNCTION(dns_get_record) Z_PARAM_STRING(hostname, hostname_len) Z_PARAM_OPTIONAL Z_PARAM_LONG(type_param) - Z_PARAM_ZVAL_DEREF_EX(authns, 1, 0) - Z_PARAM_ZVAL_DEREF_EX(addtl, 1, 0) + Z_PARAM_ZVAL(authns) + Z_PARAM_ZVAL(addtl) Z_PARAM_BOOL(raw) ZEND_PARSE_PARAMETERS_END(); if (authns) { - zval_ptr_dtor(authns); - array_init(authns); + authns = zend_try_array_init(authns); + if (!authns) { + return; + } } if (addtl) { - zval_ptr_dtor(addtl); - array_init(addtl); + addtl = zend_try_array_init(addtl); + if (!addtl) { + return; + } } if (!raw) { @@ -1049,17 +1053,21 @@ PHP_FUNCTION(dns_get_mx) ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING(hostname, hostname_len) - Z_PARAM_ZVAL_DEREF(mx_list) + Z_PARAM_ZVAL(mx_list) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_DEREF(weight_list) + Z_PARAM_ZVAL(weight_list) ZEND_PARSE_PARAMETERS_END(); - zval_ptr_dtor(mx_list); - array_init(mx_list); + mx_list = zend_try_array_init(mx_list); + if (!mx_list) { + return; + } if (weight_list) { - zval_ptr_dtor(weight_list); - array_init(weight_list); + weight_list = zend_try_array_init(weight_list); + if (!weight_list) { + return; + } } #if defined(HAVE_DNS_SEARCH) diff --git a/ext/standard/dns_win32.c b/ext/standard/dns_win32.c index aa11a01f47..393b41d0e8 100644 --- a/ext/standard/dns_win32.c +++ b/ext/standard/dns_win32.c @@ -50,7 +50,7 @@ PHP_FUNCTION(dns_get_mx) /* {{{ */ DNS_STATUS status; /* Return value of DnsQuery_A() function */ PDNS_RECORD pResult, pRec; /* Pointer to DNS_RECORD structure */ - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/|z/", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|z", &hostname, &hostname_len, &mx_list, &weight_list) == FAILURE) { return; } @@ -60,12 +60,16 @@ PHP_FUNCTION(dns_get_mx) /* {{{ */ RETURN_FALSE; } - zval_ptr_dtor(mx_list); - array_init(mx_list); + mx_list = zend_try_array_init(mx_list); + if (!mx_list) { + goto cleanup; + } if (weight_list) { - zval_ptr_dtor(weight_list); - array_init(weight_list); + weight_list = zend_try_array_init(weight_list); + if (!weight_list) { + goto cleanup; + } } for (pRec = pResult; pRec; pRec = pRec->pNext) { @@ -81,6 +85,7 @@ PHP_FUNCTION(dns_get_mx) /* {{{ */ } } +cleanup: /* Free memory allocated for DNS records. */ DnsRecordListFree(pResult, DnsFreeRecordListDeep); @@ -352,18 +357,22 @@ PHP_FUNCTION(dns_get_record) int type, type_to_fetch, first_query = 1, store_results = 1; zend_bool raw = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|lz/!z/!b", + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|lz!z!b", &hostname, &hostname_len, &type_param, &authns, &addtl, &raw) == FAILURE) { return; } if (authns) { - zval_ptr_dtor(authns); - array_init(authns); + authns = zend_try_array_init(authns); + if (!authns) { + return; + } } if (addtl) { - zval_ptr_dtor(addtl); - array_init(addtl); + addtl = zend_try_array_init(addtl); + if (!addtl) { + return; + } } if (!raw) { diff --git a/ext/standard/exec.c b/ext/standard/exec.c index 5b885c554d..bfad4173a7 100644 --- a/ext/standard/exec.c +++ b/ext/standard/exec.c @@ -216,9 +216,9 @@ static void php_exec_ex(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */ Z_PARAM_STRING(cmd, cmd_len) Z_PARAM_OPTIONAL if (!mode) { - Z_PARAM_ZVAL_DEREF(ret_array) + Z_PARAM_ZVAL(ret_array) } - Z_PARAM_ZVAL_DEREF(ret_code) + Z_PARAM_ZVAL(ret_code) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); if (!cmd_len) { @@ -233,18 +233,20 @@ static void php_exec_ex(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */ if (!ret_array) { ret = php_exec(mode, cmd, NULL, return_value); } else { - if (Z_TYPE_P(ret_array) != IS_ARRAY) { - zval_ptr_dtor(ret_array); - array_init(ret_array); - } else if (Z_REFCOUNT_P(ret_array) > 1) { - zval_ptr_dtor(ret_array); - ZVAL_ARR(ret_array, zend_array_dup(Z_ARR_P(ret_array))); + if (Z_TYPE_P(Z_REFVAL_P(ret_array)) == IS_ARRAY) { + ZVAL_DEREF(ret_array); + SEPARATE_ARRAY(ret_array); + } else { + ret_array = zend_try_array_init(ret_array); + if (!ret_array) { + return; + } } + ret = php_exec(2, cmd, ret_array, return_value); } if (ret_code) { - zval_ptr_dtor(ret_code); - ZVAL_LONG(ret_code, ret); + ZEND_TRY_ASSIGN_LONG(ret_code, ret); } } /* }}} */ diff --git a/ext/standard/file.c b/ext/standard/file.c index c962ba4824..93b58e9a94 100644 --- a/ext/standard/file.c +++ b/ext/standard/file.c @@ -343,7 +343,7 @@ PHP_FUNCTION(flock) Z_PARAM_RESOURCE(res) Z_PARAM_LONG(operation) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_DEREF(wouldblock) + Z_PARAM_ZVAL(wouldblock) ZEND_PARSE_PARAMETERS_END(); PHP_STREAM_TO_ZVAL(stream, res); @@ -355,15 +355,14 @@ PHP_FUNCTION(flock) } if (wouldblock) { - zval_ptr_dtor(wouldblock); - ZVAL_LONG(wouldblock, 0); + ZEND_TRY_ASSIGN_LONG(wouldblock, 0); } /* flock_values contains all possible actions if (operation & 4) we won't block on the lock */ act = flock_values[act - 1] | (operation & PHP_LOCK_NB ? LOCK_NB : 0); if (php_stream_lock(stream, act)) { if (operation && errno == EWOULDBLOCK && wouldblock) { - ZVAL_LONG(wouldblock, 1); + ZEND_TRY_ASSIGN_LONG(wouldblock, 1); } RETURN_FALSE; } diff --git a/ext/standard/fsock.c b/ext/standard/fsock.c index 6fc7143cd6..32e651d1e4 100644 --- a/ext/standard/fsock.c +++ b/ext/standard/fsock.c @@ -53,8 +53,8 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent) Z_PARAM_STRING(host, host_len) Z_PARAM_OPTIONAL Z_PARAM_LONG(port) - Z_PARAM_ZVAL_DEREF(zerrno) - Z_PARAM_ZVAL_DEREF(zerrstr) + Z_PARAM_ZVAL(zerrno) + Z_PARAM_ZVAL(zerrstr) Z_PARAM_DOUBLE(timeout) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); @@ -79,15 +79,6 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent) #endif tv.tv_usec = conv % 1000000; - if (zerrno) { - zval_ptr_dtor(zerrno); - ZVAL_LONG(zerrno, 0); - } - if (zerrstr) { - zval_ptr_dtor(zerrstr); - ZVAL_EMPTY_STRING(zerrstr); - } - stream = php_stream_xport_create(hostname, hostname_len, REPORT_ERRORS, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, hashkey, &tv, NULL, &errstr, &err); @@ -102,22 +93,27 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent) efree(hashkey); } - if (stream == NULL) { + if (stream == NULL) { if (zerrno) { - zval_ptr_dtor(zerrno); - ZVAL_LONG(zerrno, err); + ZEND_TRY_ASSIGN_LONG(zerrno, err); } - if (zerrstr && errstr) { - /* no need to dup; we need to efree buf anyway */ - zval_ptr_dtor(zerrstr); - ZVAL_STR(zerrstr, errstr); - } else if (!zerrstr && errstr) { - zend_string_release_ex(errstr, 0); + if (errstr) { + if (zerrstr) { + ZEND_TRY_ASSIGN_STR(zerrstr, errstr); + } + zend_string_release(errstr); } RETURN_FALSE; } + if (zerrno) { + ZEND_TRY_ASSIGN_LONG(zerrno, 0); + } + if (zerrstr) { + ZEND_TRY_ASSIGN_EMPTY_STRING(zerrstr); + } + if (errstr) { zend_string_release_ex(errstr, 0); } diff --git a/ext/standard/head.c b/ext/standard/head.c index 302599f02b..be2b2668f0 100644 --- a/ext/standard/head.c +++ b/ext/standard/head.c @@ -358,8 +358,8 @@ PHP_FUNCTION(headers_sent) ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_DEREF(arg1) - Z_PARAM_ZVAL_DEREF(arg2) + Z_PARAM_ZVAL(arg1) + Z_PARAM_ZVAL(arg2) ZEND_PARSE_PARAMETERS_END(); if (SG(headers_sent)) { @@ -369,14 +369,12 @@ PHP_FUNCTION(headers_sent) switch(ZEND_NUM_ARGS()) { case 2: - zval_ptr_dtor(arg2); - ZVAL_LONG(arg2, line); + ZEND_TRY_ASSIGN_LONG(arg2, line); case 1: - zval_ptr_dtor(arg1); if (file) { - ZVAL_STRING(arg1, file); + ZEND_TRY_ASSIGN_STRING(arg1, file); } else { - ZVAL_EMPTY_STRING(arg1); + ZEND_TRY_ASSIGN_EMPTY_STRING(arg1); } break; } diff --git a/ext/standard/image.c b/ext/standard/image.c index d32d1499f3..cf9ba12be8 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -1493,12 +1493,14 @@ static void php_getimagesize_from_any(INTERNAL_FUNCTION_PARAMETERS, int mode) { ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_STRING(input, input_len) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_DEREF(info) + Z_PARAM_ZVAL(info) ZEND_PARSE_PARAMETERS_END(); if (argc == 2) { - zval_ptr_dtor(info); - array_init(info); + info = zend_try_array_init(info); + if (!info) { + return; + } } if (mode == FROM_PATH) { diff --git a/ext/standard/incomplete_class.c b/ext/standard/incomplete_class.c index 943dafaa43..87a17ab7f6 100644 --- a/ext/standard/incomplete_class.c +++ b/ext/standard/incomplete_class.c @@ -60,9 +60,10 @@ static zval *incomplete_class_get_property(zval *object, zval *member, int type, } /* }}} */ -static void incomplete_class_write_property(zval *object, zval *member, zval *value, void **cache_slot) /* {{{ */ +static zval *incomplete_class_write_property(zval *object, zval *member, zval *value, void **cache_slot) /* {{{ */ { incomplete_class_message(object, E_NOTICE); + return value; } /* }}} */ diff --git a/ext/standard/proc_open.c b/ext/standard/proc_open.c index 612cdf0f88..8347ea7864 100644 --- a/ext/standard/proc_open.c +++ b/ext/standard/proc_open.c @@ -447,7 +447,7 @@ PHP_FUNCTION(proc_open) ZEND_PARSE_PARAMETERS_START(3, 6) Z_PARAM_STRING(command, command_len) Z_PARAM_ARRAY(descriptorspec) - Z_PARAM_ZVAL_DEREF(pipes) + Z_PARAM_ZVAL(pipes) Z_PARAM_OPTIONAL Z_PARAM_STRING_EX(cwd, cwd_len, 1, 0) Z_PARAM_ARRAY_EX(environment, 1, 0) @@ -862,6 +862,11 @@ PHP_FUNCTION(proc_open) #endif /* we forked/spawned and this is the parent */ + pipes = zend_try_array_init(pipes); + if (!pipes) { + goto exit_fail; + } + proc = (struct php_process_handle*)pemalloc(sizeof(struct php_process_handle), is_persistent); proc->is_persistent = is_persistent; proc->command = command; @@ -873,9 +878,6 @@ PHP_FUNCTION(proc_open) #endif proc->env = env; - zval_ptr_dtor(pipes); - array_init(pipes); - #if PHP_CAN_DO_PTS if (dev_ptmx >= 0) { close(dev_ptmx); diff --git a/ext/standard/scanf.c b/ext/standard/scanf.c index 37cce100ce..6c7544004b 100644 --- a/ext/standard/scanf.c +++ b/ext/standard/scanf.c @@ -739,9 +739,8 @@ literal: if (numVars && objIndex >= argCount) { break; } else if (numVars) { - current = Z_REFVAL(args[objIndex++]); - zval_ptr_dtor(current); - ZVAL_LONG(current, (zend_long)(string - baseString) ); + current = args + objIndex++; + ZEND_TRY_ASSIGN_LONG(current, (zend_long) (string - baseString)); } else { add_index_long(return_value, objIndex++, string - baseString); } @@ -858,9 +857,8 @@ literal: if (numVars && objIndex >= argCount) { break; } else if (numVars) { - current = Z_REFVAL(args[objIndex++]); - zval_ptr_dtor(current); - ZVAL_STRINGL(current, string, end-string); + current = args + objIndex++; + ZEND_TRY_ASSIGN_STRINGL(current, string, end - string); } else { add_index_stringl(return_value, objIndex++, string, end-string); } @@ -899,9 +897,8 @@ literal: if (numVars && objIndex >= argCount) { break; } else if (numVars) { - current = Z_REFVAL(args[objIndex++]); - zval_ptr_dtor(current); - ZVAL_STRINGL(current, string, end-string); + current = args + objIndex++; + ZEND_TRY_ASSIGN_STRINGL(current, string, end - string); } else { add_index_stringl(return_value, objIndex++, string, end-string); } @@ -1052,10 +1049,9 @@ addToInt: if (numVars && objIndex >= argCount) { break; } else if (numVars) { - /* change passed value type to string */ - current = Z_REFVAL(args[objIndex++]); - zval_ptr_dtor(current); - ZVAL_STRING(current, buf); + /* change passed value type to string */ + current = args + objIndex++; + ZEND_TRY_ASSIGN_STRING(current, buf); } else { add_index_string(return_value, objIndex++, buf); } @@ -1063,9 +1059,8 @@ addToInt: if (numVars && objIndex >= argCount) { break; } else if (numVars) { - current = Z_REFVAL(args[objIndex++]); - zval_ptr_dtor(current); - ZVAL_LONG(current, value); + current = args + objIndex++; + ZEND_TRY_ASSIGN_LONG(current, value); } else { add_index_long(return_value, objIndex++, value); } @@ -1168,9 +1163,8 @@ addToFloat: if (numVars && objIndex >= argCount) { break; } else if (numVars) { - current = Z_REFVAL(args[objIndex++]); - zval_ptr_dtor(current); - ZVAL_DOUBLE(current, dvalue); + current = args + objIndex++; + ZEND_TRY_ASSIGN_DOUBLE(current, dvalue); } else { add_index_double(return_value, objIndex++, dvalue ); } diff --git a/ext/standard/streamsfuncs.c b/ext/standard/streamsfuncs.c index 442091ad46..8f67b8b3fc 100644 --- a/ext/standard/streamsfuncs.c +++ b/ext/standard/streamsfuncs.c @@ -107,8 +107,8 @@ PHP_FUNCTION(stream_socket_client) ZEND_PARSE_PARAMETERS_START(1, 6) Z_PARAM_STR(host) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_DEREF(zerrno) - Z_PARAM_ZVAL_DEREF(zerrstr) + Z_PARAM_ZVAL(zerrno) + Z_PARAM_ZVAL(zerrstr) Z_PARAM_DOUBLE(timeout) Z_PARAM_LONG(flags) Z_PARAM_RESOURCE(zcontext) @@ -129,13 +129,11 @@ PHP_FUNCTION(stream_socket_client) tv.tv_sec = conv / 1000000; tv.tv_usec = conv % 1000000; #endif - if (zerrno) { - zval_ptr_dtor(zerrno); - ZVAL_LONG(zerrno, 0); + if (zerrno) { + ZEND_TRY_ASSIGN_LONG(zerrno, 0); } if (zerrstr) { - zval_ptr_dtor(zerrstr); - ZVAL_EMPTY_STRING(zerrstr); + ZEND_TRY_ASSIGN_EMPTY_STRING(zerrstr); } stream = php_stream_xport_create(ZSTR_VAL(host), ZSTR_LEN(host), REPORT_ERRORS, @@ -156,14 +154,12 @@ PHP_FUNCTION(stream_socket_client) efree(hashkey); } - if (stream == NULL) { + if (stream == NULL) { if (zerrno) { - zval_ptr_dtor(zerrno); - ZVAL_LONG(zerrno, err); + ZEND_TRY_ASSIGN_LONG(zerrno, err); } if (zerrstr && errstr) { - zval_ptr_dtor(zerrstr); - ZVAL_STR(zerrstr, errstr); + ZEND_TRY_ASSIGN_STR(zerrstr, errstr); } else if (errstr) { zend_string_release_ex(errstr, 0); } @@ -197,8 +193,8 @@ PHP_FUNCTION(stream_socket_server) ZEND_PARSE_PARAMETERS_START(1, 5) Z_PARAM_STRING(host, host_len) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_DEREF(zerrno) - Z_PARAM_ZVAL_DEREF(zerrstr) + Z_PARAM_ZVAL(zerrno) + Z_PARAM_ZVAL(zerrstr) Z_PARAM_LONG(flags) Z_PARAM_RESOURCE(zcontext) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); @@ -209,13 +205,11 @@ PHP_FUNCTION(stream_socket_server) GC_ADDREF(context->res); } - if (zerrno) { - zval_ptr_dtor(zerrno); - ZVAL_LONG(zerrno, 0); + if (zerrno) { + ZEND_TRY_ASSIGN_LONG(zerrno, 0); } if (zerrstr) { - zval_ptr_dtor(zerrstr); - ZVAL_EMPTY_STRING(zerrstr); + ZEND_TRY_ASSIGN_EMPTY_STRING(zerrstr); } stream = php_stream_xport_create(host, host_len, REPORT_ERRORS, @@ -226,14 +220,12 @@ PHP_FUNCTION(stream_socket_server) php_error_docref(NULL, E_WARNING, "unable to connect to %s (%s)", host, errstr == NULL ? "Unknown error" : ZSTR_VAL(errstr)); } - if (stream == NULL) { + if (stream == NULL) { if (zerrno) { - zval_ptr_dtor(zerrno); - ZVAL_LONG(zerrno, err); + ZEND_TRY_ASSIGN_LONG(zerrno, err); } if (zerrstr && errstr) { - zval_ptr_dtor(zerrstr); - ZVAL_STR(zerrstr, errstr); + ZEND_TRY_ASSIGN_STR(zerrstr, errstr); } else if (errstr) { zend_string_release_ex(errstr, 0); } @@ -265,7 +257,7 @@ PHP_FUNCTION(stream_socket_accept) Z_PARAM_RESOURCE(zstream) Z_PARAM_OPTIONAL Z_PARAM_DOUBLE(timeout) - Z_PARAM_ZVAL_DEREF(zpeername) + Z_PARAM_ZVAL(zpeername) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); php_stream_from_zval(stream, zstream); @@ -279,10 +271,6 @@ PHP_FUNCTION(stream_socket_accept) tv.tv_sec = conv / 1000000; tv.tv_usec = conv % 1000000; #endif - if (zpeername) { - zval_ptr_dtor(zpeername); - ZVAL_NULL(zpeername); - } if (0 == php_stream_xport_accept(stream, &clistream, zpeername ? &peername : NULL, @@ -291,7 +279,7 @@ PHP_FUNCTION(stream_socket_accept) ) && clistream) { if (peername) { - ZVAL_STR(zpeername, peername); + ZEND_TRY_ASSIGN_STR(zpeername, peername); } php_stream_to_zval(clistream, return_value); } else { @@ -387,14 +375,13 @@ PHP_FUNCTION(stream_socket_recvfrom) Z_PARAM_LONG(to_read) Z_PARAM_OPTIONAL Z_PARAM_LONG(flags) - Z_PARAM_ZVAL_DEREF(zremote) + Z_PARAM_ZVAL(zremote) ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); php_stream_from_zval(stream, zstream); if (zremote) { - zval_ptr_dtor(zremote); - ZVAL_NULL(zremote); + ZEND_TRY_ASSIGN_NULL(zremote); } if (to_read <= 0) { @@ -410,7 +397,7 @@ PHP_FUNCTION(stream_socket_recvfrom) if (recvd >= 0) { if (zremote && remote_addr) { - ZVAL_STR(zremote, remote_addr); + ZEND_TRY_ASSIGN_STR(zremote, remote_addr); } ZSTR_VAL(read_buf)[recvd] = '\0'; ZSTR_LEN(read_buf) = recvd; diff --git a/ext/standard/string.c b/ext/standard/string.c index 26144eb166..3839512ecc 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -3655,16 +3655,12 @@ PHP_FUNCTION(similar_text) Z_PARAM_STR(t1) Z_PARAM_STR(t2) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_DEREF(percent) + Z_PARAM_ZVAL(percent) ZEND_PARSE_PARAMETERS_END(); - if (ac > 2) { - convert_to_double_ex(percent); - } - if (ZSTR_LEN(t1) + ZSTR_LEN(t2) == 0) { if (ac > 2) { - Z_DVAL_P(percent) = 0; + ZEND_TRY_ASSIGN_DOUBLE(percent, 0); } RETURN_LONG(0); @@ -3673,7 +3669,7 @@ PHP_FUNCTION(similar_text) sim = php_similar_char(ZSTR_VAL(t1), ZSTR_LEN(t1), ZSTR_VAL(t2), ZSTR_LEN(t2)); if (ac > 2) { - Z_DVAL_P(percent) = sim * 200.0 / (ZSTR_LEN(t1) + ZSTR_LEN(t2)); + ZEND_TRY_ASSIGN_DOUBLE(percent, sim * 200.0 / (ZSTR_LEN(t1) + ZSTR_LEN(t2))); } RETURN_LONG(sim); @@ -4442,7 +4438,7 @@ static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensit Z_PARAM_ZVAL(replace) Z_PARAM_ZVAL(subject) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_DEREF(zcount) + Z_PARAM_ZVAL(zcount) ZEND_PARSE_PARAMETERS_END(); /* Make sure we're dealing with strings and do the replacement. */ @@ -4479,8 +4475,7 @@ static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensit count = php_str_replace_in_subject(search, replace, subject, return_value, case_sensitivity); } if (argc > 3) { - zval_ptr_dtor(zcount); - ZVAL_LONG(zcount, count); + ZEND_TRY_ASSIGN_LONG(zcount, count); } } /* }}} */ @@ -4906,7 +4901,7 @@ PHP_FUNCTION(parse_str) ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_STRING(arg, arglen) Z_PARAM_OPTIONAL - Z_PARAM_ZVAL_DEREF(arrayArg) + Z_PARAM_ZVAL(arrayArg) ZEND_PARSE_PARAMETERS_END(); res = estrndup(arg, arglen); @@ -4928,9 +4923,11 @@ PHP_FUNCTION(parse_str) zend_throw_error(NULL, "Cannot re-assign $this"); } } else { - /* Clear out the array that was passed in. */ - zval_ptr_dtor(arrayArg); - array_init(arrayArg); + arrayArg = zend_try_array_init(arrayArg); + if (!arrayArg) { + return; + } + sapi_module.treat_data(PARSE_STRING, res, arrayArg); } } diff --git a/ext/standard/tests/array/extract_typed_ref.phpt b/ext/standard/tests/array/extract_typed_ref.phpt new file mode 100644 index 0000000000..8b697d5ccb --- /dev/null +++ b/ext/standard/tests/array/extract_typed_ref.phpt @@ -0,0 +1,23 @@ +--TEST-- +extract() into typed references must respect their type +--FILE-- +<?php + +class Test { + public int $i = 0; + public string $s = ""; +} + +$test = new Test; +$i =& $test->i; +$s =& $test->s; +try { + extract(['i' => 'foo', 's' => 42]); +} catch (TypeError $e) { echo $e->getMessage(), "\n"; } +var_dump($test->i, $test->s); + +?> +--EXPECT-- +Cannot assign string to reference held by property Test::$i of type int +int(0) +string(0) "" diff --git a/ext/standard/tests/general_functions/settype_typed_property.phpt b/ext/standard/tests/general_functions/settype_typed_property.phpt new file mode 100644 index 0000000000..a206a4ba41 --- /dev/null +++ b/ext/standard/tests/general_functions/settype_typed_property.phpt @@ -0,0 +1,28 @@ +--TEST-- +Using settype() on a typed property +--FILE-- +<?php + +class Test { + public int $x; +} + +$test = new Test; +$test->x = 42; +settype($test->x, 'string'); +// Same as $test->x = (string) $test->x. +// Leaves value unchanged due to coercion +var_dump($test->x); + +try { + settype($test->x, 'array'); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +var_dump($test->x); + +?> +--EXPECT-- +int(42) +Cannot assign array to reference held by property Test::$x of type int +int(42) diff --git a/ext/standard/tests/serialize/typed_property_refs.phpt b/ext/standard/tests/serialize/typed_property_refs.phpt new file mode 100644 index 0000000000..9475e8a783 --- /dev/null +++ b/ext/standard/tests/serialize/typed_property_refs.phpt @@ -0,0 +1,73 @@ +--TEST-- +unserialize with references to typed properties shall skip the references or fail +--FILE-- +<?php + +class A { + public int $a; + public $b; +} + +class B { + public $a; + public int $b; +} + +class C { + public int $a; + public string $b; +} + +class D { + public int $a; + public float $b; +} + +var_dump(unserialize('O:1:"A":2:{s:1:"a";i:1;s:1:"b";R:2;}')); +var_dump(unserialize('O:1:"B":2:{s:1:"a";i:1;s:1:"b";R:2;}')); + +try { + var_dump(unserialize('O:1:"A":2:{s:1:"a";N;s:1:"b";R:2;}')); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump(unserialize('O:1:"B":2:{s:1:"a";N;s:1:"b";R:2;}')); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump(unserialize('O:1:"C":2:{s:1:"a";i:1;s:1:"b";R:2;}')); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump(unserialize('O:1:"C":2:{s:1:"b";s:1:"x";s:1:"a";R:2;}')); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +try { + var_dump(unserialize('O:1:"D":2:{s:1:"a";i:1;s:1:"b";R:2;}')); +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +object(A)#1 (2) { + ["a"]=> + &int(1) + ["b"]=> + &int(1) +} +object(B)#1 (2) { + ["a"]=> + &int(1) + ["b"]=> + &int(1) +} +Typed property A::$a must be int, null used +Typed property B::$b must be int, null used +Typed property C::$b must be string, int used +Typed property C::$a must be int, string used +Reference with value of type int held by property D::$a of type int is not compatible with property D::$b of type float diff --git a/ext/standard/type.c b/ext/standard/type.c index 1a26e0eaa3..bc1233e35d 100644 --- a/ext/standard/type.c +++ b/ext/standard/type.c @@ -45,40 +45,46 @@ PHP_FUNCTION(settype) { zval *var; char *type; - size_t type_len = 0; + size_t type_len; + zval tmp; ZEND_PARSE_PARAMETERS_START(2, 2) - Z_PARAM_ZVAL_DEREF(var) + Z_PARAM_ZVAL(var) Z_PARAM_STRING(type, type_len) ZEND_PARSE_PARAMETERS_END(); + ZVAL_COPY(&tmp, var); if (!strcasecmp(type, "integer")) { - convert_to_long(var); + convert_to_long(&tmp); } else if (!strcasecmp(type, "int")) { - convert_to_long(var); + convert_to_long(&tmp); } else if (!strcasecmp(type, "float")) { - convert_to_double(var); + convert_to_double(&tmp); } else if (!strcasecmp(type, "double")) { /* deprecated */ - convert_to_double(var); + convert_to_double(&tmp); } else if (!strcasecmp(type, "string")) { - convert_to_string(var); + convert_to_string(&tmp); } else if (!strcasecmp(type, "array")) { - convert_to_array(var); + convert_to_array(&tmp); } else if (!strcasecmp(type, "object")) { - convert_to_object(var); + convert_to_object(&tmp); } else if (!strcasecmp(type, "bool")) { - convert_to_boolean(var); + convert_to_boolean(&tmp); } else if (!strcasecmp(type, "boolean")) { - convert_to_boolean(var); + convert_to_boolean(&tmp); } else if (!strcasecmp(type, "null")) { - convert_to_null(var); + convert_to_null(&tmp); } else if (!strcasecmp(type, "resource")) { + zval_ptr_dtor(&tmp); php_error_docref(NULL, E_WARNING, "Cannot convert to resource type"); RETURN_FALSE; } else { + zval_ptr_dtor(&tmp); php_error_docref(NULL, E_WARNING, "Invalid type"); RETURN_FALSE; } + + zend_try_assign(var, &tmp); RETVAL_TRUE; } /* }}} */ @@ -357,7 +363,7 @@ PHP_FUNCTION(is_callable) Z_PARAM_ZVAL(var) Z_PARAM_OPTIONAL Z_PARAM_BOOL(syntax_only) - Z_PARAM_ZVAL_DEREF(callable_name) + Z_PARAM_ZVAL(callable_name) ZEND_PARSE_PARAMETERS_END(); if (syntax_only) { @@ -365,8 +371,7 @@ PHP_FUNCTION(is_callable) } if (ZEND_NUM_ARGS() > 2) { retval = zend_is_callable_ex(var, NULL, check_flags, &name, NULL, &error); - zval_ptr_dtor(callable_name); - ZVAL_STR(callable_name, name); + ZEND_TRY_ASSIGN_STR(callable_name, name); } else { retval = zend_is_callable_ex(var, NULL, check_flags, NULL, NULL, &error); } diff --git a/ext/standard/var.c b/ext/standard/var.c index 108bafca8b..27ec44f991 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -51,7 +51,7 @@ static void php_array_element_dump(zval *zv, zend_ulong index, zend_string *key, } /* }}} */ -static void php_object_property_dump(zval *zv, zend_ulong index, zend_string *key, int level) /* {{{ */ +static void php_object_property_dump(zend_property_info *prop_info, zval *zv, zend_ulong index, zend_string *key, int level) /* {{{ */ { const char *prop_name, *class_name; @@ -74,7 +74,18 @@ static void php_object_property_dump(zval *zv, zend_ulong index, zend_string *ke } ZEND_PUTS("]=>\n"); } - php_var_dump(zv, level + 2); + + if (Z_TYPE_P(zv) == IS_UNDEF) { + ZEND_ASSERT(prop_info->type); + php_printf("%*cuninitialized(%s%s)\n", + level + 1, ' ', + ZEND_TYPE_ALLOW_NULL(prop_info->type) ? "?" : "", + ZEND_TYPE_IS_CLASS(prop_info->type) ? + ZSTR_VAL(ZEND_TYPE_IS_CE(prop_info->type) ? ZEND_TYPE_CE(prop_info->type)->name : ZEND_TYPE_NAME(prop_info->type)) : + zend_get_type_by_const(ZEND_TYPE_CODE(prop_info->type))); + } else { + php_var_dump(zv, level + 2); + } } /* }}} */ @@ -154,8 +165,19 @@ again: zend_string *key; zval *val; - ZEND_HASH_FOREACH_KEY_VAL_IND(myht, num, key, val) { - php_object_property_dump(val, num, key, level); + ZEND_HASH_FOREACH_KEY_VAL(myht, num, key, val) { + zend_property_info *prop_info = NULL; + + if (Z_TYPE_P(val) == IS_INDIRECT) { + val = Z_INDIRECT_P(val); + if (key) { + prop_info = zend_get_typed_property_info_for_slot(Z_OBJ_P(struc), val); + } + } + + if (!Z_ISUNDEF_P(val) || prop_info) { + php_object_property_dump(prop_info, val, num, key, level); + } } ZEND_HASH_FOREACH_END(); zend_release_properties(myht); } @@ -216,7 +238,7 @@ static void zval_array_element_dump(zval *zv, zend_ulong index, zend_string *key } /* }}} */ -static void zval_object_property_dump(zval *zv, zend_ulong index, zend_string *key, int level) /* {{{ */ +static void zval_object_property_dump(zend_property_info *prop_info, zval *zv, zend_ulong index, zend_string *key, int level) /* {{{ */ { const char *prop_name, *class_name; @@ -237,7 +259,17 @@ static void zval_object_property_dump(zval *zv, zend_ulong index, zend_string *k } ZEND_PUTS("]=>\n"); } - php_debug_zval_dump(zv, level + 2); + if (prop_info && Z_TYPE_P(zv) == IS_UNDEF) { + ZEND_ASSERT(prop_info->type); + php_printf("%*cuninitialized(%s%s)\n", + level + 1, ' ', + ZEND_TYPE_ALLOW_NULL(prop_info->type) ? "?" : "", + ZEND_TYPE_IS_CLASS(prop_info->type) ? + ZSTR_VAL(ZEND_TYPE_IS_CE(prop_info->type) ? ZEND_TYPE_CE(prop_info->type)->name : ZEND_TYPE_NAME(prop_info->type)) : + zend_get_type_by_const(ZEND_TYPE_CODE(prop_info->type))); + } else { + php_debug_zval_dump(zv, level + 2); + } } /* }}} */ @@ -313,8 +345,19 @@ again: php_printf("%sobject(%s)#%d (%d) refcount(%u){\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0, Z_REFCOUNT_P(struc)); zend_string_release_ex(class_name, 0); if (myht) { - ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) { - zval_object_property_dump(val, index, key, level); + ZEND_HASH_FOREACH_KEY_VAL(myht, index, key, val) { + zend_property_info *prop_info = NULL; + + if (Z_TYPE_P(val) == IS_INDIRECT) { + val = Z_INDIRECT_P(val); + if (key) { + prop_info = zend_get_typed_property_info_for_slot(Z_OBJ_P(struc), val); + } + } + + if (!Z_ISUNDEF_P(val) || prop_info) { + zval_object_property_dump(prop_info, val, index, key, level); + } } ZEND_HASH_FOREACH_END(); GC_UNPROTECT_RECURSION(myht); zend_release_properties(myht); diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index d07d657719..8dad71450e 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -46,6 +46,7 @@ struct php_unserialize_data { var_dtor_entries *first_dtor; var_dtor_entries *last_dtor; HashTable *allowed_classes; + HashTable *ref_props; var_entries entries; }; @@ -57,6 +58,7 @@ PHPAPI php_unserialize_data_t php_var_unserialize_init() { d->last = &d->entries; d->first_dtor = d->last_dtor = NULL; d->allowed_classes = NULL; + d->ref_props = NULL; d->entries.used_slots = 0; d->entries.next = NULL; if (!BG(serialize_lock)) { @@ -239,6 +241,11 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) } zval_ptr_dtor_nogc(&wakeup_name); + + if ((*var_hashx)->ref_props) { + zend_hash_destroy((*var_hashx)->ref_props); + FREE_HASHTABLE((*var_hashx)->ref_props); + } } /* }}} */ @@ -395,11 +402,12 @@ static inline size_t parse_uiv(const unsigned char *p) static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER, int as_key); -static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, int objprops) +static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, zend_object *obj) { while (elements-- > 0) { zval key, *data, d, *old_data; zend_ulong idx; + zend_property_info *info = NULL; ZVAL_UNDEF(&key); @@ -411,7 +419,7 @@ static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTab data = NULL; ZVAL_UNDEF(&d); - if (!objprops) { + if (!obj) { if (Z_TYPE(key) == IS_LONG) { idx = Z_LVAL(key); numeric_key: @@ -440,8 +448,7 @@ numeric_key: } else { if (EXPECTED(Z_TYPE(key) == IS_STRING)) { string_key: - if (Z_TYPE_P(rval) == IS_OBJECT - && zend_hash_num_elements(&Z_OBJCE_P(rval)->properties_info) > 0) { + if (obj && zend_hash_num_elements(&obj->ce->properties_info) > 0) { zend_property_info *existing_propinfo; zend_string *new_key; const char *unmangled_class = NULL; @@ -456,8 +463,8 @@ string_key: unmangled = zend_string_init(unmangled_prop, unmangled_prop_len, 0); - existing_propinfo = zend_hash_find_ptr(&Z_OBJCE_P(rval)->properties_info, unmangled); - if ((unmangled_class == NULL || !strcmp(unmangled_class, "*") || !strcasecmp(unmangled_class, ZSTR_VAL(Z_OBJCE_P(rval)->name))) + existing_propinfo = zend_hash_find_ptr(&obj->ce->properties_info, unmangled); + if ((unmangled_class == NULL || !strcmp(unmangled_class, "*") || !strcasecmp(unmangled_class, ZSTR_VAL(obj->ce->name))) && (existing_propinfo != NULL) && (existing_propinfo->flags & ZEND_ACC_PPP_MASK)) { if (existing_propinfo->flags & ZEND_ACC_PROTECTED) { @@ -491,9 +498,24 @@ string_key: if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) { if (Z_TYPE_P(old_data) == IS_INDIRECT) { old_data = Z_INDIRECT_P(old_data); + info = zend_get_typed_property_info_for_slot(obj, old_data); + var_push_dtor(var_hash, old_data); + data = zend_hash_update_ind(ht, Z_STR(key), &d); + + if (UNEXPECTED(info)) { + /* Remember to which property this slot belongs, so we can add a + * type source if it is turned into a reference lateron. */ + if (!(*var_hash)->ref_props) { + (*var_hash)->ref_props = emalloc(sizeof(HashTable)); + zend_hash_init((*var_hash)->ref_props, 8, NULL, NULL, 0); + } + zend_hash_index_update_ptr( + (*var_hash)->ref_props, (zend_uintptr_t) data, info); + } + } else { + var_push_dtor(var_hash, old_data); + data = zend_hash_update_ind(ht, Z_STR(key), &d); } - var_push_dtor(var_hash, old_data); - data = zend_hash_update_ind(ht, Z_STR(key), &d); } else { data = zend_hash_add_new(ht, Z_STR(key), &d); } @@ -512,6 +534,18 @@ string_key: return 0; } + if (UNEXPECTED(info)) { + if (!zend_verify_prop_assignable_by_ref(info, data, /* strict */ 1)) { + zval_ptr_dtor(data); + ZVAL_UNDEF(data); + zval_dtor(&key); + return 0; + } + if (Z_ISREF_P(data)) { + ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), info); + } + } + if (BG(unserialize).level > 1) { var_push_dtor(var_hash, data); } @@ -613,7 +647,7 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, zend_long elements) } zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, HT_FLAGS(ht) & HASH_FLAG_PACKED); - if (!process_nested_data(UNSERIALIZE_PASSTHRU, ht, elements, 1)) { + if (!process_nested_data(UNSERIALIZE_PASSTHRU, ht, elements, Z_OBJ_P(rval))) { if (has_wakeup) { ZVAL_DEREF(rval); GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED); @@ -697,13 +731,19 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER, int as_key) return 0; } - if (Z_ISREF_P(rval_ref)) { - ZVAL_COPY(rval, rval_ref); - } else { + if (!Z_ISREF_P(rval_ref)) { + zend_property_info *info = NULL; + if ((*var_hash)->ref_props) { + info = zend_hash_index_find_ptr((*var_hash)->ref_props, (zend_uintptr_t) rval_ref); + } ZVAL_NEW_REF(rval_ref, rval_ref); - ZVAL_COPY(rval, rval_ref); + if (info) { + ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(rval_ref), info); + } } + ZVAL_COPY(rval, rval_ref); + return 1; } @@ -901,7 +941,7 @@ use_double: * prohibit "r:" references to non-objects, as we only generate them for objects. */ HT_ALLOW_COW_VIOLATION(Z_ARRVAL_P(rval)); - if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements, 0)) { + if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements, NULL)) { return 0; } diff --git a/ext/sysvmsg/sysvmsg.c b/ext/sysvmsg/sysvmsg.c index a00b73ee8a..0f7726f334 100644 --- a/ext/sysvmsg/sysvmsg.c +++ b/ext/sysvmsg/sysvmsg.c @@ -318,7 +318,7 @@ PHP_FUNCTION(msg_remove_queue) } /* }}} */ -/* {{{ proto mixed msg_receive(resource queue, int desiredmsgtype, int &msgtype, int maxsize, mixed message [, bool unserialize=true [, int flags=0 [, int errorcode]]]) +/* {{{ proto mixed msg_receive(resource queue, int desiredmsgtype, int &msgtype, int maxsize, mixed &message [, bool unserialize=true [, int flags=0 [, int &errorcode]]]) Send a message of type msgtype (must be > 0) to a message queue */ PHP_FUNCTION(msg_receive) { @@ -332,7 +332,7 @@ PHP_FUNCTION(msg_receive) RETVAL_FALSE; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlz/lz/|blz/", + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlzlz|blz", &queue, &desiredmsgtype, &out_msgtype, &maxsize, &out_message, &do_unserialize, &flags, &zerrcode) == FAILURE) { return; @@ -368,19 +368,12 @@ PHP_FUNCTION(msg_receive) result = msgrcv(mq->id, messagebuffer, maxsize, desiredmsgtype, realflags); - zval_ptr_dtor(out_msgtype); - zval_ptr_dtor(out_message); - ZVAL_LONG(out_msgtype, 0); - ZVAL_FALSE(out_message); - - if (zerrcode) { - zval_ptr_dtor(zerrcode); - ZVAL_LONG(zerrcode, 0); - } - if (result >= 0) { /* got it! */ - ZVAL_LONG(out_msgtype, messagebuffer->mtype); + ZEND_TRY_ASSIGN_LONG(out_msgtype, messagebuffer->mtype); + if (zerrcode) { + ZEND_TRY_ASSIGN_LONG(zerrcode, 0); + } RETVAL_TRUE; if (do_unserialize) { @@ -391,16 +384,21 @@ PHP_FUNCTION(msg_receive) PHP_VAR_UNSERIALIZE_INIT(var_hash); if (!php_var_unserialize(&tmp, &p, p + result, &var_hash)) { php_error_docref(NULL, E_WARNING, "message corrupted"); + ZEND_TRY_ASSIGN_FALSE(out_message); RETVAL_FALSE; } else { - ZVAL_COPY_VALUE(out_message, &tmp); + ZEND_TRY_ASSIGN_VALUE(out_message, &tmp); } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); } else { - ZVAL_STRINGL(out_message, messagebuffer->mtext, result); + ZEND_TRY_ASSIGN_STRINGL(out_message, messagebuffer->mtext, result); + } + } else { + ZEND_TRY_ASSIGN_LONG(out_msgtype, 0); + ZEND_TRY_ASSIGN_FALSE(out_message); + if (zerrcode) { + ZEND_TRY_ASSIGN_LONG(zerrcode, errno); } - } else if (zerrcode) { - ZVAL_LONG(zerrcode, errno); } efree(messagebuffer); } @@ -420,7 +418,7 @@ PHP_FUNCTION(msg_send) RETVAL_FALSE; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlz|bbz/", + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlz|bbz", &queue, &msgtype, &message, &do_serialize, &blocking, &zerror) == FAILURE) { return; } @@ -486,8 +484,7 @@ PHP_FUNCTION(msg_send) if (result == -1) { php_error_docref(NULL, E_WARNING, "msgsnd failed: %s", strerror(errno)); if (zerror) { - zval_ptr_dtor(zerror); - ZVAL_LONG(zerror, errno); + ZEND_TRY_ASSIGN_LONG(zerror, errno); } } else { RETVAL_TRUE; diff --git a/ext/xml/xml.c b/ext/xml/xml.c index 9868c5e3c4..d5f2a51312 100644 --- a/ext/xml/xml.c +++ b/ext/xml/xml.c @@ -1434,21 +1434,25 @@ PHP_FUNCTION(xml_parse_into_struct) size_t data_len; int ret; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsz/|z/", &pind, &data, &data_len, &xdata, &info) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "rsz|z", &pind, &data, &data_len, &xdata, &info) == FAILURE) { return; } if (info) { - zval_ptr_dtor(info); - array_init(info); + info = zend_try_array_init(info); + if (!info) { + return; + } } if ((parser = (xml_parser *)zend_fetch_resource(Z_RES_P(pind), "XML Parser", le_xml_parser)) == NULL) { RETURN_FALSE; } - zval_ptr_dtor(xdata); - array_init(xdata); + xdata = zend_try_array_init(xdata); + if (!xdata) { + return; + } ZVAL_COPY_VALUE(&parser->data, xdata); diff --git a/ext/xmlreader/php_xmlreader.c b/ext/xmlreader/php_xmlreader.c index ba5c854aee..2710be98c6 100644 --- a/ext/xmlreader/php_xmlreader.c +++ b/ext/xmlreader/php_xmlreader.c @@ -181,7 +181,7 @@ zval *xmlreader_read_property(zval *object, zval *member, int type, void **cache /* }}} */ /* {{{ xmlreader_write_property */ -void xmlreader_write_property(zval *object, zval *member, zval *value, void **cache_slot) +zval *xmlreader_write_property(zval *object, zval *member, zval *value, void **cache_slot) { xmlreader_object *obj; zval tmp_member; @@ -200,12 +200,14 @@ void xmlreader_write_property(zval *object, zval *member, zval *value, void **ca if (hnd != NULL) { php_error_docref(NULL, E_WARNING, "Cannot write to read-only property"); } else { - zend_std_write_property(object, member, value, cache_slot); + value = zend_std_write_property(object, member, value, cache_slot); } if (member == &tmp_member) { zval_ptr_dtor_str(&tmp_member); } + + return value; } /* }}} */ diff --git a/ext/xmlrpc/xmlrpc-epi-php.c b/ext/xmlrpc/xmlrpc-epi-php.c index 737a3f84a5..937f7b1b0f 100644 --- a/ext/xmlrpc/xmlrpc-epi-php.c +++ b/ext/xmlrpc/xmlrpc-epi-php.c @@ -764,11 +764,9 @@ void decode_request_worker(char *xml_in, int xml_in_len, char *encoding_in, zval if (method_name_out) { method_name = XMLRPC_RequestGetMethodName(response); if (method_name) { - zval_ptr_dtor(method_name_out); - ZVAL_STRING(method_name_out, method_name); + ZEND_TRY_ASSIGN_STRING(method_name_out, method_name); } else { - zval_ptr_dtor(retval); - ZVAL_NULL(retval); + ZEND_TRY_ASSIGN_NULL(retval); } } } @@ -787,7 +785,7 @@ PHP_FUNCTION(xmlrpc_decode_request) zval *method; size_t xml_len, encoding_len = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/|s", &xml, &xml_len, &method, &encoding, &encoding_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz|s", &xml, &xml_len, &method, &encoding, &encoding_len) == FAILURE) { return; } @@ -1389,15 +1387,19 @@ PHP_FUNCTION(xmlrpc_set_type) size_t type_len; XMLRPC_VALUE_TYPE vtype; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z/s", &arg, &type, &type_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zs", &arg, &type, &type_len) == FAILURE) { return; } vtype = xmlrpc_str_as_type(type); if (vtype != xmlrpc_none) { - if (set_zval_xmlrpc_type(arg, vtype) == SUCCESS) { + zval tmp; + ZVAL_COPY(&tmp, Z_REFVAL_P(arg)); + if (set_zval_xmlrpc_type(&tmp, vtype) == SUCCESS) { + ZEND_TRY_ASSIGN_VALUE(arg, &tmp); RETURN_TRUE; } + Z_TRY_DELREF(tmp); } else { zend_error(E_WARNING,"invalid type '%s' passed to xmlrpc_set_type()", type); } diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 31455daab8..8d533b7907 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -137,6 +137,7 @@ ZEND_FUNCTION(zend_leak_variable) static zend_object *zend_test_class_new(zend_class_entry *class_type) /* {{{ */ { zend_object *obj = zend_objects_new(class_type); + object_properties_init(obj, class_type); obj->handlers = &zend_test_class_handlers; return obj; } @@ -203,6 +204,36 @@ PHP_MINIT_FUNCTION(zend_test) zend_declare_property_null(zend_test_class, "_StaticProp", sizeof("_StaticProp") - 1, ZEND_ACC_STATIC); + { + zend_string *name = zend_string_init("intProp", sizeof("intProp") - 1, 1); + zval val; + ZVAL_LONG(&val, 123); + zend_declare_typed_property( + zend_test_class, name, &val, ZEND_ACC_PUBLIC, NULL, ZEND_TYPE_ENCODE(IS_LONG, 0)); + zend_string_release(name); + } + + { + zend_string *name = zend_string_init("classProp", sizeof("classProp") - 1, 1); + zend_string *class_name = zend_string_init("stdClass", sizeof("stdClass") - 1, 1); + zval val; + ZVAL_NULL(&val); + zend_declare_typed_property( + zend_test_class, name, &val, ZEND_ACC_PUBLIC, NULL, + ZEND_TYPE_ENCODE_CLASS(class_name, 1)); + zend_string_release(name); + } + + { + zend_string *name = zend_string_init("staticIntProp", sizeof("staticIntProp") - 1, 1); + zval val; + ZVAL_LONG(&val, 123); + zend_declare_typed_property( + zend_test_class, name, &val, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC, NULL, + ZEND_TYPE_ENCODE(IS_LONG, 0)); + zend_string_release(name); + } + INIT_CLASS_ENTRY(class_entry, "_ZendTestChildClass", NULL); zend_test_child_class = zend_register_internal_class_ex(&class_entry, zend_test_class); diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 5aa17fb669..dbc6c1603e 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -2133,7 +2133,7 @@ static ZIPARCHIVE_METHOD(getExternalAttributesName) ZIP_FROM_OBJECT(intern, self); - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz/z/|l", + if (zend_parse_parameters(ZEND_NUM_ARGS(), "szz|l", &name, &name_len, &z_opsys, &z_attr, &flags) == FAILURE) { return; } @@ -2150,10 +2150,8 @@ static ZIPARCHIVE_METHOD(getExternalAttributesName) (zip_flags_t)flags, &opsys, &attr) < 0) { RETURN_FALSE; } - zval_ptr_dtor(z_opsys); - ZVAL_LONG(z_opsys, opsys); - zval_ptr_dtor(z_attr); - ZVAL_LONG(z_attr, attr); + ZEND_TRY_ASSIGN_LONG(z_opsys, opsys); + ZEND_TRY_ASSIGN_LONG(z_attr, attr); RETURN_TRUE; } /* }}} */ @@ -2171,7 +2169,7 @@ static ZIPARCHIVE_METHOD(getExternalAttributesIndex) ZIP_FROM_OBJECT(intern, self); - if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz/z/|l", + if (zend_parse_parameters(ZEND_NUM_ARGS(), "lzz|l", &index, &z_opsys, &z_attr, &flags) == FAILURE) { return; } @@ -2181,10 +2179,8 @@ static ZIPARCHIVE_METHOD(getExternalAttributesIndex) (zip_flags_t)flags, &opsys, &attr) < 0) { RETURN_FALSE; } - zval_ptr_dtor(z_opsys); - ZVAL_LONG(z_opsys, opsys); - zval_ptr_dtor(z_attr); - ZVAL_LONG(z_attr, attr); + ZEND_TRY_ASSIGN_LONG(z_opsys, opsys); + ZEND_TRY_ASSIGN_LONG(z_attr, attr); RETURN_TRUE; } /* }}} */ |