]> granicus.if.org Git - php/commitdiff
Fixed bug #64354 (Unserialize array of objects whose class can't be autoloaded fail)
authorXinchen Hui <laruence@php.net>
Sat, 9 Mar 2013 15:00:58 +0000 (23:00 +0800)
committerXinchen Hui <laruence@php.net>
Sat, 9 Mar 2013 15:00:58 +0000 (23:00 +0800)
about the __sleep one, since php_serialize_* are all void function,
so,,only check exception at the very begining

NEWS
ext/standard/tests/serialize/bug64354_1.phpt [new file with mode: 0644]
ext/standard/tests/serialize/bug64354_2.phpt [new file with mode: 0644]
ext/standard/tests/serialize/bug64354_3.phpt [new file with mode: 0644]
ext/standard/var.c
ext/standard/var_unserializer.c
ext/standard/var_unserializer.re

diff --git a/NEWS b/NEWS
index f8a43f6501aa3de0f71024da0810f729aea69bde..1fbd5a2858903ab92db8fac54638865b07a0df5a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,8 @@ PHP                                                                        NEWS
 ?? ??? 2013, PHP 5.4.13
 
 - Core:
+  . Fixed bug #64354 (Unserialize array of objects whose class can't
+    be autoloaded fail). (Laruence)
   . Fixed bug #64235 (Insteadof not work for class method in 5.4.11).
     (Laruence)
   . Fixed bug #64197 (_Offsetof() macro used but not defined on ARM/Clang). 
diff --git a/ext/standard/tests/serialize/bug64354_1.phpt b/ext/standard/tests/serialize/bug64354_1.phpt
new file mode 100644 (file)
index 0000000..e85749b
--- /dev/null
@@ -0,0 +1,25 @@
+--TEST--
+Bug #64354 (Unserialize array of objects whose class can't be autoloaded fail)
+--FILE--
+<?php
+spl_autoload_register(
+    function($class) {
+        throw new Exception("Failed");
+    }
+);
+
+try {
+    var_dump(unserialize('O:1:"A":0:{}'));
+} catch (Exception $e) { 
+    var_dump($e->getMessage());
+}
+
+try {
+    var_dump(unserialize('a:2:{i:0;O:1:"A":0:{}i:1;O:1:"A":0:{}}'));
+} catch (Exception $e) { 
+    var_dump($e->getMessage());
+}
+?>
+--EXPECTF--
+string(6) "Failed"
+string(6) "Failed"
diff --git a/ext/standard/tests/serialize/bug64354_2.phpt b/ext/standard/tests/serialize/bug64354_2.phpt
new file mode 100644 (file)
index 0000000..41a455b
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+Bug #64354 (Unserialize array of objects whose class can't be autoloaded fail)
+--FILE--
+<?php
+class A {
+    public function __wakeup() {
+        throw new Exception("Failed");
+    }
+}
+
+spl_autoload_register(
+    function($class) {
+        throw new Exception("Failed");
+    }
+);
+
+try {
+    var_dump(unserialize('a:2:{i:0;O:1:"A":0:{}i:1;O:1:"B":0:{}}'));
+} catch (Exception $e) { 
+    var_dump($e->getMessage());
+}
+?>
+--EXPECTF--
+string(6) "Failed"
diff --git a/ext/standard/tests/serialize/bug64354_3.phpt b/ext/standard/tests/serialize/bug64354_3.phpt
new file mode 100644 (file)
index 0000000..3ce6115
--- /dev/null
@@ -0,0 +1,29 @@
+--TEST--
+Bug #64354 (Unserialize array of objects whose class can't be autoloaded fail)
+--FILE--
+<?php
+class A {
+    public function __sleep() {
+        throw new Exception("Failed");
+    }
+}
+
+class B implements Serializable {
+    public function serialize() {
+        return NULL;
+    }
+
+    public function unserialize($data) {
+    }
+}
+
+$data = array(new A, new B);
+
+try {
+    serialize($data);
+} catch (Exception $e) { 
+    var_dump($e->getMessage());
+}
+?>
+--EXPECTF--
+string(6) "Failed"
index b13edf6615c7bc216a4fdb7a76006a0ddfe4edf6..f76a14cfa66410880fd2208f50d766a3de7ddfbe 100644 (file)
@@ -714,6 +714,10 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var
        ulong *var_already;
        HashTable *myht;
 
+       if (EG(exception)) {
+               return;
+       }
+
        if (var_hash && php_add_var_hash(var_hash, struc, (void *) &var_already TSRMLS_CC) == FAILURE) {
                if (Z_ISREF_P(struc)) {
                        smart_str_appendl(buf, "R:", 2);
@@ -800,8 +804,15 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var
                                        BG(serialize_lock)++;
                                        res = call_user_function_ex(CG(function_table), &struc, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC);
                                        BG(serialize_lock)--;
+                    
+                                       if (EG(exception)) {
+                                               if (retval_ptr) {
+                                                       zval_ptr_dtor(&retval_ptr);
+                                               }
+                                               return;
+                                       }
 
-                                       if (res == SUCCESS && !EG(exception)) {
+                                       if (res == SUCCESS) {
                                                if (retval_ptr) {
                                                        if (HASH_OF(retval_ptr)) {
                                                                php_var_serialize_class(buf, struc, retval_ptr, var_hash TSRMLS_CC);
@@ -921,6 +932,11 @@ PHP_FUNCTION(serialize)
        php_var_serialize(&buf, struc, &var_hash TSRMLS_CC);
        PHP_VAR_SERIALIZE_DESTROY(var_hash);
 
+       if (EG(exception)) {
+               smart_str_free(&buf);
+               RETURN_FALSE;
+       }
+
        if (buf.c) {
                RETURN_STRINGL(buf.c, buf.len, 0);
        } else {
@@ -951,7 +967,9 @@ PHP_FUNCTION(unserialize)
        if (!php_var_unserialize(&return_value, &p, p + buf_len, &var_hash TSRMLS_CC)) {
                PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
                zval_dtor(return_value);
-               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
+               if (!EG(exception)) {
+                       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
+               }
                RETURN_FALSE;
        }
        PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
index bd0b2f66958c80bffe1faee49078e47a23c5c16f..d8bae08d2a599925b28cc021da32fe68cc4c7466 100644 (file)
@@ -1,4 +1,4 @@
-/* Generated by re2c 0.13.5 on Mon Jan 21 11:34:03 2013 */
+/* Generated by re2c 0.13.5 on Sat Mar  9 22:33:09 2013 */
 #line 1 "ext/standard/var_unserializer.re"
 /*
   +----------------------------------------------------------------------+
@@ -396,8 +396,13 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
                BG(serialize_lock)--;
        }
 
-       if (retval_ptr)
+       if (retval_ptr) {
                zval_ptr_dtor(&retval_ptr);
+       }
+
+       if (EG(exception)) {
+               return 0;
+       }
 
        return finish_nested_data(UNSERIALIZE_PASSTHRU);
 
@@ -427,7 +432,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
        
        
 
-#line 431 "ext/standard/var_unserializer.c"
+#line 436 "ext/standard/var_unserializer.c"
 {
        YYCTYPE yych;
        static const unsigned char yybm[] = {
@@ -487,9 +492,9 @@ yy2:
        yych = *(YYMARKER = ++YYCURSOR);
        if (yych == ':') goto yy95;
 yy3:
-#line 759 "ext/standard/var_unserializer.re"
+#line 785 "ext/standard/var_unserializer.re"
        { return 0; }
-#line 493 "ext/standard/var_unserializer.c"
+#line 498 "ext/standard/var_unserializer.c"
 yy4:
        yych = *(YYMARKER = ++YYCURSOR);
        if (yych == ':') goto yy89;
@@ -532,13 +537,13 @@ yy13:
        goto yy3;
 yy14:
        ++YYCURSOR;
-#line 753 "ext/standard/var_unserializer.re"
+#line 779 "ext/standard/var_unserializer.re"
        {
        /* this is the case where we have less data than planned */
        php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data");
        return 0; /* not sure if it should be 0 or 1 here? */
 }
-#line 542 "ext/standard/var_unserializer.c"
+#line 547 "ext/standard/var_unserializer.c"
 yy16:
        yych = *++YYCURSOR;
        goto yy3;
@@ -568,7 +573,7 @@ yy20:
        yych = *++YYCURSOR;
        if (yych != '"') goto yy18;
        ++YYCURSOR;
-#line 630 "ext/standard/var_unserializer.re"
+#line 635 "ext/standard/var_unserializer.re"
        {
        size_t len, len2, len3, maxlen;
        long elements;
@@ -623,10 +628,19 @@ yy20:
                BG(serialize_lock) = 1;
                if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
                        BG(serialize_lock) = 0;
+                       if (EG(exception)) {
+                               efree(class_name);
+                               return 0;
+                       }
                        ce = *pce;
                        break;
                }
                BG(serialize_lock) = 0;
+
+               if (EG(exception)) {
+                       efree(class_name);
+                       return 0;
+               }
                
                /* Check for unserialize callback */
                if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
@@ -644,6 +658,12 @@ yy20:
                BG(serialize_lock) = 1;
                if (call_user_function_ex(CG(function_table), NULL, user_func, &retval_ptr, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) {
                        BG(serialize_lock) = 0;
+                       if (EG(exception)) {
+                               efree(class_name);
+                               zval_ptr_dtor(&user_func);
+                               zval_ptr_dtor(&arg_func_name);
+                               return 0;
+                       }
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "defined (%s) but not found", user_func->value.str.val);
                        incomplete_class = 1;
                        ce = PHP_IC_ENTRY;
@@ -655,6 +675,12 @@ yy20:
                if (retval_ptr) {
                        zval_ptr_dtor(&retval_ptr);
                }
+               if (EG(exception)) {
+                       efree(class_name);
+                       zval_ptr_dtor(&user_func);
+                       zval_ptr_dtor(&arg_func_name);
+                       return 0;
+               }
                
                /* The callback function may have defined the class */
                if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
@@ -691,7 +717,7 @@ yy20:
 
        return object_common2(UNSERIALIZE_PASSTHRU, elements);
 }
-#line 695 "ext/standard/var_unserializer.c"
+#line 721 "ext/standard/var_unserializer.c"
 yy25:
        yych = *++YYCURSOR;
        if (yych <= ',') {
@@ -716,7 +742,7 @@ yy27:
        yych = *++YYCURSOR;
        if (yych != '"') goto yy18;
        ++YYCURSOR;
-#line 622 "ext/standard/var_unserializer.re"
+#line 627 "ext/standard/var_unserializer.re"
        {
 
        INIT_PZVAL(*rval);
@@ -724,7 +750,7 @@ yy27:
        return object_common2(UNSERIALIZE_PASSTHRU,
                        object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
 }
-#line 728 "ext/standard/var_unserializer.c"
+#line 754 "ext/standard/var_unserializer.c"
 yy32:
        yych = *++YYCURSOR;
        if (yych == '+') goto yy33;
@@ -745,7 +771,7 @@ yy34:
        yych = *++YYCURSOR;
        if (yych != '{') goto yy18;
        ++YYCURSOR;
-#line 602 "ext/standard/var_unserializer.re"
+#line 607 "ext/standard/var_unserializer.re"
        {
        long elements = parse_iv(start + 2);
        /* use iv() not uiv() in order to check data range */
@@ -765,7 +791,7 @@ yy34:
 
        return finish_nested_data(UNSERIALIZE_PASSTHRU);
 }
-#line 769 "ext/standard/var_unserializer.c"
+#line 795 "ext/standard/var_unserializer.c"
 yy39:
        yych = *++YYCURSOR;
        if (yych == '+') goto yy40;
@@ -786,7 +812,7 @@ yy41:
        yych = *++YYCURSOR;
        if (yych != '"') goto yy18;
        ++YYCURSOR;
-#line 573 "ext/standard/var_unserializer.re"
+#line 578 "ext/standard/var_unserializer.re"
        {
        size_t len, maxlen;
        char *str;
@@ -815,7 +841,7 @@ yy41:
        ZVAL_STRINGL(*rval, str, len, 0);
        return 1;
 }
-#line 819 "ext/standard/var_unserializer.c"
+#line 845 "ext/standard/var_unserializer.c"
 yy46:
        yych = *++YYCURSOR;
        if (yych == '+') goto yy47;
@@ -836,7 +862,7 @@ yy48:
        yych = *++YYCURSOR;
        if (yych != '"') goto yy18;
        ++YYCURSOR;
-#line 545 "ext/standard/var_unserializer.re"
+#line 550 "ext/standard/var_unserializer.re"
        {
        size_t len, maxlen;
        char *str;
@@ -864,7 +890,7 @@ yy48:
        ZVAL_STRINGL(*rval, str, len, 1);
        return 1;
 }
-#line 868 "ext/standard/var_unserializer.c"
+#line 894 "ext/standard/var_unserializer.c"
 yy53:
        yych = *++YYCURSOR;
        if (yych <= '/') {
@@ -952,7 +978,7 @@ yy61:
        }
 yy63:
        ++YYCURSOR;
-#line 535 "ext/standard/var_unserializer.re"
+#line 540 "ext/standard/var_unserializer.re"
        {
 #if SIZEOF_LONG == 4
 use_double:
@@ -962,7 +988,7 @@ use_double:
        ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
        return 1;
 }
-#line 966 "ext/standard/var_unserializer.c"
+#line 992 "ext/standard/var_unserializer.c"
 yy65:
        yych = *++YYCURSOR;
        if (yych <= ',') {
@@ -1021,7 +1047,7 @@ yy73:
        yych = *++YYCURSOR;
        if (yych != ';') goto yy18;
        ++YYCURSOR;
-#line 520 "ext/standard/var_unserializer.re"
+#line 525 "ext/standard/var_unserializer.re"
        {
        *p = YYCURSOR;
        INIT_PZVAL(*rval);
@@ -1036,7 +1062,7 @@ yy73:
 
        return 1;
 }
-#line 1040 "ext/standard/var_unserializer.c"
+#line 1066 "ext/standard/var_unserializer.c"
 yy76:
        yych = *++YYCURSOR;
        if (yych == 'N') goto yy73;
@@ -1063,7 +1089,7 @@ yy79:
        if (yych <= '9') goto yy79;
        if (yych != ';') goto yy18;
        ++YYCURSOR;
-#line 493 "ext/standard/var_unserializer.re"
+#line 498 "ext/standard/var_unserializer.re"
        {
 #if SIZEOF_LONG == 4
        int digits = YYCURSOR - start - 3;
@@ -1090,7 +1116,7 @@ yy79:
        ZVAL_LONG(*rval, parse_iv(start + 2));
        return 1;
 }
-#line 1094 "ext/standard/var_unserializer.c"
+#line 1120 "ext/standard/var_unserializer.c"
 yy83:
        yych = *++YYCURSOR;
        if (yych <= '/') goto yy18;
@@ -1098,24 +1124,24 @@ yy83:
        yych = *++YYCURSOR;
        if (yych != ';') goto yy18;
        ++YYCURSOR;
-#line 486 "ext/standard/var_unserializer.re"
+#line 491 "ext/standard/var_unserializer.re"
        {
        *p = YYCURSOR;
        INIT_PZVAL(*rval);
        ZVAL_BOOL(*rval, parse_iv(start + 2));
        return 1;
 }
-#line 1109 "ext/standard/var_unserializer.c"
+#line 1135 "ext/standard/var_unserializer.c"
 yy87:
        ++YYCURSOR;
-#line 479 "ext/standard/var_unserializer.re"
+#line 484 "ext/standard/var_unserializer.re"
        {
        *p = YYCURSOR;
        INIT_PZVAL(*rval);
        ZVAL_NULL(*rval);
        return 1;
 }
-#line 1119 "ext/standard/var_unserializer.c"
+#line 1145 "ext/standard/var_unserializer.c"
 yy89:
        yych = *++YYCURSOR;
        if (yych <= ',') {
@@ -1138,7 +1164,7 @@ yy91:
        if (yych <= '9') goto yy91;
        if (yych != ';') goto yy18;
        ++YYCURSOR;
-#line 456 "ext/standard/var_unserializer.re"
+#line 461 "ext/standard/var_unserializer.re"
        {
        long id;
 
@@ -1161,7 +1187,7 @@ yy91:
        
        return 1;
 }
-#line 1165 "ext/standard/var_unserializer.c"
+#line 1191 "ext/standard/var_unserializer.c"
 yy95:
        yych = *++YYCURSOR;
        if (yych <= ',') {
@@ -1184,7 +1210,7 @@ yy97:
        if (yych <= '9') goto yy97;
        if (yych != ';') goto yy18;
        ++YYCURSOR;
-#line 435 "ext/standard/var_unserializer.re"
+#line 440 "ext/standard/var_unserializer.re"
        {
        long id;
 
@@ -1205,9 +1231,9 @@ yy97:
        
        return 1;
 }
-#line 1209 "ext/standard/var_unserializer.c"
+#line 1235 "ext/standard/var_unserializer.c"
 }
-#line 761 "ext/standard/var_unserializer.re"
+#line 787 "ext/standard/var_unserializer.re"
 
 
        return 0;
index 204995783fe5761c4784ef13d76255ab060da220..4d99cbfd78944c8ed77f51647ae7ef50d86084b0 100644 (file)
@@ -400,8 +400,13 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
                BG(serialize_lock)--;
        }
 
-       if (retval_ptr)
+       if (retval_ptr) {
                zval_ptr_dtor(&retval_ptr);
+       }
+
+       if (EG(exception)) {
+               return 0;
+       }
 
        return finish_nested_data(UNSERIALIZE_PASSTHRU);
 
@@ -681,10 +686,19 @@ object ":" uiv ":" ["]    {
                BG(serialize_lock) = 1;
                if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
                        BG(serialize_lock) = 0;
+                       if (EG(exception)) {
+                               efree(class_name);
+                               return 0;
+                       }
                        ce = *pce;
                        break;
                }
                BG(serialize_lock) = 0;
+
+               if (EG(exception)) {
+                       efree(class_name);
+                       return 0;
+               }
                
                /* Check for unserialize callback */
                if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
@@ -702,6 +716,12 @@ object ":" uiv ":" ["]     {
                BG(serialize_lock) = 1;
                if (call_user_function_ex(CG(function_table), NULL, user_func, &retval_ptr, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) {
                        BG(serialize_lock) = 0;
+                       if (EG(exception)) {
+                               efree(class_name);
+                               zval_ptr_dtor(&user_func);
+                               zval_ptr_dtor(&arg_func_name);
+                               return 0;
+                       }
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "defined (%s) but not found", user_func->value.str.val);
                        incomplete_class = 1;
                        ce = PHP_IC_ENTRY;
@@ -713,6 +733,12 @@ object ":" uiv ":" ["]     {
                if (retval_ptr) {
                        zval_ptr_dtor(&retval_ptr);
                }
+               if (EG(exception)) {
+                       efree(class_name);
+                       zval_ptr_dtor(&user_func);
+                       zval_ptr_dtor(&arg_func_name);
+                       return 0;
+               }
                
                /* The callback function may have defined the class */
                if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {