CVE-2017-12932 (published 2017-08-18T03:29Z)

ext/standard/var_unserializer.re in PHP 7.0.x through 7.0.22 and 7.1.x through 7.1.8 is prone to a heap use after free while unserializing untrusted data, related to improper use of the hash API for key deletion in a situation with an invalid array size. Exploitation of this issue can have an unspecified impact on the integrity of PHP.

Severity: HIGH
CVSS v2 base score: 7.5 (AV:N/AC:L/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 9.8, CRITICAL (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-416
cwe_name: Use After Free
description: The product reuses or references memory after it has been freed. At some point afterward, the memory may be allocated again and saved in another pointer, while the original pointer references a location somewhere within the new allocation. Any operations using the original pointer are no longer valid because the memory "belongs" to the code that operates on the new pointer.
extended_description: 
             
             
             
			 
             
             
         
         

Fix information:
repo_url: https://github.com/php/php-src
commit_details: repo_url: https://github.com/php/php-src
author: Nikita Popov
author_date: 2017-08-12 13:00:39+02:00
msg: Fixed bug #74103 and bug #75054

Directly fail unserialization when trying to acquire an r/R
reference to an UNDEF HT slot. Previously this left an UNDEF and
later deleted the index/key from the HT.

What actually caused the issue here is a combination of two
factors: First, the key deletion was performed using the hash API,
rather than the symtable API, such that the element was not actually
removed if it used an integral string key. Second, a subsequent
deletion operation, while collecting trailing UNDEF ranges, would
mark the element as available for reuse (leaving a corrupted HT
state with nNumOfElemnts > nNumUsed).

Fix this by failing early and dropping the deletion code.
repository: repo_url: https://github.com/php/php-src
repo_name: php/php-src
description: The PHP Interpreter
repo_language: C
owner: php
file_changes: filename: NEWS
change_type: ModificationType.MODIFY
diff: @@ -52,6 +52,12 @@ PHP                                                                        NEWS
   . Fixed bug #74669 (Unserialize ArrayIterator broken). (Andrew Nester)
   . Fixed bug #75015 (Crash in recursive iterator destructors). (Julien)
 
+- Standard:
+  . Fixed bug #74103 (heap-use-after-free when unserializing invalid array
+    size). (Nikita)
+  . Fixed bug #75054 (A Denial of Service Vulnerability was found when
+    performing deserialization). (Nikita)
+
 - XMLRPC:
   . Fixed bug #74975 (Incorrect xmlrpc serialization for classes with declared
     properties). (blar)

programming_language: Markdown
filename: bug74103.phpt
change_type: ModificationType.ADD
diff: @@ -0,0 +1,9 @@
+--TEST--
+Bug #74103: heap-use-after-free when unserializing invalid array size
+--FILE--
+<?php
+var_dump(unserialize('a:7:{i:0;i:04;s:1:"a";i:2;i:00009617006;i:4;s:1:"a";i:4;s:1:"a";R:5;s:1:"7";R:3;s:1:"a";R:5;;s:18;}}'));
+?>
+--EXPECTF--
+Notice: unserialize(): Error at offset 68 of 100 bytes in %s on line %d
+bool(false)

programming_language: SQL
filename: bug75054.phpt
change_type: ModificationType.ADD
diff: @@ -0,0 +1,12 @@
+--TEST--
+Bug #75054: A Denial of Service Vulnerability was found when performing deserialization
+--FILE--
+<?php
+$poc = 'a:9:{i:0;s:4:"0000";i:0;s:4:"0000";i:0;R:2;s:4:"5003";R:2;s:4:"0000";R:2;s:4:"0000";R:2;s:4:"';
+$poc .= "\x06";
+$poc .= '000";R:2;s:4:"0000";d:0;s:4:"0000";a:9:{s:4:"0000";';
+var_dump(unserialize($poc));
+?>
+--EXPECTF--
+Notice: unserialize(): Error at offset 43 of 145 bytes in %s on line %d
+bool(false)

programming_language: PHP
filename: var_unserializer.c
change_type: ModificationType.MODIFY
diff: @@ -1,4 +1,4 @@
-/* Generated by re2c 0.15.3 */
+/* Generated by re2c 0.16 */
 #line 1 "ext/standard/var_unserializer.re"
 /*
   +----------------------------------------------------------------------+
@@ -405,16 +405,7 @@ static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTab
 			return 0;
 		}
 
-		if (UNEXPECTED(Z_ISUNDEF_P(data))) {
-			if (Z_TYPE(key) == IS_LONG) {
-				zend_hash_index_del(ht, Z_LVAL(key));
-			} else {
-				zend_hash_del_ind(ht, Z_STR(key));
-			}
-		} else {
-			var_push_dtor(var_hash, data);
-		}
-
+		var_push_dtor(var_hash, data);
 		zval_dtor(&key);
 
 		if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
@@ -581,7 +572,7 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
 	start = cursor;
 
 
-#line 585 "ext/standard/var_unserializer.c"
+#line 576 "ext/standard/var_unserializer.c"
 {
 	YYCTYPE yych;
 	static const unsigned char yybm[] = {
@@ -622,536 +613,409 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
 	yych = *YYCURSOR;
 	switch (yych) {
 	case 'C':
-	case 'O':	goto yy13;
+	case 'O':	goto yy4;
 	case 'N':	goto yy5;
-	case 'R':	goto yy2;
-	case 'S':	goto yy10;
-	case 'a':	goto yy11;
-	case 'b':	goto yy6;
-	case 'd':	goto yy8;
-	case 'i':	goto yy7;
+	case 'R':	goto yy6;
+	case 'S':	goto yy7;
+	case 'a':	goto yy8;
+	case 'b':	goto yy9;
+	case 'd':	goto yy10;
+	case 'i':	goto yy11;
 	case 'o':	goto yy12;
-	case 'r':	goto yy4;
-	case 's':	goto yy9;
-	case '}':	goto yy14;
-	default:	goto yy16;
+	case 'r':	goto yy13;
+	case 's':	goto yy14;
+	case '}':	goto yy15;
+	default:	goto yy2;
 	}
 yy2:
-	yych = *(YYMARKER = ++YYCURSOR);
-	if (yych == ':') goto yy95;
+	++YYCURSOR;
 yy3:
-#line 962 "ext/standard/var_unserializer.re"
+#line 951 "ext/standard/var_unserializer.re"
 	{ return 0; }
-#line 646 "ext/standard/var_unserializer.c"
+#line 636 "ext/standard/var_unserializer.c"
 yy4:
 	yych = *(YYMARKER = ++YYCURSOR);
-	if (yych == ':') goto yy89;
+	if (yych == ':') goto yy17;
 	goto yy3;
 yy5:
 	yych = *++YYCURSOR;
-	if (yych == ';') goto yy87;
+	if (yych == ';') goto yy19;
 	goto yy3;
 yy6:
 	yych = *(YYMARKER = ++YYCURSOR);
-	if (yych == ':') goto yy83;
+	if (yych == ':') goto yy21;
 	goto yy3;
 yy7:
 	yych = *(YYMARKER = ++YYCURSOR);
-	if (yych == ':') goto yy77;
+	if (yych == ':') goto yy22;
 	goto yy3;
 yy8:
 	yych = *(YYMARKER = ++YYCURSOR);
-	if (yych == ':') goto yy53;
+	if (yych == ':') goto yy23;
 	goto yy3;
 yy9:
 	yych = *(YYMARKER = ++YYCURSOR);
-	if (yych == ':') goto yy46;
+	if (yych == ':') goto yy24;
 	goto yy3;
 yy10:
 	yych = *(YYMARKER = ++YYCURSOR);
-	if (yych == ':') goto yy39;
+	if (yych == ':') goto yy25;
 	goto yy3;
 yy11:
 	yych = *(YYMARKER = ++YYCURSOR);
-	if (yych == ':') goto yy32;
+	if (yych == ':') goto yy26;
 	goto yy3;
 yy12:
 	yych = *(YYMARKER = ++YYCURSOR);
-	if (yych == ':') goto yy25;
+	if (yych == ':') goto yy27;
 	goto yy3;
 yy13:
 	yych = *(YYMARKER = ++YYCURSOR);
-	if (yych == ':') goto yy17;
+	if (yych == ':') goto yy28;
 	goto yy3;
 yy14:
+	yych = *(YYMARKER = ++YYCURSOR);
+	if (yych == ':') goto yy29;
+	goto yy3;
+yy15:
 	++YYCURSOR;
-#line 956 "ext/standard/var_unserializer.re"
+#line 945 "ext/standard/var_unserializer.re"
 	{
 	/* this is the case where we have less data than planned */
 	php_error_docref(NULL, E_NOTICE, "Unexpected end of serialized data");
 	return 0; /* not sure if it should be 0 or 1 here? */
 }
-#line 695 "ext/standard/var_unserializer.c"
-yy16:
-	yych = *++YYCURSOR;
-	goto yy3;
+#line 689 "ext/standard/var_unserializer.c"
 yy17:
 	yych = *++YYCURSOR;
 	if (yybm[0+yych] & 128) {
-		goto yy20;
+		goto yy31;
 	}
-	if (yych == '+') goto yy19;
+	if (yych == '+') goto yy30;
 yy18:
 	YYCURSOR = YYMARKER;
 	goto yy3;
 yy19:
+	++YYCURSOR;
+#line 629 "ext/standard/var_unserializer.re"
+	{
+	*p = YYCURSOR;
+	ZVAL_NULL(rval);
+	return 1;
+}
+#line 707 "ext/standard/var_unserializer.c"
+yy21:
 	yych = *++YYCURSOR;
-	if (yybm[0+yych] & 128) {
-		goto yy20;
+	if (yych <= ',') {
+		if (yych == '+') goto yy33;
+		goto yy18;
+	} else {
+		if (yych <= '-') goto yy33;
+		if (yych <= '/') goto yy18;
+		if (yych <= '9') goto yy34;
+		goto yy18;
 	}
+yy22:
+	yych = *++YYCURSOR;
+	if (yych == '+') goto yy36;
+	if (yych <= '/') goto yy18;
+	if (yych <= '9') goto yy37;
 	goto yy18;
-yy20:
-	++YYCURSOR;
-	if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
-	yych = *YYCURSOR;
-	if (yybm[0+yych] & 128) {
-		goto yy20;
-	}
+yy23:
+	yych = *++YYCURSOR;
+	if (yych == '+') goto yy39;
 	if (yych <= '/') goto yy18;
-	if (yych >= ';') goto yy18;
+	if (yych <= '9') goto yy40;
+	goto yy18;
+yy24:
 	yych = *++YYCURSOR;
-	if (yych != '"') goto yy18;
-	++YYCURSOR;
-#line 804 "ext/standard/var_unserializer.re"
-	{
-	size_t len, len2, len3, maxlen;
-	zend_long elements;
-	char *str;
-	zend_string *class_name;
-	zend_class_entry *ce;
-	int incomplete_class = 0;
-
-	int custom_object = 0;
-
-	zval user_func;
-	zval retval;
-	zval args[1];
-
-    if (!var_hash) return 0;
-	if (*start == 'C') {
-		custom_object = 1;
-	}
-
-	len2 = len = parse_uiv(start + 2);
-	maxlen = max - YYCURSOR;
-	if (maxlen < len || len == 0) {
-		*p = start + 2;
-		return 0;
-	}
-
-	str = (char*)YYCURSOR;
-
-	YYCURSOR += len;
-
-	if (*(YYCURSOR) != '"') {
-		*p = YYCURSOR;
-		return 0;
-	}
-	if (*(YYCURSOR+1) != ':') {
-		*p = YYCURSOR+1;
-		return 0;
-	}
-
-	len3 = strspn(str, "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377\\");
-	if (len3 != len)
-	{
-		*p = YYCURSOR + len3 - len;
-		return 0;
-	}
-
-	class_name = zend_string_init(str, len, 0);
-
-	do {
-		if(!unserialize_allowed_class(class_name, classes)) {
-			incomplete_class = 1;
-			ce = PHP_IC_ENTRY;
-			break;
-		}
-
-		/* Try to find class directly */
-		BG(serialize_lock)++;
-		ce = zend_lookup_class(class_name);
-		if (ce) {
-			BG(serialize_lock)--;
-			if (EG(exception)) {
-				zend_string_release(class_name);
-				return 0;
-			}
-			break;
-		}
-		BG(serialize_lock)--;
-
-		if (EG(exception)) {
-			zend_string_release(class_name);
-			return 0;
-		}
-
-		/* Check for unserialize callback */
-		if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
-			incomplete_class = 1;
-			ce = PHP_IC_ENTRY;
-			break;
-		}
-
-		/* Call unserialize callback */
-		ZVAL_STRING(&user_func, PG(unserialize_callback_func));
-
-		ZVAL_STR_COPY(&args[0], class_name);
-		BG(serialize_lock)++;
-		if (call_user_function_ex(CG(function_table), NULL, &user_func, &retval, 1, args, 0, NULL) != SUCCESS) {
-			BG(serialize_lock)--;
-			if (EG(exception)) {
-				zend_string_release(class_name);
-				zval_ptr_dtor(&user_func);
-				zval_ptr_dtor(&args[0]);
-				return 0;
-			}
-			php_error_docref(NULL, E_WARNING, "defined (%s) but not found", Z_STRVAL(user_func));
-			incomplete_class = 1;
-			ce = PHP_IC_ENTRY;
-			zval_ptr_dtor(&user_func);
-			zval_ptr_dtor(&args[0]);
-			break;
-		}
-		BG(serialize_lock)--;
-		zval_ptr_dtor(&retval);
-		if (EG(exception)) {
-			zend_string_release(class_name);
-			zval_ptr_dtor(&user_func);
-			zval_ptr_dtor(&args[0]);
-			return 0;
-		}
-
-		/* The callback function may have defined the class */
-		BG(serialize_lock)++;
-		if ((ce = zend_lookup_class(class_name)) == NULL) {
-			php_error_docref(NULL, E_WARNING, "Function %s() hasn't defined the class it was called for", Z_STRVAL(user_func));
-			incomplete_class = 1;
-			ce = PHP_IC_ENTRY;
+	if (yych <= '/') goto yy18;
+	if (yych <= '1') goto yy42;
+	goto yy18;
+yy25:
+	yych = *++YYCURSOR;
+	if (yych <= '/') {
+		if (yych <= ',') {
+			if (yych == '+') goto yy43;
+			goto yy18;
+		} else {
+			if (yych <= '-') goto yy44;
+			if (yych <= '.') goto yy45;
+			goto yy18;
 		}
-		BG(serialize_lock)--;
-
-		zval_ptr_dtor(&user_func);
-		zval_ptr_dtor(&args[0]);
-		break;
-	} while (1);
-
-	*p = YYCURSOR;
-
-	if (custom_object) {
-		int ret;
-
-		ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
-
-		if (ret && incomplete_class) {
-			php_store_class_name(rval, ZSTR_VAL(class_name), len2);
+	} else {
+		if (yych <= 'I') {
+			if (yych <= '9') goto yy46;
+			if (yych <= 'H') goto yy18;
+			goto yy48;
+		} else {
+			if (yych == 'N') goto yy49;
+			goto yy18;
 		}
-		zend_string_release(class_name);
-		return ret;
 	}
-
-	elements = object_common1(UNSERIALIZE_PASSTHRU, ce);
-
-	if (elements < 0) {
-	   zend_string_release(class_name);
-	   return 0;
+yy26:
+	yych = *++YYCURSOR;
+	if (yych <= ',') {
+		if (yych == '+') goto yy50;
+		goto yy18;
+	} else {
+		if (yych <= '-') goto yy50;
+		if (yych <= '/') goto yy18;
+		if (yych <= '9') goto yy51;
+		goto yy18;
 	}
-
-	if (incomplete_class) {
-		php_store_class_name(rval, ZSTR_VAL(class_name), len2);
+yy27:
+	yych = *++YYCURSOR;
+	if (yych <= ',') {
+		if (yych == '+') goto yy53;
+		goto yy18;
+	} else {
+		if (yych <= '-') goto yy53;
+		if (yych <= '/') goto yy18;
+		if (yych <= '9') goto yy54;
+		goto yy18;
 	}
-	zend_string_release(class_name);
-
-	return object_common2(UNSERIALIZE_PASSTHRU, elements);
-}
-#line 878 "ext/standard/var_unserializer.c"
-yy25:
+yy28:
 	yych = *++YYCURSOR;
 	if (yych <= ',') {
-		if (yych != '+') goto yy18;
+		if (yych == '+') goto yy56;
+		goto yy18;
 	} else {
-		if (yych <= '-') goto yy26;
+		if (yych <= '-') goto yy56;
 		if (yych <= '/') goto yy18;
-		if (yych <= '9') goto yy27;
+		if (yych <= '9') goto yy57;
 		goto yy18;
 	}
-yy26:
+yy29:
 	yych = *++YYCURSOR;
+	if (yych == '+') goto yy59;
 	if (yych <= '/') goto yy18;
-	if (yych >= ':') goto yy18;
-yy27:
+	if (yych <= '9') goto yy60;
+	goto yy18;
+yy30:
+	yych = *++YYCURSOR;
+	if (yybm[0+yych] & 128) {
+		goto yy31;
+	}
+	goto yy18;
+yy31:
 	++YYCURSOR;
 	if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
 	yych = *YYCURSOR;
+	if (yybm[0+yych] & 128) {
+		goto yy31;
+	}
 	if (yych <= '/') goto yy18;
-	if (yych <= '9') goto yy27;
-	if (yych >= ';') goto yy18;
+	if (yych <= ':') goto yy62;
+	goto yy18;
+yy33:
 	yych = *++YYCURSOR;
-	if (yych != '"') goto yy18;
+	if (yych <= '/') goto yy18;
+	if (yych >= ':') goto yy18;
+yy34:
 	++YYCURSOR;
-#line 793 "ext/standard/var_unserializer.re"
-	{
-	zend_long elements;
-    if (!var_hash) return 0;
-
-	elements = object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR);
-	if (elements < 0 || elements >= HT_MAX_SIZE) {
-		return 0;
-	}
-	return object_common2(UNSERIALIZE_PASSTHRU, elements);
-}
-#line 914 "ext/standard/var_unserializer.c"
-yy32:
-	yych = *++YYCURSOR;
-	if (yych == '+') goto yy33;
+	if (YYLIMIT <= YYCURSOR) YYFILL(1);
+	yych = *YYCURSOR;
 	if (yych <= '/') goto yy18;
 	if (yych <= '9') goto yy34;
+	if (yych == ';') goto yy63;
 	goto yy18;
-yy33:
+yy36:
 	yych = *++YYCURSOR;
 	if (yych <= '/') goto yy18;
 	if (yych >= ':') goto yy18;
-yy34:
+yy37:
 	++YYCURSOR;
 	if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
 	yych = *YYCURSOR;
 	if (yych <= '/') goto yy18;
-	if (yych <= '9') goto yy34;
-	if (yych >= ';') goto yy18;
+	if (yych <= '9') goto yy37;
+	if (yych <= ':') goto yy65;
+	goto yy18;
+yy39:
 	yych = *++YYCURSOR;
-	if (yych != '{') goto yy18;
+	if (yych <= '/') goto yy18;
+	if (yych >= ':') goto yy18;
+yy40:
 	++YYCURSOR;
-#line 769 "ext/standard/var_unserializer.re"
-	{
-	zend_long elements = parse_iv(start + 2);
-	/* use iv() not uiv() in order to check data range */
-	*p = YYCURSOR;
-    if (!var_hash) return 0;
-
-	if (elements < 0 || elements >= HT_MAX_SIZE) {
-		return 0;
-	}
-
-	array_init_size(rval, elements);
-	if (elements) {
-		/* we can't convert from packed to hash during unserialization, because
-		   reference to some zvals might be keept in var_hash (to support references) */
-		zend_hash_real_init(Z_ARRVAL_P(rval), 0);
+	if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
+	yych = *YYCURSOR;
+	if (yych <= '/') goto yy18;
+	if (yych <= '9') goto yy40;
+	if (yych <= ':') goto yy66;
+	goto yy18;
+yy42:
+	yych = *++YYCURSOR;
+	if (yych == ';') goto yy67;
+	goto yy18;
+yy43:
+	yych = *++YYCURSOR;
+	if (yych == '.') goto yy45;
+	if (yych <= '/') goto yy18;
+	if (yych <= '9') goto yy46;
+	goto yy18;
+yy44:
+	yych = *++YYCURSOR;
+	if (yych <= '/') {
+		if (yych != '.') goto yy18;
+	} else {
+		if (yych <= '9') goto yy46;
+		if (yych == 'I') goto yy48;
+		goto yy18;
 	}
-
-	if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements, 0)) {
-		return 0;
+yy45:
+	yych = *++YYCURSOR;
+	if (yych <= '/') goto yy18;
+	if (yych <= '9') goto yy69;
+	goto yy18;
+yy46:
+	++YYCURSOR;
+	if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
+	yych = *YYCURSOR;
+	if (yych <= ':') {
+		if (yych <= '.') {
+			if (yych <= '-') goto yy18;
+			goto yy69;
+		} else {
+			if (yych <= '/') goto yy18;
+			if (yych <= '9') goto yy46;
+			goto yy18;
+		}
+	} else {
+		if (yych <= 'E') {
+			if (yych <= ';') goto yy71;
+			if (yych <= 'D') goto yy18;
+			goto yy73;
+		} else {
+			if (yych == 'e') goto yy73;
+			goto yy18;
+		}
 	}
-
-	return finish_nested_data(UNSERIALIZE_PASSTHRU);
-}
-#line 959 "ext/standard/var_unserializer.c"
-yy39:
+yy48:
+	yych = *++YYCURSOR;
+	if (yych == 'N') goto yy74;
+	goto yy18;
+yy49:
+	yych = *++YYCURSOR;
+	if (yych == 'A') goto yy75;
+	goto yy18;
+yy50:
 	yych = *++YYCURSOR;
-	if (yych == '+') goto yy40;
 	if (yych <= '/') goto yy18;
-	if (yych <= '9') goto yy41;
+	if (yych >= ':') goto yy18;
+yy51:
+	++YYCURSOR;
+	if (YYLIMIT <= YYCURSOR) YYFILL(1);
+	yych = *YYCURSOR;
+	if (yych <= '/') goto yy18;
+	if (yych <= '9') goto yy51;
+	if (yych == ';') goto yy76;
 	goto yy18;
-yy40:
+yy53:
 	yych = *++YYCURSOR;
 	if (yych <= '/') goto yy18;
 	if (yych >= ':') goto yy18;
-yy41:
+yy54:
 	++YYCURSOR;
 	if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
 	yych = *YYCURSOR;
 	if (yych <= '/') goto yy18;
-	if (yych <= '9') goto yy41;
-	if (yych >= ';') goto yy18;
+	if (yych <= '9') goto yy54;
+	if (yych <= ':') goto yy78;
+	goto yy18;
+yy56:
 	yych = *++YYCURSOR;
-	if (yych != '"') goto yy18;
+	if (yych <= '/') goto yy18;
+	if (yych >= ':') goto yy18;
+yy57:
 	++YYCURSOR;
-#line 735 "ext/standard/var_unserializer.re"
-	{
-	size_t len, maxlen;
-	zend_string *str;
-
-	len = parse_uiv(start + 2);
-	maxlen = max - YYCURSOR;
-	if (maxlen < len) {
-		*p = start + 2;
-		return 0;
-	}
-
-	if ((str = unserialize_str(&YYCURSOR, len, maxlen)) == NULL) {
-		return 0;
-	}
-
-	if (*(YYCURSOR) != '"') {
-		zend_string_free(str);
-		*p = YYCURSOR;
-		return 0;
-	}
-
-	if (*(YYCURSOR + 1) != ';') {
-		efree(str);
-		*p = YYCURSOR + 1;
-		return 0;
-	}
-
-	YYCURSOR += 2;
-	*p = YYCURSOR;
-
-	ZVAL_STR(rval, str);
-	return 1;
-}
-#line 1014 "ext/standard/var_unserializer.c"
-yy46:
-	yych = *++YYCURSOR;
-	if (yych == '+') goto yy47;
+	if (YYLIMIT <= YYCURSOR) YYFILL(1);
+	yych = *YYCURSOR;
 	if (yych <= '/') goto yy18;
-	if (yych <= '9') goto yy48;
+	if (yych <= '9') goto yy57;
+	if (yych == ';') goto yy79;
 	goto yy18;
-yy47:
+yy59:
 	yych = *++YYCURSOR;
 	if (yych <= '/') goto yy18;
 	if (yych >= ':') goto yy18;
-yy48:
+yy60:
 	++YYCURSOR;
 	if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
 	yych = *YYCURSOR;
 	if (yych <= '/') goto yy18;
-	if (yych <= '9') goto yy48;
-	if (yych >= ';') goto yy18;
+	if (yych <= '9') goto yy60;
+	if (yych <= ':') goto yy81;
+	goto yy18;
+yy62:
 	yych = *++YYCURSOR;
-	if (yych != '"') goto yy18;
+	if (yych == '"') goto yy82;
+	goto yy18;
+yy63:
 	++YYCURSOR;
-#line 703 "ext/standard/var_unserializer.re"
+#line 580 "ext/standard/var_unserializer.re"
 	{
-	size_t len, maxlen;
-	char *str;
-
-	len = parse_uiv(start + 2);
-	maxlen = max - YYCURSOR;
-	if (maxlen < len) {
-		*p = start + 2;
-		return 0;
-	}
-
-	str = (char*)YYCURSOR;
+	zend_long id;
 
-	YYCURSOR += len;
+ 	*p = YYCURSOR;
+	if (!var_hash) return 0;
 
-	if (*(YYCURSOR) != '"') {
-		*p = YYCURSOR;
+	id = parse_iv(start + 2) - 1;
+	if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) {
 		return 0;
 	}
 
-	if (*(YYCURSOR + 1) != ';') {
-		*p = YYCURSOR + 1;
+	if (Z_ISUNDEF_P(rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P(Z_REFVAL_P(rval_ref)))) {
 		return 0;
 	}
 
-	YYCURSOR += 2;
-	*p = YYCURSOR;
+	if (Z_ISREF_P(rval_ref)) {
+		ZVAL_COPY(rval, rval_ref);
+	} else {
+		ZVAL_NEW_REF(rval_ref, rval_ref);
+		ZVAL_COPY(rval, rval_ref);
+	}
 
-	ZVAL_STRINGL(rval, str, len);
 	return 1;
 }
-#line 1067 "ext/standard/var_unserializer.c"
-yy53:
-	yych = *++YYCURSOR;
-	if (yych <= '/') {
-		if (yych <= ',') {
-			if (yych == '+') goto yy57;
-			goto yy18;
-		} else {
-			if (yych <= '-') goto yy55;
-			if (yych <= '.') goto yy60;
-			goto yy18;
-		}
-	} else {
-		if (yych <= 'I') {
-			if (yych <= '9') goto yy58;
-			if (yych <= 'H') goto yy18;
-			goto yy56;
-		} else {
-			if (yych != 'N') goto yy18;
-		}
-	}
+#line 982 "ext/standard/var_unserializer.c"
+yy65:
 	yych = *++YYCURSOR;
-	if (yych == 'A') goto yy76;
+	if (yych == '"') goto yy84;
 	goto yy18;
-yy55:
-	yych = *++YYCURSOR;
-	if (yych <= '/') {
-		if (yych == '.') goto yy60;
-		goto yy18;
-	} else {
-		if (yych <= '9') goto yy58;
-		if (yych != 'I') goto yy18;
-	}
-yy56:
+yy66:
 	yych = *++YYCURSOR;
-	if (yych == 'N') goto yy72;
+	if (yych == '{') goto yy86;
 	goto yy18;
-yy57:
-	yych = *++YYCURSOR;
-	if (yych == '.') goto yy60;
-	if (yych <= '/') goto yy18;
-	if (yych >= ':') goto yy18;
-yy58:
+yy67:
 	++YYCURSOR;
-	if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
-	yych = *YYCURSOR;
-	if (yych <= ':') {
-		if (yych <= '.') {
-			if (yych <= '-') goto yy18;
-			goto yy70;
-		} else {
-			if (yych <= '/') goto yy18;
-			if (yych <= '9') goto yy58;
-			goto yy18;
-		}
-	} else {
-		if (yych <= 'E') {
-			if (yych <= ';') goto yy63;
-			if (yych <= 'D') goto yy18;
-			goto yy65;
-		} else {
-			if (yych == 'e') goto yy65;
-			goto yy18;
-		}
-	}
-yy60:
-	yych = *++YYCURSOR;
-	if (yych <= '/') goto yy18;
-	if (yych >= ':') goto yy18;
-yy61:
+#line 635 "ext/standard/var_unserializer.re"
+	{
+	*p = YYCURSOR;
+	ZVAL_BOOL(rval, parse_iv(start + 2));
+	return 1;
+}
+#line 999 "ext/standard/var_unserializer.c"
+yy69:
 	++YYCURSOR;
 	if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
 	yych = *YYCURSOR;
 	if (yych <= ';') {
 		if (yych <= '/') goto yy18;
-		if (yych <= '9') goto yy61;
+		if (yych <= '9') goto yy69;
 		if (yych <= ':') goto yy18;
 	} else {
 		if (yych <= 'E') {
 			if (yych <= 'D') goto yy18;
-			goto yy65;
+			goto yy73;
 		} else {
-			if (yych == 'e') goto yy65;
+			if (yych == 'e') goto yy73;
 			goto yy18;
 		}
 	}
-yy63:
+yy71:
 	++YYCURSOR;
-#line 694 "ext/standard/var_unserializer.re"
+#line 683 "ext/standard/var_unserializer.re"
 	{
 #if SIZEOF_ZEND_LONG == 4
 use_double:
@@ -1160,257 +1024,406 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
 	ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL));
 	return 1;
 }
-#line 1164 "ext/standard/var_unserializer.c"
-yy65:
+#line 1028 "ext/standard/var_unserializer.c"
+yy73:
 	yych = *++YYCURSOR;
 	if (yych <= ',') {
-		if (yych != '+') goto yy18;
+		if (yych == '+') goto yy88;
+		goto yy18;
 	} else {
-		if (yych <= '-') goto yy66;
+		if (yych <= '-') goto yy88;
 		if (yych <= '/') goto yy18;
-		if (yych <= '9') goto yy67;
+		if (yych <= '9') goto yy89;
 		goto yy18;
 	}
-yy66:
+yy74:
 	yych = *++YYCURSOR;
-	if (yych <= ',') {
-		if (yych == '+') goto yy69;
-		goto yy18;
-	} else {
-		if (yych <= '-') goto yy69;
-		if (yych <= '/') goto yy18;
-		if (yych >= ':') goto yy18;
-	}
-yy67:
-	++YYCURSOR;
-	if (YYLIMIT <= YYCURSOR) YYFILL(1);
-	yych = *YYCURSOR;
-	if (yych <= '/') goto yy18;
-	if (yych <= '9') goto yy67;
-	if (yych == ';') goto yy63;
+	if (yych == 'F') goto yy91;
 	goto yy18;
-yy69:
+yy75:
 	yych = *++YYCURSOR;
-	if (yych <= '/') goto yy18;
-	if (yych <= '9') goto yy67;
+	if (yych == 'N') goto yy91;
 	goto yy18;
-yy70:
+yy76:
 	++YYCURSOR;
-	if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
-	yych = *YYCURSOR;
-	if (yych <= ';') {
-		if (yych <= '/') goto yy18;
-		if (yych <= '9') goto yy70;
-		if (yych <= ':') goto yy18;
-		goto yy63;
-	} else {
-		if (yych <= 'E') {
-			if (yych <= 'D') goto yy18;
-			goto yy65;
+#line 641 "ext/standard/var_unserializer.re"
+	{
+#if SIZEOF_ZEND_LONG == 4
+	int digits = YYCURSOR - start - 3;
+
+	if (start[2] == '-' || start[2] == '+') {
+		digits--;
+	}
+
+	/* Use double for large zend_long values that were serialized on a 64-bit system */
+	if (digits >= MAX_LENGTH_OF_LONG - 1) {
+		if (digits == MAX_LENGTH_OF_LONG - 1) {
+			int cmp = strncmp((char*)YYCURSOR - MAX_LENGTH_OF_LONG, long_min_digits, MAX_LENGTH_OF_LONG - 1);
+
+			if (!(cmp < 0 || (cmp == 0 && start[2] == '-'))) {
+				goto use_double;
+			}
 		} else {
-			if (yych == 'e') goto yy65;
-			goto yy18;
+			goto use_double;
 		}
 	}
-yy72:
-	yych = *++YYCURSOR;
-	if (yych != 'F') goto yy18;
-yy73:
+#endif
+	*p = YYCURSOR;
+	ZVAL_LONG(rval, parse_iv(start + 2));
+	return 1;
+}
+#line 1076 "ext/standard/var_unserializer.c"
+yy78:
 	yych = *++YYCURSOR;
-	if (yych != ';') goto yy18;
+	if (yych == '"') goto yy92;
+	goto yy18;
+yy79:
 	++YYCURSOR;
-#line 678 "ext/standard/var_unserializer.re"
+#line 605 "ext/standard/var_unserializer.re"
 	{
-	*p = YYCURSOR;
+	zend_long id;
 
-	if (!strncmp((char*)start + 2, "NAN", 3)) {
-		ZVAL_DOUBLE(rval, php_get_nan());
-	} else if (!strncmp((char*)start + 2, "INF", 3)) {
-		ZVAL_DOUBLE(rval, php_get_inf());
-	} else if (!strncmp((char*)start + 2, "-INF", 4)) {
-		ZVAL_DOUBLE(rval, -php_get_inf());
-	} else {
-		ZVAL_NULL(rval);
+ 	*p = YYCURSOR;
+	if (!var_hash) return 0;
+
+	id = parse_iv(start + 2) - 1;
+	if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) {
+		return 0;
+	}
+
+	if (rval_ref == rval) {
+		return 0;
 	}
 
+	if (Z_ISUNDEF_P(rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P(Z_REFVAL_P(rval_ref)))) {
+		return 0;
+	}
+
+	ZVAL_COPY(rval, rval_ref);
+
 	return 1;
 }
-#line 1239 "ext/standard/var_unserializer.c"
-yy76:
+#line 1107 "ext/standard/var_unserializer.c"
+yy81:
 	yych = *++YYCURSOR;
-	if (yych == 'N') goto yy73;
+	if (yych == '"') goto yy94;
 	goto yy18;
-yy77:
-	yych = *++YYCURSOR;
-	if (yych <= ',') {
-		if (yych != '+') goto yy18;
-	} else {
-		if (yych <= '-') goto yy78;
-		if (yych <= '/') goto yy18;
-		if (yych <= '9') goto yy79;
-		goto yy18;
-	}
-yy78:
-	yych = *++YYCURSOR;
-	if (yych <= '/') goto yy18;
-	if (yych >= ':') goto yy18;
-yy79:
+yy82:
 	++YYCURSOR;
-	if (YYLIMIT <= YYCURSOR) YYFILL(1);
-	yych = *YYCURSOR;
-	if (yych <= '/') goto yy18;
-	if (yych <= '9') goto yy79;
-	if (yych != ';') goto yy18;
-	++YYCURSOR;
-#line 652 "ext/standard/var_unserializer.re"
+#line 793 "ext/standard/var_unserializer.re"
 	{
-#if SIZEOF_ZEND_LONG == 4
-	int digits = YYCURSOR - start - 3;
+	size_t len, len2, len3, maxlen;
+	zend_long elements;
+	char *str;
+	zend_string *class_name;
+	zend_class_entry *ce;
+	int incomplete_class = 0;
 
-	if (start[2] == '-' || start[2] == '+') {
-		digits--;
+	int custom_object = 0;
+
+	zval user_func;
+	zval retval;
+	zval args[1];
+
+    if (!var_hash) return 0;
+	if (*start == 'C') {
+		custom_object = 1;
 	}
 
-	/* Use double for large zend_long values that were serialized on a 64-bit system */
-	if (digits >= MAX_LENGTH_OF_LONG - 1) {
-		if (digits == MAX_LENGTH_OF_LONG - 1) {
-			int cmp = strncmp((char*)YYCURSOR - MAX_LENGTH_OF_LONG, long_min_digits, MAX_LENGTH_OF_LONG - 1);
+	len2 = len = parse_uiv(start + 2);
+	maxlen = max - YYCURSOR;
+	if (maxlen < len || len == 0) {
+		*p = start + 2;
+		return 0;
+	}
 
-			if (!(cmp < 0 || (cmp == 0 && start[2] == '-'))) {
-				goto use_double;
+	str = (char*)YYCURSOR;
+
+	YYCURSOR += len;
+
+	if (*(YYCURSOR) != '"') {
+		*p = YYCURSOR;
+		return 0;
+	}
+	if (*(YYCURSOR+1) != ':') {
+		*p = YYCURSOR+1;
+		return 0;
+	}
+
+	len3 = strspn(str, "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377\\");
+	if (len3 != len)
+	{
+		*p = YYCURSOR + len3 - len;
+		return 0;
+	}
+
+	class_name = zend_string_init(str, len, 0);
+
+	do {
+		if(!unserialize_allowed_class(class_name, classes)) {
+			incomplete_class = 1;
+			ce = PHP_IC_ENTRY;
+			break;
+		}
+
+		/* Try to find class directly */
+		BG(serialize_lock)++;
+		ce = zend_lookup_class(class_name);
+		if (ce) {
+			BG(serialize_lock)--;
+			if (EG(exception)) {
+				zend_string_release(class_name);
+				return 0;
 			}
-		} else {
-			goto use_double;
+			break;
 		}
-	}
-#endif
+		BG(serialize_lock)--;
+
+		if (EG(exception)) {
+			zend_string_release(class_name);
+			return 0;
+		}
+
+		/* Check for unserialize callback */
+		if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
+			incomplete_class = 1;
+			ce = PHP_IC_ENTRY;
+			break;
+		}
+
+		/* Call unserialize callback */
+		ZVAL_STRING(&user_func, PG(unserialize_callback_func));
+
+		ZVAL_STR_COPY(&args[0], class_name);
+		BG(serialize_lock)++;
+		if (call_user_function_ex(CG(function_table), NULL, &user_func, &retval, 1, args, 0, NULL) != SUCCESS) {
+			BG(serialize_lock)--;
+			if (EG(exception)) {
+				zend_string_release(class_name);
+				zval_ptr_dtor(&user_func);
+				zval_ptr_dtor(&args[0]);
+				return 0;
+			}
+			php_error_docref(NULL, E_WARNING, "defined (%s) but not found", Z_STRVAL(user_func));
+			incomplete_class = 1;
+			ce = PHP_IC_ENTRY;
+			zval_ptr_dtor(&user_func);
+			zval_ptr_dtor(&args[0]);
+			break;
+		}
+		BG(serialize_lock)--;
+		zval_ptr_dtor(&retval);
+		if (EG(exception)) {
+			zend_string_release(class_name);
+			zval_ptr_dtor(&user_func);
+			zval_ptr_dtor(&args[0]);
+			return 0;
+		}
+
+		/* The callback function may have defined the class */
+		BG(serialize_lock)++;
+		if ((ce = zend_lookup_class(class_name)) == NULL) {
+			php_error_docref(NULL, E_WARNING, "Function %s() hasn't defined the class it was called for", Z_STRVAL(user_func));
+			incomplete_class = 1;
+			ce = PHP_IC_ENTRY;
+		}
+		BG(serialize_lock)--;
+
+		zval_ptr_dtor(&user_func);
+		zval_ptr_dtor(&args[0]);
+		break;
+	} while (1);
+
 	*p = YYCURSOR;
-	ZVAL_LONG(rval, parse_iv(start + 2));
-	return 1;
+
+	if (custom_object) {
+		int ret;
+
+		ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
+
+		if (ret && incomplete_class) {
+			php_store_class_name(rval, ZSTR_VAL(class_name), len2);
+		}
+		zend_string_release(class_name);
+		return ret;
+	}
+
+	elements = object_common1(UNSERIALIZE_PASSTHRU, ce);
+
+	if (elements < 0) {
+	   zend_string_release(class_name);
+	   return 0;
+	}
+
+	if (incomplete_class) {
+		php_store_class_name(rval, ZSTR_VAL(class_name), len2);
+	}
+	zend_string_release(class_name);
+
+	return object_common2(UNSERIALIZE_PASSTHRU, elements);
 }
-#line 1292 "ext/standard/var_unserializer.c"
-yy83:
-	yych = *++YYCURSOR;
-	if (yych <= '/') goto yy18;
-	if (yych >= '2') goto yy18;
-	yych = *++YYCURSOR;
-	if (yych != ';') goto yy18;
+#line 1266 "ext/standard/var_unserializer.c"
+yy84:
 	++YYCURSOR;
-#line 646 "ext/standard/var_unserializer.re"
+#line 724 "ext/standard/var_unserializer.re"
 	{
+	size_t len, maxlen;
+	zend_string *str;
+
+	len = parse_uiv(start + 2);
+	maxlen = max - YYCURSOR;
+	if (maxlen < len) {
+		*p = start + 2;
+		return 0;
+	}
+
+	if ((str = unserialize_str(&YYCURSOR, len, maxlen)) == NULL) {
+		return 0;
+	}
+
+	if (*(YYCURSOR) != '"') {
+		zend_string_free(str);
+		*p = YYCURSOR;
+		return 0;
+	}
+
+	if (*(YYCURSOR + 1) != ';') {
+		efree(str);
+		*p = YYCURSOR + 1;
+		return 0;
+	}
+
+	YYCURSOR += 2;
 	*p = YYCURSOR;
-	ZVAL_BOOL(rval, parse_iv(start + 2));
+
+	ZVAL_STR(rval, str);
 	return 1;
 }
-#line 1306 "ext/standard/var_unserializer.c"
-yy87:
+#line 1303 "ext/standard/var_unserializer.c"
+yy86:
 	++YYCURSOR;
-#line 640 "ext/standard/var_unserializer.re"
+#line 758 "ext/standard/var_unserializer.re"
 	{
+	zend_long elements = parse_iv(start + 2);
+	/* use iv() not uiv() in order to check data range */
 	*p = YYCURSOR;
-	ZVAL_NULL(rval);
-	return 1;
+    if (!var_hash) return 0;
+
+	if (elements < 0 || elements >= HT_MAX_SIZE) {
+		return 0;
+	}
+
+	array_init_size(rval, elements);
+	if (elements) {
+		/* we can't convert from packed to hash during unserialization, because
+		   reference to some zvals might be keept in var_hash (to support references) */
+		zend_hash_real_init(Z_ARRVAL_P(rval), 0);
+	}
+
+	if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements, 0)) {
+		return 0;
+	}
+
+	return finish_nested_data(UNSERIALIZE_PASSTHRU);
 }
-#line 1315 "ext/standard/var_unserializer.c"
-yy89:
+#line 1330 "ext/standard/var_unserializer.c"
+yy88:
 	yych = *++YYCURSOR;
 	if (yych <= ',') {
-		if (yych != '+') goto yy18;
+		if (yych == '+') goto yy96;
+		goto yy18;
 	} else {
-		if (yych <= '-') goto yy90;
+		if (yych <= '-') goto yy96;
 		if (yych <= '/') goto yy18;
-		if (yych <= '9') goto yy91;
-		goto yy18;
+		if (yych >= ':') goto yy18;
 	}
-yy90:
-	yych = *++YYCURSOR;
-	if (yych <= '/') goto yy18;
-	if (yych >= ':') goto yy18;
-yy91:
+yy89:
 	++YYCURSOR;
 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
 	yych = *YYCURSOR;
 	if (yych <= '/') goto yy18;
-	if (yych <= '9') goto yy91;
-	if (yych != ';') goto yy18;
+	if (yych <= '9') goto yy89;
+	if (yych == ';') goto yy71;
+	goto yy18;
+yy91:
+	yych = *++YYCURSOR;
+	if (yych == ';') goto yy97;
+	goto yy18;
+yy92:
 	++YYCURSOR;
-#line 615 "ext/standard/var_unserializer.re"
+#line 782 "ext/standard/var_unserializer.re"
 	{
-	zend_long id;
+	zend_long elements;
+    if (!var_hash) return 0;
 
- 	*p = YYCURSOR;
-	if (!var_hash) return 0;
+	elements = object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR);
+	if (elements < 0 || elements >= HT_MAX_SIZE) {
+		return 0;
+	}
+	return object_common2(UNSERIALIZE_PASSTHRU, elements);
+}
+#line 1366 "ext/standard/var_unserializer.c"
+yy94:
+	++YYCURSOR;
+#line 692 "ext/standard/var_unserializer.re"
+	{
+	size_t len, maxlen;
+	char *str;
 
-	id = parse_iv(start + 2) - 1;
-	if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) {
+	len = parse_uiv(start + 2);
+	maxlen = max - YYCURSOR;
+	if (maxlen < len) {
+		*p = start + 2;
 		return 0;
 	}
 
-	if (rval_ref == rval) {
+	str = (char*)YYCURSOR;
+
+	YYCURSOR += len;
+
+	if (*(YYCURSOR) != '"') {
+		*p = YYCURSOR;
 		return 0;
 	}
 
-	if (Z_ISUNDEF_P(rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P(Z_REFVAL_P(rval_ref)))) {
-		ZVAL_UNDEF(rval);
-		return 1;
+	if (*(YYCURSOR + 1) != ';') {
+		*p = YYCURSOR + 1;
+		return 0;
 	}
 
-	ZVAL_COPY(rval, rval_ref);
+	YYCURSOR += 2;
+	*p = YYCURSOR;
 
+	ZVAL_STRINGL(rval, str, len);
 	return 1;
 }
-#line 1363 "ext/standard/var_unserializer.c"
-yy95:
-	yych = *++YYCURSOR;
-	if (yych <= ',') {
-		if (yych != '+') goto yy18;
-	} else {
-		if (yych <= '-') goto yy96;
-		if (yych <= '/') goto yy18;
-		if (yych <= '9') goto yy97;
-		goto yy18;
-	}
+#line 1401 "ext/standard/var_unserializer.c"
 yy96:
 	yych = *++YYCURSOR;
 	if (yych <= '/') goto yy18;
-	if (yych >= ':') goto yy18;
+	if (yych <= '9') goto yy89;
+	goto yy18;
 yy97:
 	++YYCURSOR;
-	if (YYLIMIT <= YYCURSOR) YYFILL(1);
-	yych = *YYCURSOR;
-	if (yych <= '/') goto yy18;
-	if (yych <= '9') goto yy97;
-	if (yych != ';') goto yy18;
-	++YYCURSOR;
-#line 589 "ext/standard/var_unserializer.re"
+#line 667 "ext/standard/var_unserializer.re"
 	{
-	zend_long id;
-
- 	*p = YYCURSOR;
-	if (!var_hash) return 0;
-
-	id = parse_iv(start + 2) - 1;
-	if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) {
-		return 0;
-	}
+	*p = YYCURSOR;
 
-	zval_ptr_dtor(rval);
-	if (Z_ISUNDEF_P(rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P(Z_REFVAL_P(rval_ref)))) {
-		ZVAL_UNDEF(rval);
-		return 1;
-	}
-	if (Z_ISREF_P(rval_ref)) {
-		ZVAL_COPY(rval, rval_ref);
+	if (!strncmp((char*)start + 2, "NAN", 3)) {
+		ZVAL_DOUBLE(rval, php_get_nan());
+	} else if (!strncmp((char*)start + 2, "INF", 3)) {
+		ZVAL_DOUBLE(rval, php_get_inf());
+	} else if (!strncmp((char*)start + 2, "-INF", 4)) {
+		ZVAL_DOUBLE(rval, -php_get_inf());
 	} else {
-		ZVAL_NEW_REF(rval_ref, rval_ref);
-		ZVAL_COPY(rval, rval_ref);
+		ZVAL_NULL(rval);
 	}
 
 	return 1;
 }
-#line 1412 "ext/standard/var_unserializer.c"
+#line 1425 "ext/standard/var_unserializer.c"
 }
-#line 964 "ext/standard/var_unserializer.re"
+#line 953 "ext/standard/var_unserializer.re"
 
 
 	return 0;

programming_language: C
filename: var_unserializer.re
change_type: ModificationType.MODIFY
diff: @@ -409,16 +409,7 @@ string_key:
 			return 0;
 		}
 
-		if (UNEXPECTED(Z_ISUNDEF_P(data))) {
-			if (Z_TYPE(key) == IS_LONG) {
-				zend_hash_index_del(ht, Z_LVAL(key));
-			} else {
-				zend_hash_del_ind(ht, Z_STR(key));
-			}
-		} else {
-			var_push_dtor(var_hash, data);
-		}
-
+		var_push_dtor(var_hash, data);
 		zval_dtor(&key);
 
 		if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
@@ -597,11 +588,10 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
 		return 0;
 	}
 
-	zval_ptr_dtor(rval);
 	if (Z_ISUNDEF_P(rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P(Z_REFVAL_P(rval_ref)))) {
-		ZVAL_UNDEF(rval);
-		return 1;
+		return 0;
 	}
+
 	if (Z_ISREF_P(rval_ref)) {
 		ZVAL_COPY(rval, rval_ref);
 	} else {
@@ -628,8 +618,7 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
 	}
 
 	if (Z_ISUNDEF_P(rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P(Z_REFVAL_P(rval_ref)))) {
-		ZVAL_UNDEF(rval);
-		return 1;
+		return 0;
 	}
 
 	ZVAL_COPY(rval, rval_ref);

programming_language: C