You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

1474 lines
31 KiB

From: Markus Koschany <apo@debian.org>
Date: Sun, 19 Mar 2017 20:45:23 +0100
Subject: CVE-2016-7479
var_unserializer.c was recreated with the re2c tool in Wheezy.
Origin: https://git.php.net/?p=php-src.git;a=commit;h=0426b916df396a23e5c34514e4f2f0627efdcdf0
---
ext/standard/var_unserializer.c | 964 ++++++++++++++++++++++++++++-----------
ext/standard/var_unserializer.re | 84 ++--
2 files changed, 745 insertions(+), 303 deletions(-)
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c
index bb0301c..22594ad 100644
--- a/ext/standard/var_unserializer.c
+++ b/ext/standard/var_unserializer.c
@@ -1,4 +1,5 @@
-/* Generated by re2c 0.13.7.5 on Mon Aug 31 23:15:46 2015 */
+/* Generated by re2c 0.13.5 on Sun Mar 19 22:57:00 2017 */
+#line 1 "ext/standard/var_unserializer.re"
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
@@ -28,6 +29,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;
@@ -58,12 +64,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;
@@ -85,8 +91,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)
@@ -164,6 +176,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
@@ -178,10 +193,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);
@@ -241,6 +281,7 @@ static char *unserialize_str(const unsigned char **p, size_t *len, size_t maxlen
#define YYMARKER marker
+#line 289 "ext/standard/var_unserializer.re"
@@ -434,19 +475,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;
}
@@ -456,20 +494,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);
@@ -500,42 +534,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
+#line 538 "<stdout>"
{
YYCTYPE yych;
- static const unsigned char yybm[] = {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- };
if ((YYLIMIT - YYCURSOR) < 7) YYFILL(7);
yych = *YYCURSOR;
@@ -557,86 +558,147 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
}
yy2:
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == ':') goto yy95;
+ switch (yych) {
+ case ':': goto yy95;
+ default: goto yy3;
+ }
yy3:
+#line 901 "ext/standard/var_unserializer.re"
{ return 0; }
+#line 569 "<stdout>"
yy4:
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == ':') goto yy89;
- goto yy3;
+ switch (yych) {
+ case ':': goto yy89;
+ default: goto yy3;
+ }
yy5:
yych = *++YYCURSOR;
- if (yych == ';') goto yy87;
- goto yy3;
+ switch (yych) {
+ case ';': goto yy87;
+ default: goto yy3;
+ }
yy6:
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == ':') goto yy83;
- goto yy3;
+ switch (yych) {
+ case ':': goto yy83;
+ default: goto yy3;
+ }
yy7:
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == ':') goto yy77;
- goto yy3;
+ switch (yych) {
+ case ':': goto yy77;
+ default: goto yy3;
+ }
yy8:
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == ':') goto yy53;
- goto yy3;
+ switch (yych) {
+ case ':': goto yy53;
+ default: goto yy3;
+ }
yy9:
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == ':') goto yy46;
- goto yy3;
+ switch (yych) {
+ case ':': goto yy46;
+ default: goto yy3;
+ }
yy10:
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == ':') goto yy39;
- goto yy3;
+ switch (yych) {
+ case ':': goto yy39;
+ default: goto yy3;
+ }
yy11:
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == ':') goto yy32;
- goto yy3;
+ switch (yych) {
+ case ':': goto yy32;
+ default: goto yy3;
+ }
yy12:
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == ':') goto yy25;
- goto yy3;
+ switch (yych) {
+ case ':': goto yy25;
+ default: goto yy3;
+ }
yy13:
yych = *(YYMARKER = ++YYCURSOR);
- if (yych == ':') goto yy17;
- goto yy3;
+ switch (yych) {
+ case ':': goto yy17;
+ default: goto yy3;
+ }
yy14:
++YYCURSOR;
+#line 895 "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 638 "<stdout>"
yy16:
yych = *++YYCURSOR;
goto yy3;
yy17:
yych = *++YYCURSOR;
- if (yybm[0+yych] & 128) {
- goto yy20;
+ switch (yych) {
+ case '+': goto yy19;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy20;
+ default: goto yy18;
}
- if (yych == '+') goto yy19;
yy18:
YYCURSOR = YYMARKER;
goto yy3;
yy19:
yych = *++YYCURSOR;
- if (yybm[0+yych] & 128) {
- goto yy20;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy20;
+ default: goto yy18;
}
- goto yy18;
yy20:
++YYCURSOR;
if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
yych = *YYCURSOR;
- if (yybm[0+yych] & 128) {
- goto yy20;
- }
- if (yych <= '/') goto yy18;
- if (yych >= ';') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy20;
+ case ':': goto yy22;
+ default: goto yy18;
+ }
+yy22:
yych = *++YYCURSOR;
- if (yych != '"') goto yy18;
+ switch (yych) {
+ case '"': goto yy23;
+ default: goto yy18;
+ }
+yy23:
++YYCURSOR;
+#line 743 "ext/standard/var_unserializer.re"
{
size_t len, len2, len3, maxlen;
long elements;
@@ -788,30 +850,66 @@ yy20:
return object_common2(UNSERIALIZE_PASSTHRU, elements);
}
+#line 854 "<stdout>"
yy25:
yych = *++YYCURSOR;
- if (yych <= ',') {
- if (yych != '+') goto yy18;
- } else {
- if (yych <= '-') goto yy26;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy27;
- goto yy18;
+ switch (yych) {
+ case '+':
+ case '-': goto yy26;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy27;
+ default: goto yy18;
}
yy26:
yych = *++YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych >= ':') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy27;
+ default: goto yy18;
+ }
yy27:
++YYCURSOR;
if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
yych = *YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy27;
- if (yych >= ';') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy27;
+ case ':': goto yy29;
+ default: goto yy18;
+ }
+yy29:
yych = *++YYCURSOR;
- if (yych != '"') goto yy18;
+ switch (yych) {
+ case '"': goto yy30;
+ default: goto yy18;
+ }
+yy30:
++YYCURSOR;
+#line 730 "ext/standard/var_unserializer.re"
{
long elements;
if (!var_hash) return 0;
@@ -824,26 +922,65 @@ yy27:
}
return object_common2(UNSERIALIZE_PASSTHRU, elements);
}
+#line 926 "<stdout>"
yy32:
yych = *++YYCURSOR;
- if (yych == '+') goto yy33;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy34;
- goto yy18;
+ switch (yych) {
+ case '+': goto yy33;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy34;
+ default: goto yy18;
+ }
yy33:
yych = *++YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych >= ':') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy34;
+ default: goto yy18;
+ }
yy34:
++YYCURSOR;
if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
yych = *YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy34;
- if (yych >= ';') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy34;
+ case ':': goto yy36;
+ default: goto yy18;
+ }
+yy36:
yych = *++YYCURSOR;
- if (yych != '{') goto yy18;
+ switch (yych) {
+ case '{': goto yy37;
+ default: goto yy18;
+ }
+yy37:
++YYCURSOR;
+#line 709 "ext/standard/var_unserializer.re"
{
long elements = parse_iv(start + 2);
/* use iv() not uiv() in order to check data range */
@@ -864,26 +1001,65 @@ yy34:
return finish_nested_data(UNSERIALIZE_PASSTHRU);
}
+#line 1005 "<stdout>"
yy39:
yych = *++YYCURSOR;
- if (yych == '+') goto yy40;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy41;
- goto yy18;
+ switch (yych) {
+ case '+': goto yy40;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy41;
+ default: goto yy18;
+ }
yy40:
yych = *++YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych >= ':') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy41;
+ default: goto yy18;
+ }
yy41:
++YYCURSOR;
if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
yych = *YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy41;
- if (yych >= ';') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy41;
+ case ':': goto yy43;
+ default: goto yy18;
+ }
+yy43:
yych = *++YYCURSOR;
- if (yych != '"') goto yy18;
+ switch (yych) {
+ case '"': goto yy44;
+ default: goto yy18;
+ }
+yy44:
++YYCURSOR;
+#line 680 "ext/standard/var_unserializer.re"
{
size_t len, maxlen;
char *str;
@@ -912,26 +1088,65 @@ yy41:
ZVAL_STRINGL(*rval, str, len, 0);
return 1;
}
+#line 1092 "<stdout>"
yy46:
yych = *++YYCURSOR;
- if (yych == '+') goto yy47;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy48;
- goto yy18;
+ switch (yych) {
+ case '+': goto yy47;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy48;
+ default: goto yy18;
+ }
yy47:
yych = *++YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych >= ':') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy48;
+ default: goto yy18;
+ }
yy48:
++YYCURSOR;
if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
yych = *YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy48;
- if (yych >= ';') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy48;
+ case ':': goto yy50;
+ default: goto yy18;
+ }
+yy50:
yych = *++YYCURSOR;
- if (yych != '"') goto yy18;
+ switch (yych) {
+ case '"': goto yy51;
+ default: goto yy18;
+ }
+yy51:
++YYCURSOR;
+#line 652 "ext/standard/var_unserializer.re"
{
size_t len, maxlen;
char *str;
@@ -959,93 +1174,131 @@ yy48:
ZVAL_STRINGL(*rval, str, len, 1);
return 1;
}
+#line 1178 "<stdout>"
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;
- }
- }
+ switch (yych) {
+ case '+': goto yy57;
+ case '-': goto yy55;
+ case '.': goto yy60;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy58;
+ case 'I': goto yy56;
+ case 'N': goto yy54;
+ default: goto yy18;
+ }
+yy54:
yych = *++YYCURSOR;
- if (yych == 'A') goto yy76;
- goto yy18;
+ switch (yych) {
+ case 'A': goto yy76;
+ default: goto yy18;
+ }
yy55:
yych = *++YYCURSOR;
- if (yych <= '/') {
- if (yych == '.') goto yy60;
- goto yy18;
- } else {
- if (yych <= '9') goto yy58;
- if (yych != 'I') goto yy18;
+ switch (yych) {
+ case '.': goto yy60;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy58;
+ case 'I': goto yy56;
+ default: goto yy18;
}
yy56:
yych = *++YYCURSOR;
- if (yych == 'N') goto yy72;
- goto yy18;
+ switch (yych) {
+ case 'N': goto yy72;
+ default: goto yy18;
+ }
yy57:
yych = *++YYCURSOR;
- if (yych == '.') goto yy60;
- if (yych <= '/') goto yy18;
- if (yych >= ':') goto yy18;
+ switch (yych) {
+ case '.': goto yy60;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy58;
+ default: goto yy18;
+ }
yy58:
++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;
- }
+ switch (yych) {
+ case '.': goto yy70;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy58;
+ case ';': goto yy63;
+ case 'E':
+ case 'e': goto yy65;
+ default: goto yy18;
}
yy60:
yych = *++YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych >= ':') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy61;
+ default: goto yy18;
+ }
yy61:
++YYCURSOR;
if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
yych = *YYCURSOR;
- if (yych <= ';') {
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy61;
- if (yych <= ':') goto yy18;
- } else {
- if (yych <= 'E') {
- if (yych <= 'D') goto yy18;
- goto yy65;
- } else {
- if (yych == 'e') goto yy65;
- goto yy18;
- }
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy61;
+ case ';': goto yy63;
+ case 'E':
+ case 'e': goto yy65;
+ default: goto yy18;
}
yy63:
++YYCURSOR;
+#line 642 "ext/standard/var_unserializer.re"
{
#if SIZEOF_LONG == 4
use_double:
@@ -1055,64 +1308,109 @@ use_double:
ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
return 1;
}
+#line 1312 "<stdout>"
yy65:
yych = *++YYCURSOR;
- if (yych <= ',') {
- if (yych != '+') goto yy18;
- } else {
- if (yych <= '-') goto yy66;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy67;
- goto yy18;
+ switch (yych) {
+ case '+':
+ case '-': goto yy66;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy67;
+ default: goto yy18;
}
yy66:
yych = *++YYCURSOR;
- if (yych <= ',') {
- if (yych == '+') goto yy69;
- goto yy18;
- } else {
- if (yych <= '-') goto yy69;
- if (yych <= '/') goto yy18;
- if (yych >= ':') goto yy18;
+ switch (yych) {
+ case '+':
+ case '-': goto yy69;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy67;
+ default: goto yy18;
}
yy67:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy67;
- if (yych == ';') goto yy63;
- goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy67;
+ case ';': goto yy63;
+ default: goto yy18;
+ }
yy69:
yych = *++YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy67;
- goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy67;
+ default: goto yy18;
+ }
yy70:
++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;
- } else {
- if (yych == 'e') goto yy65;
- goto yy18;
- }
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy70;
+ case ';': goto yy63;
+ case 'E':
+ case 'e': goto yy65;
+ default: goto yy18;
}
yy72:
yych = *++YYCURSOR;
- if (yych != 'F') goto yy18;
+ switch (yych) {
+ case 'F': goto yy73;
+ default: goto yy18;
+ }
yy73:
yych = *++YYCURSOR;
- if (yych != ';') goto yy18;
+ switch (yych) {
+ case ';': goto yy74;
+ default: goto yy18;
+ }
+yy74:
++YYCURSOR;
+#line 627 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
INIT_PZVAL(*rval);
@@ -1127,32 +1425,66 @@ yy73:
return 1;
}
+#line 1429 "<stdout>"
yy76:
yych = *++YYCURSOR;
- if (yych == 'N') goto yy73;
- goto yy18;
+ switch (yych) {
+ case 'N': goto yy73;
+ default: 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;
+ switch (yych) {
+ case '+':
+ case '-': goto yy78;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy79;
+ default: goto yy18;
}
yy78:
yych = *++YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych >= ':') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy79;
+ default: goto yy18;
+ }
yy79:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy79;
- if (yych != ';') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy79;
+ case ';': goto yy81;
+ default: goto yy18;
+ }
+yy81:
++YYCURSOR;
+#line 600 "ext/standard/var_unserializer.re"
{
#if SIZEOF_LONG == 4
int digits = YYCURSOR - start - 3;
@@ -1179,49 +1511,93 @@ yy79:
ZVAL_LONG(*rval, parse_iv(start + 2));
return 1;
}
+#line 1515 "<stdout>"
yy83:
yych = *++YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych >= '2') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1': goto yy84;
+ default: goto yy18;
+ }
+yy84:
yych = *++YYCURSOR;
- if (yych != ';') goto yy18;
+ switch (yych) {
+ case ';': goto yy85;
+ default: goto yy18;
+ }
+yy85:
++YYCURSOR;
+#line 593 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
INIT_PZVAL(*rval);
ZVAL_BOOL(*rval, parse_iv(start + 2));
return 1;
}
+#line 1538 "<stdout>"
yy87:
++YYCURSOR;
+#line 586 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
INIT_PZVAL(*rval);
ZVAL_NULL(*rval);
return 1;
}
+#line 1548 "<stdout>"
yy89:
yych = *++YYCURSOR;
- if (yych <= ',') {
- if (yych != '+') goto yy18;
- } else {
- if (yych <= '-') goto yy90;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy91;
- goto yy18;
+ switch (yych) {
+ case '+':
+ case '-': goto yy90;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy91;
+ default: goto yy18;
}
yy90:
yych = *++YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych >= ':') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy91;
+ default: goto yy18;
+ }
yy91:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy91;
- if (yych != ';') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy91;
+ case ';': goto yy93;
+ default: goto yy18;
+ }
+yy93:
++YYCURSOR;
+#line 563 "ext/standard/var_unserializer.re"
{
long id;
@@ -1244,28 +1620,60 @@ yy91:
return 1;
}
+#line 1624 "<stdout>"
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;
+ switch (yych) {
+ case '+':
+ case '-': goto yy96;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy97;
+ default: goto yy18;
}
yy96:
yych = *++YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych >= ':') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy97;
+ default: goto yy18;
+ }
yy97:
++YYCURSOR;
if (YYLIMIT <= YYCURSOR) YYFILL(1);
yych = *YYCURSOR;
- if (yych <= '/') goto yy18;
- if (yych <= '9') goto yy97;
- if (yych != ';') goto yy18;
+ switch (yych) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': goto yy97;
+ case ';': goto yy99;
+ default: goto yy18;
+ }
+yy99:
++YYCURSOR;
+#line 542 "ext/standard/var_unserializer.re"
{
long id;
@@ -1286,7 +1694,9 @@ yy97:
return 1;
}
+#line 1698 "<stdout>"
}
+#line 903 "ext/standard/var_unserializer.re"
return 0;
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index 0302723..d4d5622 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -27,6 +27,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;
@@ -57,12 +62,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;
@@ -84,8 +89,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)
@@ -163,6 +174,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
@@ -177,10 +191,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);
@@ -440,19 +479,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;
}
@@ -462,20 +498,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);