--- /dev/null
+--TEST--
+Bug #72663 (1): Don't call __destruct if __wakeup not called or fails
+--FILE--
+<?php
+
+class Test1 {
+ public function __wakeup() {
+ echo "Wakeup\n";
+ }
+ public function __destruct() {
+ echo "Dtor\n";
+ }
+}
+
+class Test2 {
+ public function __wakeup() {
+ throw new Exception('Unserialization forbidden');
+ }
+ public function __destruct() {
+ echo "Dtor\n";
+ }
+}
+
+// Unserialize object with error in properties
+$s = 'O:5:"Test1":1:{s:10:"";}';
+var_dump(unserialize($s));
+
+// Variation: Object is turned into a reference
+$s = 'O:5:"Test1":2:{i:0;R:1;s:10:"";}';
+var_dump(unserialize($s));
+
+// Unserialize object with throwing __wakeup
+$s = 'O:5:"Test2":0:{}';
+try {
+ var_dump(unserialize($s));
+} catch (Exception $e) {
+ echo "Caught\n";
+}
+//
+// Variation: Object is turned into a reference
+$s = 'O:5:"Test2":1:{i:0;R:1;}';
+try {
+ var_dump(unserialize($s));
+} catch (Exception $e) {
+ echo "Caught\n";
+}
+
+?>
+--EXPECTF--
+Notice: unserialize(): Error at offset 17 of 24 bytes in %s on line %d
+bool(false)
+
+Notice: unserialize(): Error at offset 25 of 32 bytes in %s on line %d
+bool(false)
+Caught
+Caught
zval retval;
zval fname;
HashTable *ht;
+ zend_bool has_wakeup;
if (Z_TYPE_P(rval) != IS_OBJECT) {
return 0;
}
+ has_wakeup = Z_OBJCE_P(rval) != PHP_IC_ENTRY
+ && zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1);
+
ht = Z_OBJPROP_P(rval);
zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, (ht->u.flags & HASH_FLAG_PACKED));
if (!process_nested_data(UNSERIALIZE_PASSTHRU, ht, elements, 1)) {
+ if (has_wakeup) {
+ ZVAL_DEREF(rval);
+ GC_FLAGS(Z_OBJ_P(rval)) |= IS_OBJ_DESTRUCTOR_CALLED;
+ }
return 0;
}
ZVAL_DEREF(rval);
- if (Z_OBJCE_P(rval) != PHP_IC_ENTRY &&
- zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1)) {
+ if (has_wakeup) {
ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1);
BG(serialize_lock)++;
- call_user_function_ex(CG(function_table), rval, &fname, &retval, 0, 0, 1, NULL);
+ 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);
}
return finish_nested_data(UNSERIALIZE_PASSTHRU);
-
}
#ifdef PHP_WIN32
# pragma optimize("", on)
start = cursor;
-#line 518 "ext/standard/var_unserializer.c"
+#line 526 "ext/standard/var_unserializer.c"
{
YYCTYPE yych;
static const unsigned char yybm[] = {
zval retval;
zval fname;
HashTable *ht;
+ zend_bool has_wakeup;
if (Z_TYPE_P(rval) != IS_OBJECT) {
return 0;
}
+ has_wakeup = Z_OBJCE_P(rval) != PHP_IC_ENTRY
+ && zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1);
+
ht = Z_OBJPROP_P(rval);
zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, (ht->u.flags & HASH_FLAG_PACKED));
if (!process_nested_data(UNSERIALIZE_PASSTHRU, ht, elements, 1)) {
+ if (has_wakeup) {
+ ZVAL_DEREF(rval);
+ GC_FLAGS(Z_OBJ_P(rval)) |= IS_OBJ_DESTRUCTOR_CALLED;
+ }
return 0;
}
ZVAL_DEREF(rval);
- if (Z_OBJCE_P(rval) != PHP_IC_ENTRY &&
- zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1)) {
+ if (has_wakeup) {
ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1);
BG(serialize_lock)++;
- call_user_function_ex(CG(function_table), rval, &fname, &retval, 0, 0, 1, NULL);
+ 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);
}
return finish_nested_data(UNSERIALIZE_PASSTHRU);
-
}
#ifdef PHP_WIN32
# pragma optimize("", on)