summaryrefslogtreecommitdiff
path: root/ext/standard/var_unserializer.re
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2017-01-05 00:28:21 +0100
committerNikita Popov <nikic@php.net>2017-01-05 00:28:21 +0100
commit8d8e94936959eb2466ec77d1e537427f92650363 (patch)
treeff3b27265e33dbf052fda0141ded85837f7d84c7 /ext/standard/var_unserializer.re
parent7b436b0c48b7fb089aa6d97075b72f7a9eed4a98 (diff)
parentb47c49d7a00bc34d7e0f3d72732f66e904da6fa7 (diff)
downloadphp-git-8d8e94936959eb2466ec77d1e537427f92650363.tar.gz
Merge branch 'PHP-7.0' into PHP-7.1
Diffstat (limited to 'ext/standard/var_unserializer.re')
-rw-r--r--ext/standard/var_unserializer.re53
1 files changed, 38 insertions, 15 deletions
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index f5a64a8f2d..c9272e92be 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -69,6 +69,9 @@ PHPAPI void php_var_unserialize_set_allowed_classes(php_unserialize_data_t d, Ha
#define VAR_ENTRIES_MAX 1024
#define VAR_ENTRIES_DBG 0
+/* VAR_FLAG used in var_dtor entries to signify an entry on which __wakeup should be called */
+#define VAR_WAKEUP_FLAG 1
+
typedef struct {
zval *data[VAR_ENTRIES_MAX];
zend_long used_slots;
@@ -137,6 +140,7 @@ PHPAPI zval *var_tmp_var(php_unserialize_data_t *var_hashx)
(*var_hashx)->last_dtor = var_hash;
}
ZVAL_UNDEF(&var_hash->data[var_hash->used_slots]);
+ Z_ACCESS_FLAGS(var_hash->data[var_hash->used_slots]) = 0;
return &var_hash->data[var_hash->used_slots++];
}
@@ -184,6 +188,10 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
zend_long i;
var_entries *var_hash = (*var_hashx)->first;
var_dtor_entries *var_dtor_hash = (*var_hashx)->first_dtor;
+ zend_bool wakeup_failed = 0;
+ zval wakeup_name;
+ ZVAL_UNDEF(&wakeup_name);
+
#if VAR_ENTRIES_DBG
fprintf(stderr, "var_destroy(%ld)\n", var_hash?var_hash->used_slots:-1L);
#endif
@@ -196,15 +204,40 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
while (var_dtor_hash) {
for (i = 0; i < var_dtor_hash->used_slots; i++) {
+ zval *zv = &var_dtor_hash->data[i];
#if VAR_ENTRIES_DBG
fprintf(stderr, "var_destroy dtor(%p, %ld)\n", var_dtor_hash->data[i], Z_REFCOUNT_P(var_dtor_hash->data[i]));
#endif
- zval_ptr_dtor(&var_dtor_hash->data[i]);
+
+ /* Perform delayed __wakeup calls */
+ if (Z_ACCESS_FLAGS_P(zv) == VAR_WAKEUP_FLAG) {
+ if (!wakeup_failed) {
+ zval retval;
+ if (Z_ISUNDEF(wakeup_name)) {
+ ZVAL_STRINGL(&wakeup_name, "__wakeup", sizeof("__wakeup") - 1);
+ }
+
+ BG(serialize_lock)++;
+ if (call_user_function_ex(CG(function_table), zv, &wakeup_name, &retval, 0, 0, 1, NULL) == FAILURE || Z_ISUNDEF(retval)) {
+ wakeup_failed = 1;
+ GC_FLAGS(Z_OBJ_P(zv)) |= IS_OBJ_DESTRUCTOR_CALLED;
+ }
+ BG(serialize_lock)--;
+
+ zval_ptr_dtor(&retval);
+ } else {
+ GC_FLAGS(Z_OBJ_P(zv)) |= IS_OBJ_DESTRUCTOR_CALLED;
+ }
+ }
+
+ zval_ptr_dtor(zv);
}
next = var_dtor_hash->next;
efree_size(var_dtor_hash, sizeof(var_dtor_entries));
var_dtor_hash = next;
}
+
+ zval_ptr_dtor(&wakeup_name);
}
/* }}} */
@@ -508,8 +541,6 @@ static inline zend_long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *
#endif
static inline int object_common2(UNSERIALIZE_PARAMETER, zend_long elements)
{
- zval retval;
- zval fname;
HashTable *ht;
zend_bool has_wakeup;
@@ -532,18 +563,10 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, zend_long elements)
ZVAL_DEREF(rval);
if (has_wakeup) {
- ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1);
- BG(serialize_lock)++;
- if (call_user_function_ex(CG(function_table), rval, &fname, &retval, 0, 0, 1, NULL) == FAILURE || Z_ISUNDEF(retval)) {
- GC_FLAGS(Z_OBJ_P(rval)) |= IS_OBJ_DESTRUCTOR_CALLED;
- }
- BG(serialize_lock)--;
- zval_dtor(&fname);
- zval_dtor(&retval);
- }
-
- if (EG(exception)) {
- return 0;
+ /* Delay __wakeup call until end of serialization */
+ zval *wakeup_var = var_tmp_var(var_hash);
+ ZVAL_COPY(wakeup_var, rval);
+ Z_ACCESS_FLAGS_P(wakeup_var) = VAR_WAKEUP_FLAG;
}
return finish_nested_data(UNSERIALIZE_PASSTHRU);