summaryrefslogtreecommitdiff
path: root/ext/standard/var_unserializer.re
diff options
context:
space:
mode:
Diffstat (limited to 'ext/standard/var_unserializer.re')
-rw-r--r--ext/standard/var_unserializer.re84
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);