mirror of
https://github.com/php/php-src.git
synced 2026-04-21 15:08:16 +02:00
Implement delayed __wakeup
This commit is contained in:
+592
-537
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user