diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-01-07 12:28:51 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-01-11 15:49:06 +0100 |
commit | e219ec144ef6682b71e135fd18654ee1bb4676b4 (patch) | |
tree | e4a3ae2b619cdc9fe50ee8e1fa5adb99d804dddf /ext/standard | |
parent | fe8fdfa3bd588d80ce60f6b3848058239e0a760f (diff) | |
download | php-git-e219ec144ef6682b71e135fd18654ee1bb4676b4.tar.gz |
Implement typed properties
RFC: https://wiki.php.net/rfc/typed_properties_v2
This is a squash of PR #3734, which is a squash of PR #3313.
Co-authored-by: Bob Weinand <bobwei9@hotmail.com>
Co-authored-by: Joe Watkins <krakjoe@php.net>
Co-authored-by: Dmitry Stogov <dmitry@zend.com>
Diffstat (limited to 'ext/standard')
-rw-r--r-- | ext/standard/array.c | 48 | ||||
-rw-r--r-- | ext/standard/basic_functions.c | 7 | ||||
-rw-r--r-- | ext/standard/dns.c | 32 | ||||
-rw-r--r-- | ext/standard/dns_win32.c | 29 | ||||
-rw-r--r-- | ext/standard/exec.c | 22 | ||||
-rw-r--r-- | ext/standard/file.c | 7 | ||||
-rw-r--r-- | ext/standard/fsock.c | 36 | ||||
-rw-r--r-- | ext/standard/head.c | 12 | ||||
-rw-r--r-- | ext/standard/image.c | 8 | ||||
-rw-r--r-- | ext/standard/incomplete_class.c | 3 | ||||
-rw-r--r-- | ext/standard/proc_open.c | 10 | ||||
-rw-r--r-- | ext/standard/scanf.c | 32 | ||||
-rw-r--r-- | ext/standard/streamsfuncs.c | 55 | ||||
-rw-r--r-- | ext/standard/string.c | 25 | ||||
-rw-r--r-- | ext/standard/tests/array/extract_typed_ref.phpt | 23 | ||||
-rw-r--r-- | ext/standard/tests/general_functions/settype_typed_property.phpt | 28 | ||||
-rw-r--r-- | ext/standard/tests/serialize/typed_property_refs.phpt | 73 | ||||
-rw-r--r-- | ext/standard/type.c | 35 | ||||
-rw-r--r-- | ext/standard/var.c | 59 | ||||
-rw-r--r-- | ext/standard/var_unserializer.re | 68 |
20 files changed, 415 insertions, 197 deletions
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; } |