diff options
Diffstat (limited to 'ext/standard/var_unserializer.re')
-rw-r--r-- | ext/standard/var_unserializer.re | 84 |
1 files changed, 58 insertions, 26 deletions
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 7fbab9f2f0..bb0000ba5f 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -26,6 +26,11 @@ #define VAR_ENTRIES_MAX 1024 #define VAR_ENTRIES_DBG 0 +#define VAR_WAKEUP_FLAG 1 +#define WITH_WAKEUP_FLAG(zv_ptr) ((zval *) ((zend_uintptr_t) zv_ptr | VAR_WAKEUP_FLAG)) +#define WITHOUT_WAKEUP_FLAG(zv_ptr) ((zval *) ((zend_uintptr_t) zv_ptr & ~VAR_WAKEUP_FLAG)) +#define HAS_WAKEUP_FLAG(zv_ptr) ((zend_uintptr_t) zv_ptr & VAR_WAKEUP_FLAG) + typedef struct { zval *data[VAR_ENTRIES_MAX]; long used_slots; @@ -56,12 +61,12 @@ static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval) var_hash->data[var_hash->used_slots++] = *rval; } -PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval) +static inline zval **get_var_push_dtor_slot(php_unserialize_data_t *var_hashx) { var_entries *var_hash; if (!var_hashx || !*var_hashx) { - return; + return NULL; } var_hash = (*var_hashx)->last_dtor; @@ -83,8 +88,14 @@ PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval) (*var_hashx)->last_dtor = var_hash; } + return &var_hash->data[var_hash->used_slots++]; +} + +PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval) +{ + zval **slot = get_var_push_dtor_slot(var_hashx); Z_ADDREF_PP(rval); - var_hash->data[var_hash->used_slots++] = *rval; + *slot = *rval; } PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval **rval) @@ -162,6 +173,9 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) void *next; long i; var_entries *var_hash = (*var_hashx)->first; + zend_bool wakeup_failed = 0; + TSRMLS_FETCH(); + #if VAR_ENTRIES_DBG fprintf(stderr, "var_destroy(%ld)\n", var_hash?var_hash->used_slots:-1L); #endif @@ -176,10 +190,35 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) while (var_hash) { for (i = 0; i < var_hash->used_slots; i++) { + zval *zv = var_hash->data[i]; #if VAR_ENTRIES_DBG fprintf(stderr, "var_destroy dtor(%p, %ld)\n", var_hash->data[i], Z_REFCOUNT_P(var_hash->data[i])); #endif - zval_ptr_dtor(&var_hash->data[i]); + + if (HAS_WAKEUP_FLAG(zv)) { + zv = WITHOUT_WAKEUP_FLAG(zv); + if (!wakeup_failed) { + zval *retval_ptr = NULL; + zval wakeup_name; + INIT_PZVAL(&wakeup_name); + ZVAL_STRINGL(&wakeup_name, "__wakeup", sizeof("__wakeup") - 1, 0); + + BG(serialize_lock)++; + if (call_user_function_ex(CG(function_table), &zv, &wakeup_name, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC) == FAILURE || retval_ptr == NULL) { + wakeup_failed = 1; + zend_object_store_ctor_failed(zv TSRMLS_CC); + } + BG(serialize_lock)--; + + if (retval_ptr) { + zval_ptr_dtor(&retval_ptr); + } + } else { + zend_object_store_ctor_failed(zv TSRMLS_CC); + } + } + + zval_ptr_dtor(&zv); } next = var_hash->next; efree(var_hash); @@ -435,19 +474,16 @@ static inline long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) #endif static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) { - zval *retval_ptr = NULL; - zval fname; - if (Z_TYPE_PP(rval) != IS_OBJECT) { return 0; } if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) { - /* We've got partially constructed object on our hands here. Wipe it. */ - if(Z_TYPE_PP(rval) == IS_OBJECT) { - zend_hash_clean(Z_OBJPROP_PP(rval)); - zend_object_store_ctor_failed(*rval TSRMLS_CC); - } + /* We've got partially constructed object on our hands here. Wipe it. */ + if (Z_TYPE_PP(rval) == IS_OBJECT) { + zend_hash_clean(Z_OBJPROP_PP(rval)); + zend_object_store_ctor_failed(*rval TSRMLS_CC); + } ZVAL_NULL(*rval); return 0; } @@ -457,20 +493,16 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) } if (Z_OBJCE_PP(rval) != PHP_IC_ENTRY && - zend_hash_exists(&Z_OBJCE_PP(rval)->function_table, "__wakeup", sizeof("__wakeup"))) { - INIT_PZVAL(&fname); - ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1, 0); - BG(serialize_lock)++; - call_user_function_ex(CG(function_table), rval, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC); - BG(serialize_lock)--; - } - - if (retval_ptr) { - zval_ptr_dtor(&retval_ptr); - } - - if (EG(exception)) { - return 0; + zend_hash_exists(&Z_OBJCE_PP(rval)->function_table, "__wakeup", sizeof("__wakeup")) + ) { + /* Store object for delayed __wakeup call. Remove references. */ + zval **slot = get_var_push_dtor_slot(var_hash); + zval *zv = *rval; + Z_ADDREF_P(zv); + if (PZVAL_IS_REF(zv)) { + SEPARATE_ZVAL(&zv); + } + *slot = WITH_WAKEUP_FLAG(zv); } return finish_nested_data(UNSERIALIZE_PASSTHRU); |