diff options
author | Nikita Popov <nikic@php.net> | 2017-01-05 00:28:21 +0100 |
---|---|---|
committer | Nikita Popov <nikic@php.net> | 2017-01-05 00:28:21 +0100 |
commit | 8d8e94936959eb2466ec77d1e537427f92650363 (patch) | |
tree | ff3b27265e33dbf052fda0141ded85837f7d84c7 /ext/standard/var_unserializer.re | |
parent | 7b436b0c48b7fb089aa6d97075b72f7a9eed4a98 (diff) | |
parent | b47c49d7a00bc34d7e0f3d72732f66e904da6fa7 (diff) | |
download | php-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.re | 53 |
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); |