summaryrefslogtreecommitdiff
path: root/ext/standard
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-01-07 12:28:51 +0100
committerNikita Popov <nikita.ppv@gmail.com>2019-01-11 15:49:06 +0100
commite219ec144ef6682b71e135fd18654ee1bb4676b4 (patch)
treee4a3ae2b619cdc9fe50ee8e1fa5adb99d804dddf /ext/standard
parentfe8fdfa3bd588d80ce60f6b3848058239e0a760f (diff)
downloadphp-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.c48
-rw-r--r--ext/standard/basic_functions.c7
-rw-r--r--ext/standard/dns.c32
-rw-r--r--ext/standard/dns_win32.c29
-rw-r--r--ext/standard/exec.c22
-rw-r--r--ext/standard/file.c7
-rw-r--r--ext/standard/fsock.c36
-rw-r--r--ext/standard/head.c12
-rw-r--r--ext/standard/image.c8
-rw-r--r--ext/standard/incomplete_class.c3
-rw-r--r--ext/standard/proc_open.c10
-rw-r--r--ext/standard/scanf.c32
-rw-r--r--ext/standard/streamsfuncs.c55
-rw-r--r--ext/standard/string.c25
-rw-r--r--ext/standard/tests/array/extract_typed_ref.phpt23
-rw-r--r--ext/standard/tests/general_functions/settype_typed_property.phpt28
-rw-r--r--ext/standard/tests/serialize/typed_property_refs.phpt73
-rw-r--r--ext/standard/type.c35
-rw-r--r--ext/standard/var.c59
-rw-r--r--ext/standard/var_unserializer.re68
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;
}