1 /* Generated by re2c 1.0.1 */
2 /*
3   +----------------------------------------------------------------------+
4   | PHP Version 7                                                        |
5   +----------------------------------------------------------------------+
6   | Copyright (c) 1997-2018 The PHP Group                                |
7   +----------------------------------------------------------------------+
8   | This source file is subject to version 3.01 of the PHP license,      |
9   | that is bundled with this package in the file LICENSE, and is        |
10   | available through the world-wide-web at the following url:           |
11   | http://www.php.net/license/3_01.txt                                  |
12   | If you did not receive a copy of the PHP license and are unable to   |
13   | obtain it through the world-wide-web, please send a note to          |
14   | license@php.net so we can mail you a copy immediately.               |
15   +----------------------------------------------------------------------+
16   | Author: Sascha Schumann <sascha@schumann.cx>                         |
17   +----------------------------------------------------------------------+
18 */
19 
20 #include "php.h"
21 #include "ext/standard/php_var.h"
22 #include "php_incomplete_class.h"
23 #include "zend_portability.h"
24 
25 struct php_unserialize_data {
26 	void *first;
27 	void *last;
28 	void *first_dtor;
29 	void *last_dtor;
30 	HashTable *allowed_classes;
31 };
32 
php_var_unserialize_init()33 PHPAPI php_unserialize_data_t php_var_unserialize_init() {
34 	php_unserialize_data_t d;
35 	/* fprintf(stderr, "UNSERIALIZE_INIT    == lock: %u, level: %u\n", BG(serialize_lock), BG(unserialize).level); */
36 	if (BG(serialize_lock) || !BG(unserialize).level) {
37 		d = ecalloc(1, sizeof(struct php_unserialize_data));
38 		if (!BG(serialize_lock)) {
39 			BG(unserialize).data = d;
40 			BG(unserialize).level = 1;
41 		}
42 	} else {
43 		d = BG(unserialize).data;
44 		++BG(unserialize).level;
45 	}
46 	return d;
47 }
48 
php_var_unserialize_destroy(php_unserialize_data_t d)49 PHPAPI void php_var_unserialize_destroy(php_unserialize_data_t d) {
50 	/* fprintf(stderr, "UNSERIALIZE_DESTROY == lock: %u, level: %u\n", BG(serialize_lock), BG(unserialize).level); */
51 	if (BG(serialize_lock) || BG(unserialize).level == 1) {
52 		var_destroy(&d);
53 		efree(d);
54 	}
55 	if (!BG(serialize_lock) && !--BG(unserialize).level) {
56 		BG(unserialize).data = NULL;
57 	}
58 }
59 
php_var_unserialize_get_allowed_classes(php_unserialize_data_t d)60 PHPAPI HashTable *php_var_unserialize_get_allowed_classes(php_unserialize_data_t d) {
61 	return d->allowed_classes;
62 }
php_var_unserialize_set_allowed_classes(php_unserialize_data_t d,HashTable * classes)63 PHPAPI void php_var_unserialize_set_allowed_classes(php_unserialize_data_t d, HashTable *classes) {
64 	d->allowed_classes = classes;
65 }
66 
67 
68 /* {{{ reference-handling for unserializer: var_* */
69 #define VAR_ENTRIES_MAX 1024
70 #define VAR_ENTRIES_DBG 0
71 
72 /* VAR_FLAG used in var_dtor entries to signify an entry on which __wakeup should be called */
73 #define VAR_WAKEUP_FLAG 1
74 
75 typedef struct {
76 	zval *data[VAR_ENTRIES_MAX];
77 	zend_long used_slots;
78 	void *next;
79 } var_entries;
80 
81 typedef struct {
82 	zval data[VAR_ENTRIES_MAX];
83 	zend_long used_slots;
84 	void *next;
85 } var_dtor_entries;
86 
var_push(php_unserialize_data_t * var_hashx,zval * rval)87 static inline void var_push(php_unserialize_data_t *var_hashx, zval *rval)
88 {
89 	var_entries *var_hash = (*var_hashx)->last;
90 #if VAR_ENTRIES_DBG
91 	fprintf(stderr, "var_push(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_P(rval));
92 #endif
93 
94 	if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) {
95 		var_hash = emalloc(sizeof(var_entries));
96 		var_hash->used_slots = 0;
97 		var_hash->next = 0;
98 
99 		if (!(*var_hashx)->first) {
100 			(*var_hashx)->first = var_hash;
101 		} else {
102 			((var_entries *) (*var_hashx)->last)->next = var_hash;
103 		}
104 
105 		(*var_hashx)->last = var_hash;
106 	}
107 
108 	var_hash->data[var_hash->used_slots++] = rval;
109 }
110 
var_push_dtor(php_unserialize_data_t * var_hashx,zval * rval)111 PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval *rval)
112 {
113 	zval *tmp_var = var_tmp_var(var_hashx);
114     if (!tmp_var) {
115         return;
116     }
117 	ZVAL_COPY(tmp_var, rval);
118 }
119 
var_tmp_var(php_unserialize_data_t * var_hashx)120 PHPAPI zval *var_tmp_var(php_unserialize_data_t *var_hashx)
121 {
122     var_dtor_entries *var_hash;
123 
124     if (!var_hashx || !*var_hashx) {
125         return NULL;
126     }
127 
128     var_hash = (*var_hashx)->last_dtor;
129     if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) {
130         var_hash = emalloc(sizeof(var_dtor_entries));
131         var_hash->used_slots = 0;
132         var_hash->next = 0;
133 
134         if (!(*var_hashx)->first_dtor) {
135             (*var_hashx)->first_dtor = var_hash;
136         } else {
137             ((var_dtor_entries *) (*var_hashx)->last_dtor)->next = var_hash;
138         }
139 
140         (*var_hashx)->last_dtor = var_hash;
141     }
142     ZVAL_UNDEF(&var_hash->data[var_hash->used_slots]);
143 	Z_EXTRA(var_hash->data[var_hash->used_slots]) = 0;
144     return &var_hash->data[var_hash->used_slots++];
145 }
146 
var_replace(php_unserialize_data_t * var_hashx,zval * ozval,zval * nzval)147 PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval *nzval)
148 {
149 	zend_long i;
150 	var_entries *var_hash = (*var_hashx)->first;
151 #if VAR_ENTRIES_DBG
152 	fprintf(stderr, "var_replace(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_P(nzval));
153 #endif
154 
155 	while (var_hash) {
156 		for (i = 0; i < var_hash->used_slots; i++) {
157 			if (var_hash->data[i] == ozval) {
158 				var_hash->data[i] = nzval;
159 				/* do not break here */
160 			}
161 		}
162 		var_hash = var_hash->next;
163 	}
164 }
165 
var_access(php_unserialize_data_t * var_hashx,zend_long id)166 static zval *var_access(php_unserialize_data_t *var_hashx, zend_long id)
167 {
168 	var_entries *var_hash = (*var_hashx)->first;
169 #if VAR_ENTRIES_DBG
170 	fprintf(stderr, "var_access(%ld): %ld\n", var_hash?var_hash->used_slots:-1L, id);
171 #endif
172 
173 	while (id >= VAR_ENTRIES_MAX && var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) {
174 		var_hash = var_hash->next;
175 		id -= VAR_ENTRIES_MAX;
176 	}
177 
178 	if (!var_hash) return NULL;
179 
180 	if (id < 0 || id >= var_hash->used_slots) return NULL;
181 
182 	return var_hash->data[id];
183 }
184 
var_destroy(php_unserialize_data_t * var_hashx)185 PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
186 {
187 	void *next;
188 	zend_long i;
189 	var_entries *var_hash = (*var_hashx)->first;
190 	var_dtor_entries *var_dtor_hash = (*var_hashx)->first_dtor;
191 	zend_bool wakeup_failed = 0;
192 	zval wakeup_name;
193 	ZVAL_UNDEF(&wakeup_name);
194 
195 #if VAR_ENTRIES_DBG
196 	fprintf(stderr, "var_destroy(%ld)\n", var_hash?var_hash->used_slots:-1L);
197 #endif
198 
199 	while (var_hash) {
200 		next = var_hash->next;
201 		efree_size(var_hash, sizeof(var_entries));
202 		var_hash = next;
203 	}
204 
205 	while (var_dtor_hash) {
206 		for (i = 0; i < var_dtor_hash->used_slots; i++) {
207 			zval *zv = &var_dtor_hash->data[i];
208 #if VAR_ENTRIES_DBG
209 			fprintf(stderr, "var_destroy dtor(%p, %ld)\n", var_dtor_hash->data[i], Z_REFCOUNT_P(var_dtor_hash->data[i]));
210 #endif
211 
212 			/* Perform delayed __wakeup calls */
213 			if (Z_EXTRA_P(zv) == VAR_WAKEUP_FLAG) {
214 				if (!wakeup_failed) {
215 					zval retval;
216 					if (Z_ISUNDEF(wakeup_name)) {
217 						ZVAL_STRINGL(&wakeup_name, "__wakeup", sizeof("__wakeup") - 1);
218 					}
219 
220 					BG(serialize_lock)++;
221 					if (call_user_function(CG(function_table), zv, &wakeup_name, &retval, 0, 0) == FAILURE || Z_ISUNDEF(retval)) {
222 						wakeup_failed = 1;
223 						GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
224 					}
225 					BG(serialize_lock)--;
226 
227 					zval_ptr_dtor(&retval);
228 				} else {
229 					GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
230 				}
231 			}
232 
233 			i_zval_ptr_dtor(zv ZEND_FILE_LINE_CC);
234 		}
235 		next = var_dtor_hash->next;
236 		efree_size(var_dtor_hash, sizeof(var_dtor_entries));
237 		var_dtor_hash = next;
238 	}
239 
240 	zval_ptr_dtor_nogc(&wakeup_name);
241 }
242 
243 /* }}} */
244 
unserialize_str(const unsigned char ** p,size_t len,size_t maxlen)245 static zend_string *unserialize_str(const unsigned char **p, size_t len, size_t maxlen)
246 {
247 	size_t i, j;
248 	zend_string *str = zend_string_safe_alloc(1, len, 0, 0);
249 	unsigned char *end = *(unsigned char **)p+maxlen;
250 
251 	if (end < *p) {
252 		zend_string_efree(str);
253 		return NULL;
254 	}
255 
256 	for (i = 0; i < len; i++) {
257 		if (*p >= end) {
258 			zend_string_efree(str);
259 			return NULL;
260 		}
261 		if (**p != '\\') {
262 			ZSTR_VAL(str)[i] = (char)**p;
263 		} else {
264 			unsigned char ch = 0;
265 
266 			for (j = 0; j < 2; j++) {
267 				(*p)++;
268 				if (**p >= '0' && **p <= '9') {
269 					ch = (ch << 4) + (**p -'0');
270 				} else if (**p >= 'a' && **p <= 'f') {
271 					ch = (ch << 4) + (**p -'a'+10);
272 				} else if (**p >= 'A' && **p <= 'F') {
273 					ch = (ch << 4) + (**p -'A'+10);
274 				} else {
275 					zend_string_efree(str);
276 					return NULL;
277 				}
278 			}
279 			ZSTR_VAL(str)[i] = (char)ch;
280 		}
281 		(*p)++;
282 	}
283 	ZSTR_VAL(str)[i] = 0;
284 	ZSTR_LEN(str) = i;
285 	return str;
286 }
287 
unserialize_allowed_class(zend_string * class_name,php_unserialize_data_t * var_hashx)288 static inline int unserialize_allowed_class(
289 		zend_string *class_name, php_unserialize_data_t *var_hashx)
290 {
291 	HashTable *classes = (*var_hashx)->allowed_classes;
292 	zend_string *lcname;
293 	int res;
294 	ALLOCA_FLAG(use_heap)
295 
296 	if(classes == NULL) {
297 		return 1;
298 	}
299 	if(!zend_hash_num_elements(classes)) {
300 		return 0;
301 	}
302 
303 	ZSTR_ALLOCA_ALLOC(lcname, ZSTR_LEN(class_name), use_heap);
304 	zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(class_name), ZSTR_LEN(class_name));
305 	res = zend_hash_exists(classes, lcname);
306 	ZSTR_ALLOCA_FREE(lcname, use_heap);
307 	return res;
308 }
309 
310 #define YYFILL(n) do { } while (0)
311 #define YYCTYPE unsigned char
312 #define YYCURSOR cursor
313 #define YYLIMIT limit
314 #define YYMARKER marker
315 
316 
317 
318 
319 
320 
parse_iv2(const unsigned char * p,const unsigned char ** q)321 static inline zend_long parse_iv2(const unsigned char *p, const unsigned char **q)
322 {
323 	zend_ulong result = 0;
324 	zend_ulong neg = 0;
325 	const unsigned char *start;
326 
327 	if (*p == '-') {
328 		neg = 1;
329 		p++;
330 	} else if (UNEXPECTED(*p == '+')) {
331 		p++;
332 	}
333 
334 	while (UNEXPECTED(*p == '0')) {
335 		p++;
336 	}
337 
338 	start = p;
339 
340 	while (*p >= '0' && *p <= '9') {
341 		result = result * 10 + ((zend_ulong)(*p) - '0');
342 		p++;
343 	}
344 
345 	if (q) {
346 		*q = p;
347 	}
348 
349 	/* number too long or overflow */
350 	if (UNEXPECTED(p - start > MAX_LENGTH_OF_LONG - 1)
351 	 || (SIZEOF_ZEND_LONG == 4
352 	 	&& UNEXPECTED(p - start == MAX_LENGTH_OF_LONG - 1)
353 	 	&& UNEXPECTED(*start > '2'))
354 	 || UNEXPECTED(result > ZEND_LONG_MAX + neg)) {
355 		php_error_docref(NULL, E_WARNING, "Numerical result out of range");
356 		return (!neg) ? ZEND_LONG_MAX : ZEND_LONG_MIN;
357 	}
358 
359 	return (zend_long) ((!neg) ? result : -result);
360 }
361 
parse_iv(const unsigned char * p)362 static inline zend_long parse_iv(const unsigned char *p)
363 {
364 	return parse_iv2(p, NULL);
365 }
366 
367 /* no need to check for length - re2c already did */
parse_uiv(const unsigned char * p)368 static inline size_t parse_uiv(const unsigned char *p)
369 {
370 	unsigned char cursor;
371 	size_t result = 0;
372 
373 	while (1) {
374 		cursor = *p;
375 		if (cursor >= '0' && cursor <= '9') {
376 			result = result * 10 + (size_t)(cursor - (unsigned char)'0');
377 		} else {
378 			break;
379 		}
380 		p++;
381 	}
382 	return result;
383 }
384 
385 #define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash
386 #define UNSERIALIZE_PASSTHRU rval, p, max, var_hash
387 
388 static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER, int as_key);
389 
process_nested_data(UNSERIALIZE_PARAMETER,HashTable * ht,zend_long elements,int objprops)390 static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, int objprops)
391 {
392 	while (elements-- > 0) {
393 		zval key, *data, d, *old_data;
394 		zend_ulong idx;
395 
396 		ZVAL_UNDEF(&key);
397 
398 		if (!php_var_unserialize_internal(&key, p, max, NULL, 1)) {
399 			zval_ptr_dtor(&key);
400 			return 0;
401 		}
402 
403 		data = NULL;
404 		ZVAL_UNDEF(&d);
405 
406 		if (!objprops) {
407 			if (Z_TYPE(key) == IS_LONG) {
408 				idx = Z_LVAL(key);
409 numeric_key:
410 				if (UNEXPECTED((old_data = zend_hash_index_find(ht, idx)) != NULL)) {
411 					//??? update hash
412 					var_push_dtor(var_hash, old_data);
413 					data = zend_hash_index_update(ht, idx, &d);
414 				} else {
415 					data = zend_hash_index_add_new(ht, idx, &d);
416 				}
417 			} else if (Z_TYPE(key) == IS_STRING) {
418 				if (UNEXPECTED(ZEND_HANDLE_NUMERIC(Z_STR(key), idx))) {
419 					goto numeric_key;
420 				}
421 				if (UNEXPECTED((old_data = zend_hash_find(ht, Z_STR(key))) != NULL)) {
422 					//??? update hash
423 					var_push_dtor(var_hash, old_data);
424 					data = zend_hash_update(ht, Z_STR(key), &d);
425 				} else {
426 					data = zend_hash_add_new(ht, Z_STR(key), &d);
427 				}
428 			} else {
429 				zval_ptr_dtor(&key);
430 				return 0;
431 			}
432 		} else {
433 			if (EXPECTED(Z_TYPE(key) == IS_STRING)) {
434 string_key:
435 				if (Z_TYPE_P(rval) == IS_OBJECT
436 						&& zend_hash_num_elements(&Z_OBJCE_P(rval)->properties_info) > 0) {
437 					zend_property_info *existing_propinfo;
438 					zend_string *new_key;
439 					const char *unmangled_class = NULL;
440 					const char *unmangled_prop;
441 					size_t unmangled_prop_len;
442 					zend_string *unmangled;
443 
444 					if (UNEXPECTED(zend_unmangle_property_name_ex(Z_STR(key), &unmangled_class, &unmangled_prop, &unmangled_prop_len) == FAILURE)) {
445 						zval_ptr_dtor(&key);
446 						return 0;
447 					}
448 
449 					unmangled = zend_string_init(unmangled_prop, unmangled_prop_len, 0);
450 
451 					existing_propinfo = zend_hash_find_ptr(&Z_OBJCE_P(rval)->properties_info, unmangled);
452                     if ((unmangled_class == NULL || !strcmp(unmangled_class, "*") || !strcasecmp(unmangled_class, ZSTR_VAL(Z_OBJCE_P(rval)->name)))
453                             && (existing_propinfo != NULL)
454 							&& (existing_propinfo->flags & ZEND_ACC_PPP_MASK)) {
455 						if (existing_propinfo->flags & ZEND_ACC_PROTECTED) {
456 							new_key = zend_mangle_property_name(
457 								"*", 1, ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), 0);
458 							zend_string_release_ex(unmangled, 0);
459 						} else if (existing_propinfo->flags & ZEND_ACC_PRIVATE) {
460 							if (unmangled_class != NULL && strcmp(unmangled_class, "*") != 0) {
461 								new_key = zend_mangle_property_name(
462 									unmangled_class, strlen(unmangled_class),
463 										ZSTR_VAL(unmangled), ZSTR_LEN(unmangled),
464 										0);
465 							} else {
466 								new_key = zend_mangle_property_name(
467 									ZSTR_VAL(existing_propinfo->ce->name), ZSTR_LEN(existing_propinfo->ce->name),
468 									ZSTR_VAL(unmangled), ZSTR_LEN(unmangled),
469 									0);
470 							}
471 							zend_string_release_ex(unmangled, 0);
472 						} else {
473 							ZEND_ASSERT(existing_propinfo->flags & ZEND_ACC_PUBLIC);
474 							new_key = unmangled;
475 						}
476 						zval_ptr_dtor_str(&key);
477 						ZVAL_STR(&key, new_key);
478 					} else {
479 						zend_string_release_ex(unmangled, 0);
480 					}
481 				}
482 
483 				if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) {
484 					if (Z_TYPE_P(old_data) == IS_INDIRECT) {
485 						old_data = Z_INDIRECT_P(old_data);
486 					}
487 					var_push_dtor(var_hash, old_data);
488 					data = zend_hash_update_ind(ht, Z_STR(key), &d);
489 				} else {
490 					data = zend_hash_add_new(ht, Z_STR(key), &d);
491 				}
492 			} else if (Z_TYPE(key) == IS_LONG) {
493 				/* object properties should include no integers */
494 				convert_to_string(&key);
495 				goto string_key;
496 			} else {
497 				zval_ptr_dtor(&key);
498 				return 0;
499 			}
500 		}
501 
502 		if (!php_var_unserialize_internal(data, p, max, var_hash, 0)) {
503 			zval_ptr_dtor(&key);
504 			return 0;
505 		}
506 
507 		var_push_dtor(var_hash, data);
508 		zval_ptr_dtor_str(&key);
509 
510 		if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
511 			(*p)--;
512 			return 0;
513 		}
514 	}
515 
516 	return 1;
517 }
518 
finish_nested_data(UNSERIALIZE_PARAMETER)519 static inline int finish_nested_data(UNSERIALIZE_PARAMETER)
520 {
521 	if (*p >= max || **p != '}') {
522 		return 0;
523 	}
524 
525 	(*p)++;
526 	return 1;
527 }
528 
object_custom(UNSERIALIZE_PARAMETER,zend_class_entry * ce)529 static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
530 {
531 	zend_long datalen;
532 
533 	datalen = parse_iv2((*p) + 2, p);
534 
535 	(*p) += 2;
536 
537 	if (datalen < 0 || (max - (*p)) <= datalen) {
538 		zend_error(E_WARNING, "Insufficient data for unserializing - " ZEND_LONG_FMT " required, " ZEND_LONG_FMT " present", datalen, (zend_long)(max - (*p)));
539 		return 0;
540 	}
541 
542 	/* Check that '}' is present before calling ce->unserialize() to mitigate issues
543 	 * with unserialize reading past the end of the passed buffer if the string is not
544 	 * appropriately terminated (usually NUL terminated, but '}' is also sufficient.) */
545 	if ((*p)[datalen] != '}') {
546 		return 0;
547 	}
548 
549 	if (ce->unserialize == NULL) {
550 		zend_error(E_WARNING, "Class %s has no unserializer", ZSTR_VAL(ce->name));
551 		object_init_ex(rval, ce);
552 	} else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash) != SUCCESS) {
553 		return 0;
554 	}
555 
556 	(*p) += datalen + 1; /* +1 for '}' */
557 	return 1;
558 }
559 
object_common1(UNSERIALIZE_PARAMETER,zend_class_entry * ce)560 static inline zend_long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
561 {
562 	zend_long elements;
563 
564 	if( *p >= max - 2) {
565 		zend_error(E_WARNING, "Bad unserialize data");
566 		return -1;
567 	}
568 
569 	elements = parse_iv2((*p) + 2, p);
570 
571 	(*p) += 2;
572 
573 	if (ce->serialize == NULL) {
574 		object_init_ex(rval, ce);
575 	} else {
576 		/* If this class implements Serializable, it should not land here but in object_custom(). The passed string
577 		obviously doesn't descend from the regular serializer. */
578 		zend_error(E_WARNING, "Erroneous data format for unserializing '%s'", ZSTR_VAL(ce->name));
579 		return -1;
580 	}
581 
582 	return elements;
583 }
584 
585 #ifdef PHP_WIN32
586 # pragma optimize("", off)
587 #endif
object_common2(UNSERIALIZE_PARAMETER,zend_long elements)588 static inline int object_common2(UNSERIALIZE_PARAMETER, zend_long elements)
589 {
590 	HashTable *ht;
591 	zend_bool has_wakeup;
592 
593 	if (Z_TYPE_P(rval) != IS_OBJECT) {
594 		return 0;
595 	}
596 
597 	has_wakeup = Z_OBJCE_P(rval) != PHP_IC_ENTRY
598 		&& zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1);
599 
600 	ht = Z_OBJPROP_P(rval);
601 	if (elements >= (zend_long)(HT_MAX_SIZE - zend_hash_num_elements(ht))) {
602 		return 0;
603 	}
604 
605 	zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, HT_FLAGS(ht) & HASH_FLAG_PACKED);
606 	if (!process_nested_data(UNSERIALIZE_PASSTHRU, ht, elements, 1)) {
607 		if (has_wakeup) {
608 			ZVAL_DEREF(rval);
609 			GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED);
610 		}
611 		return 0;
612 	}
613 
614 	ZVAL_DEREF(rval);
615 	if (has_wakeup) {
616 		/* Delay __wakeup call until end of serialization */
617 		zval *wakeup_var = var_tmp_var(var_hash);
618 		ZVAL_COPY(wakeup_var, rval);
619 		Z_EXTRA_P(wakeup_var) = VAR_WAKEUP_FLAG;
620 	}
621 
622 	return finish_nested_data(UNSERIALIZE_PASSTHRU);
623 }
624 #ifdef PHP_WIN32
625 # pragma optimize("", on)
626 #endif
627 
php_var_unserialize(UNSERIALIZE_PARAMETER)628 PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
629 {
630 	var_entries *orig_var_entries = (*var_hash)->last;
631 	zend_long orig_used_slots = orig_var_entries ? orig_var_entries->used_slots : 0;
632 	int result;
633 
634 	result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU, 0);
635 
636 	if (!result) {
637 		/* If the unserialization failed, mark all elements that have been added to var_hash
638 		 * as NULL. This will forbid their use by other unserialize() calls in the same
639 		 * unserialization context. */
640 		var_entries *e = orig_var_entries;
641 		zend_long s = orig_used_slots;
642 		while (e) {
643 			for (; s < e->used_slots; s++) {
644 				e->data[s] = NULL;
645 			}
646 
647 			e = e->next;
648 			s = 0;
649 		}
650 	}
651 
652 	return result;
653 }
654 
php_var_unserialize_internal(UNSERIALIZE_PARAMETER,int as_key)655 static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER, int as_key)
656 {
657 	const unsigned char *cursor, *limit, *marker, *start;
658 	zval *rval_ref;
659 
660 	limit = max;
661 	cursor = *p;
662 
663 	if (YYCURSOR >= YYLIMIT) {
664 		return 0;
665 	}
666 
667 	if (var_hash && (*p)[0] != 'R') {
668 		var_push(var_hash, rval);
669 	}
670 
671 	start = cursor;
672 
673 
674 {
675 	YYCTYPE yych;
676 	static const unsigned char yybm[] = {
677 		  0,   0,   0,   0,   0,   0,   0,   0,
678 		  0,   0,   0,   0,   0,   0,   0,   0,
679 		  0,   0,   0,   0,   0,   0,   0,   0,
680 		  0,   0,   0,   0,   0,   0,   0,   0,
681 		  0,   0,   0,   0,   0,   0,   0,   0,
682 		  0,   0,   0,   0,   0,   0,   0,   0,
683 		128, 128, 128, 128, 128, 128, 128, 128,
684 		128, 128,   0,   0,   0,   0,   0,   0,
685 		  0,   0,   0,   0,   0,   0,   0,   0,
686 		  0,   0,   0,   0,   0,   0,   0,   0,
687 		  0,   0,   0,   0,   0,   0,   0,   0,
688 		  0,   0,   0,   0,   0,   0,   0,   0,
689 		  0,   0,   0,   0,   0,   0,   0,   0,
690 		  0,   0,   0,   0,   0,   0,   0,   0,
691 		  0,   0,   0,   0,   0,   0,   0,   0,
692 		  0,   0,   0,   0,   0,   0,   0,   0,
693 		  0,   0,   0,   0,   0,   0,   0,   0,
694 		  0,   0,   0,   0,   0,   0,   0,   0,
695 		  0,   0,   0,   0,   0,   0,   0,   0,
696 		  0,   0,   0,   0,   0,   0,   0,   0,
697 		  0,   0,   0,   0,   0,   0,   0,   0,
698 		  0,   0,   0,   0,   0,   0,   0,   0,
699 		  0,   0,   0,   0,   0,   0,   0,   0,
700 		  0,   0,   0,   0,   0,   0,   0,   0,
701 		  0,   0,   0,   0,   0,   0,   0,   0,
702 		  0,   0,   0,   0,   0,   0,   0,   0,
703 		  0,   0,   0,   0,   0,   0,   0,   0,
704 		  0,   0,   0,   0,   0,   0,   0,   0,
705 		  0,   0,   0,   0,   0,   0,   0,   0,
706 		  0,   0,   0,   0,   0,   0,   0,   0,
707 		  0,   0,   0,   0,   0,   0,   0,   0,
708 		  0,   0,   0,   0,   0,   0,   0,   0,
709 	};
710 	if ((YYLIMIT - YYCURSOR) < 7) YYFILL(7);
711 	yych = *YYCURSOR;
712 	switch (yych) {
713 	case 'C':
714 	case 'O':	goto yy4;
715 	case 'N':	goto yy5;
716 	case 'R':	goto yy6;
717 	case 'S':	goto yy7;
718 	case 'a':	goto yy8;
719 	case 'b':	goto yy9;
720 	case 'd':	goto yy10;
721 	case 'i':	goto yy11;
722 	case 'o':	goto yy12;
723 	case 'r':	goto yy13;
724 	case 's':	goto yy14;
725 	case '}':	goto yy15;
726 	default:	goto yy2;
727 	}
728 yy2:
729 	++YYCURSOR;
730 yy3:
731 	{ return 0; }
732 yy4:
733 	yych = *(YYMARKER = ++YYCURSOR);
734 	if (yych == ':') goto yy17;
735 	goto yy3;
736 yy5:
737 	yych = *++YYCURSOR;
738 	if (yych == ';') goto yy19;
739 	goto yy3;
740 yy6:
741 	yych = *(YYMARKER = ++YYCURSOR);
742 	if (yych == ':') goto yy21;
743 	goto yy3;
744 yy7:
745 	yych = *(YYMARKER = ++YYCURSOR);
746 	if (yych == ':') goto yy22;
747 	goto yy3;
748 yy8:
749 	yych = *(YYMARKER = ++YYCURSOR);
750 	if (yych == ':') goto yy23;
751 	goto yy3;
752 yy9:
753 	yych = *(YYMARKER = ++YYCURSOR);
754 	if (yych == ':') goto yy24;
755 	goto yy3;
756 yy10:
757 	yych = *(YYMARKER = ++YYCURSOR);
758 	if (yych == ':') goto yy25;
759 	goto yy3;
760 yy11:
761 	yych = *(YYMARKER = ++YYCURSOR);
762 	if (yych == ':') goto yy26;
763 	goto yy3;
764 yy12:
765 	yych = *(YYMARKER = ++YYCURSOR);
766 	if (yych == ':') goto yy27;
767 	goto yy3;
768 yy13:
769 	yych = *(YYMARKER = ++YYCURSOR);
770 	if (yych == ':') goto yy28;
771 	goto yy3;
772 yy14:
773 	yych = *(YYMARKER = ++YYCURSOR);
774 	if (yych == ':') goto yy29;
775 	goto yy3;
776 yy15:
777 	++YYCURSOR;
778 	{
779 	/* this is the case where we have less data than planned */
780 	php_error_docref(NULL, E_NOTICE, "Unexpected end of serialized data");
781 	return 0; /* not sure if it should be 0 or 1 here? */
782 }
783 yy17:
784 	yych = *++YYCURSOR;
785 	if (yybm[0+yych] & 128) {
786 		goto yy30;
787 	}
788 yy18:
789 	YYCURSOR = YYMARKER;
790 	goto yy3;
791 yy19:
792 	++YYCURSOR;
793 	{
794 	*p = YYCURSOR;
795 	ZVAL_NULL(rval);
796 	return 1;
797 }
798 yy21:
799 	yych = *++YYCURSOR;
800 	if (yych <= '/') goto yy18;
801 	if (yych <= '9') goto yy32;
802 	goto yy18;
803 yy22:
804 	yych = *++YYCURSOR;
805 	if (yych <= '/') goto yy18;
806 	if (yych <= '9') goto yy34;
807 	goto yy18;
808 yy23:
809 	yych = *++YYCURSOR;
810 	if (yych <= '/') goto yy18;
811 	if (yych <= '9') goto yy36;
812 	goto yy18;
813 yy24:
814 	yych = *++YYCURSOR;
815 	if (yych <= '/') goto yy18;
816 	if (yych <= '0') goto yy38;
817 	if (yych <= '1') goto yy39;
818 	goto yy18;
819 yy25:
820 	yych = *++YYCURSOR;
821 	if (yych <= '/') {
822 		if (yych <= ',') {
823 			if (yych == '+') goto yy40;
824 			goto yy18;
825 		} else {
826 			if (yych <= '-') goto yy41;
827 			if (yych <= '.') goto yy42;
828 			goto yy18;
829 		}
830 	} else {
831 		if (yych <= 'I') {
832 			if (yych <= '9') goto yy43;
833 			if (yych <= 'H') goto yy18;
834 			goto yy45;
835 		} else {
836 			if (yych == 'N') goto yy46;
837 			goto yy18;
838 		}
839 	}
840 yy26:
841 	yych = *++YYCURSOR;
842 	if (yych <= ',') {
843 		if (yych == '+') goto yy47;
844 		goto yy18;
845 	} else {
846 		if (yych <= '-') goto yy47;
847 		if (yych <= '/') goto yy18;
848 		if (yych <= '9') goto yy48;
849 		goto yy18;
850 	}
851 yy27:
852 	yych = *++YYCURSOR;
853 	if (yych <= '/') goto yy18;
854 	if (yych <= '9') goto yy50;
855 	goto yy18;
856 yy28:
857 	yych = *++YYCURSOR;
858 	if (yych <= '/') goto yy18;
859 	if (yych <= '9') goto yy52;
860 	goto yy18;
861 yy29:
862 	yych = *++YYCURSOR;
863 	if (yych <= '/') goto yy18;
864 	if (yych <= '9') goto yy54;
865 	goto yy18;
866 yy30:
867 	++YYCURSOR;
868 	if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
869 	yych = *YYCURSOR;
870 	if (yybm[0+yych] & 128) {
871 		goto yy30;
872 	}
873 	if (yych <= '/') goto yy18;
874 	if (yych <= ':') goto yy56;
875 	goto yy18;
876 yy32:
877 	++YYCURSOR;
878 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
879 	yych = *YYCURSOR;
880 	if (yych <= '/') goto yy18;
881 	if (yych <= '9') goto yy32;
882 	if (yych == ';') goto yy57;
883 	goto yy18;
884 yy34:
885 	++YYCURSOR;
886 	if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
887 	yych = *YYCURSOR;
888 	if (yych <= '/') goto yy18;
889 	if (yych <= '9') goto yy34;
890 	if (yych <= ':') goto yy59;
891 	goto yy18;
892 yy36:
893 	++YYCURSOR;
894 	if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
895 	yych = *YYCURSOR;
896 	if (yych <= '/') goto yy18;
897 	if (yych <= '9') goto yy36;
898 	if (yych <= ':') goto yy60;
899 	goto yy18;
900 yy38:
901 	yych = *++YYCURSOR;
902 	if (yych == ';') goto yy61;
903 	goto yy18;
904 yy39:
905 	yych = *++YYCURSOR;
906 	if (yych == ';') goto yy63;
907 	goto yy18;
908 yy40:
909 	yych = *++YYCURSOR;
910 	if (yych == '.') goto yy42;
911 	if (yych <= '/') goto yy18;
912 	if (yych <= '9') goto yy43;
913 	goto yy18;
914 yy41:
915 	yych = *++YYCURSOR;
916 	if (yych <= '/') {
917 		if (yych != '.') goto yy18;
918 	} else {
919 		if (yych <= '9') goto yy43;
920 		if (yych == 'I') goto yy45;
921 		goto yy18;
922 	}
923 yy42:
924 	yych = *++YYCURSOR;
925 	if (yych <= '/') goto yy18;
926 	if (yych <= '9') goto yy65;
927 	goto yy18;
928 yy43:
929 	++YYCURSOR;
930 	if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
931 	yych = *YYCURSOR;
932 	if (yych <= ':') {
933 		if (yych <= '.') {
934 			if (yych <= '-') goto yy18;
935 			goto yy65;
936 		} else {
937 			if (yych <= '/') goto yy18;
938 			if (yych <= '9') goto yy43;
939 			goto yy18;
940 		}
941 	} else {
942 		if (yych <= 'E') {
943 			if (yych <= ';') goto yy67;
944 			if (yych <= 'D') goto yy18;
945 			goto yy69;
946 		} else {
947 			if (yych == 'e') goto yy69;
948 			goto yy18;
949 		}
950 	}
951 yy45:
952 	yych = *++YYCURSOR;
953 	if (yych == 'N') goto yy70;
954 	goto yy18;
955 yy46:
956 	yych = *++YYCURSOR;
957 	if (yych == 'A') goto yy71;
958 	goto yy18;
959 yy47:
960 	yych = *++YYCURSOR;
961 	if (yych <= '/') goto yy18;
962 	if (yych >= ':') goto yy18;
963 yy48:
964 	++YYCURSOR;
965 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
966 	yych = *YYCURSOR;
967 	if (yych <= '/') goto yy18;
968 	if (yych <= '9') goto yy48;
969 	if (yych == ';') goto yy72;
970 	goto yy18;
971 yy50:
972 	++YYCURSOR;
973 	if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
974 	yych = *YYCURSOR;
975 	if (yych <= '/') goto yy18;
976 	if (yych <= '9') goto yy50;
977 	if (yych <= ':') goto yy74;
978 	goto yy18;
979 yy52:
980 	++YYCURSOR;
981 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
982 	yych = *YYCURSOR;
983 	if (yych <= '/') goto yy18;
984 	if (yych <= '9') goto yy52;
985 	if (yych == ';') goto yy75;
986 	goto yy18;
987 yy54:
988 	++YYCURSOR;
989 	if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
990 	yych = *YYCURSOR;
991 	if (yych <= '/') goto yy18;
992 	if (yych <= '9') goto yy54;
993 	if (yych <= ':') goto yy77;
994 	goto yy18;
995 yy56:
996 	yych = *++YYCURSOR;
997 	if (yych == '"') goto yy78;
998 	goto yy18;
999 yy57:
1000 	++YYCURSOR;
1001 	{
1002 	zend_long id;
1003 
1004  	*p = YYCURSOR;
1005 	if (!var_hash) return 0;
1006 
1007 	id = parse_uiv(start + 2) - 1;
1008 	if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) {
1009 		return 0;
1010 	}
1011 
1012 	if (Z_ISUNDEF_P(rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P(Z_REFVAL_P(rval_ref)))) {
1013 		return 0;
1014 	}
1015 
1016 	if (Z_ISREF_P(rval_ref)) {
1017 		ZVAL_COPY(rval, rval_ref);
1018 	} else {
1019 		ZVAL_NEW_REF(rval_ref, rval_ref);
1020 		ZVAL_COPY(rval, rval_ref);
1021 	}
1022 
1023 	return 1;
1024 }
1025 yy59:
1026 	yych = *++YYCURSOR;
1027 	if (yych == '"') goto yy80;
1028 	goto yy18;
1029 yy60:
1030 	yych = *++YYCURSOR;
1031 	if (yych == '{') goto yy82;
1032 	goto yy18;
1033 yy61:
1034 	++YYCURSOR;
1035 	{
1036 	*p = YYCURSOR;
1037 	ZVAL_FALSE(rval);
1038 	return 1;
1039 }
1040 yy63:
1041 	++YYCURSOR;
1042 	{
1043 	*p = YYCURSOR;
1044 	ZVAL_TRUE(rval);
1045 	return 1;
1046 }
1047 yy65:
1048 	++YYCURSOR;
1049 	if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
1050 	yych = *YYCURSOR;
1051 	if (yych <= ';') {
1052 		if (yych <= '/') goto yy18;
1053 		if (yych <= '9') goto yy65;
1054 		if (yych <= ':') goto yy18;
1055 	} else {
1056 		if (yych <= 'E') {
1057 			if (yych <= 'D') goto yy18;
1058 			goto yy69;
1059 		} else {
1060 			if (yych == 'e') goto yy69;
1061 			goto yy18;
1062 		}
1063 	}
1064 yy67:
1065 	++YYCURSOR;
1066 	{
1067 #if SIZEOF_ZEND_LONG == 4
1068 use_double:
1069 #endif
1070 	*p = YYCURSOR;
1071 	ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL));
1072 	return 1;
1073 }
1074 yy69:
1075 	yych = *++YYCURSOR;
1076 	if (yych <= ',') {
1077 		if (yych == '+') goto yy84;
1078 		goto yy18;
1079 	} else {
1080 		if (yych <= '-') goto yy84;
1081 		if (yych <= '/') goto yy18;
1082 		if (yych <= '9') goto yy85;
1083 		goto yy18;
1084 	}
1085 yy70:
1086 	yych = *++YYCURSOR;
1087 	if (yych == 'F') goto yy87;
1088 	goto yy18;
1089 yy71:
1090 	yych = *++YYCURSOR;
1091 	if (yych == 'N') goto yy87;
1092 	goto yy18;
1093 yy72:
1094 	++YYCURSOR;
1095 	{
1096 #if SIZEOF_ZEND_LONG == 4
1097 	int digits = YYCURSOR - start - 3;
1098 
1099 	if (start[2] == '-' || start[2] == '+') {
1100 		digits--;
1101 	}
1102 
1103 	/* Use double for large zend_long values that were serialized on a 64-bit system */
1104 	if (digits >= MAX_LENGTH_OF_LONG - 1) {
1105 		if (digits == MAX_LENGTH_OF_LONG - 1) {
1106 			int cmp = strncmp((char*)YYCURSOR - MAX_LENGTH_OF_LONG, long_min_digits, MAX_LENGTH_OF_LONG - 1);
1107 
1108 			if (!(cmp < 0 || (cmp == 0 && start[2] == '-'))) {
1109 				goto use_double;
1110 			}
1111 		} else {
1112 			goto use_double;
1113 		}
1114 	}
1115 #endif
1116 	*p = YYCURSOR;
1117 	ZVAL_LONG(rval, parse_iv(start + 2));
1118 	return 1;
1119 }
1120 yy74:
1121 	yych = *++YYCURSOR;
1122 	if (yych == '"') goto yy88;
1123 	goto yy18;
1124 yy75:
1125 	++YYCURSOR;
1126 	{
1127 	zend_long id;
1128 
1129  	*p = YYCURSOR;
1130 	if (!var_hash) return 0;
1131 
1132 	id = parse_uiv(start + 2) - 1;
1133 	if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) {
1134 		return 0;
1135 	}
1136 
1137 	if (rval_ref == rval) {
1138 		return 0;
1139 	}
1140 
1141 	ZVAL_DEREF(rval_ref);
1142 	if (Z_TYPE_P(rval_ref) != IS_OBJECT) {
1143 		return 0;
1144 	}
1145 
1146 	ZVAL_COPY(rval, rval_ref);
1147 
1148 	return 1;
1149 }
1150 yy77:
1151 	yych = *++YYCURSOR;
1152 	if (yych == '"') goto yy90;
1153 	goto yy18;
1154 yy78:
1155 	++YYCURSOR;
1156 	{
1157 	size_t len, len2, len3, maxlen;
1158 	zend_long elements;
1159 	char *str;
1160 	zend_string *class_name;
1161 	zend_class_entry *ce;
1162 	int incomplete_class = 0;
1163 
1164 	int custom_object = 0;
1165 
1166 	zval user_func;
1167 	zval retval;
1168 	zval args[1];
1169 
1170     if (!var_hash) return 0;
1171 	if (*start == 'C') {
1172 		custom_object = 1;
1173 	}
1174 
1175 	len2 = len = parse_uiv(start + 2);
1176 	maxlen = max - YYCURSOR;
1177 	if (maxlen < len || len == 0) {
1178 		*p = start + 2;
1179 		return 0;
1180 	}
1181 
1182 	str = (char*)YYCURSOR;
1183 
1184 	YYCURSOR += len;
1185 
1186 	if (*(YYCURSOR) != '"') {
1187 		*p = YYCURSOR;
1188 		return 0;
1189 	}
1190 	if (*(YYCURSOR+1) != ':') {
1191 		*p = YYCURSOR+1;
1192 		return 0;
1193 	}
1194 
1195 	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\\");
1196 	if (len3 != len)
1197 	{
1198 		*p = YYCURSOR + len3 - len;
1199 		return 0;
1200 	}
1201 
1202 	class_name = zend_string_init(str, len, 0);
1203 
1204 	do {
1205 		if(!unserialize_allowed_class(class_name, var_hash)) {
1206 			incomplete_class = 1;
1207 			ce = PHP_IC_ENTRY;
1208 			break;
1209 		}
1210 
1211 		/* Try to find class directly */
1212 		BG(serialize_lock)++;
1213 		ce = zend_lookup_class(class_name);
1214 		if (ce) {
1215 			BG(serialize_lock)--;
1216 			if (EG(exception)) {
1217 				zend_string_release_ex(class_name, 0);
1218 				return 0;
1219 			}
1220 			break;
1221 		}
1222 		BG(serialize_lock)--;
1223 
1224 		if (EG(exception)) {
1225 			zend_string_release_ex(class_name, 0);
1226 			return 0;
1227 		}
1228 
1229 		/* Check for unserialize callback */
1230 		if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
1231 			incomplete_class = 1;
1232 			ce = PHP_IC_ENTRY;
1233 			break;
1234 		}
1235 
1236 		/* Call unserialize callback */
1237 		ZVAL_STRING(&user_func, PG(unserialize_callback_func));
1238 
1239 		ZVAL_STR_COPY(&args[0], class_name);
1240 		BG(serialize_lock)++;
1241 		if (call_user_function_ex(CG(function_table), NULL, &user_func, &retval, 1, args, 0, NULL) != SUCCESS) {
1242 			BG(serialize_lock)--;
1243 			if (EG(exception)) {
1244 				zend_string_release_ex(class_name, 0);
1245 				zval_ptr_dtor(&user_func);
1246 				zval_ptr_dtor(&args[0]);
1247 				return 0;
1248 			}
1249 			php_error_docref(NULL, E_WARNING, "defined (%s) but not found", Z_STRVAL(user_func));
1250 			incomplete_class = 1;
1251 			ce = PHP_IC_ENTRY;
1252 			zval_ptr_dtor(&user_func);
1253 			zval_ptr_dtor(&args[0]);
1254 			break;
1255 		}
1256 		BG(serialize_lock)--;
1257 		zval_ptr_dtor(&retval);
1258 		if (EG(exception)) {
1259 			zend_string_release_ex(class_name, 0);
1260 			zval_ptr_dtor(&user_func);
1261 			zval_ptr_dtor(&args[0]);
1262 			return 0;
1263 		}
1264 
1265 		/* The callback function may have defined the class */
1266 		BG(serialize_lock)++;
1267 		if ((ce = zend_lookup_class(class_name)) == NULL) {
1268 			php_error_docref(NULL, E_WARNING, "Function %s() hasn't defined the class it was called for", Z_STRVAL(user_func));
1269 			incomplete_class = 1;
1270 			ce = PHP_IC_ENTRY;
1271 		}
1272 		BG(serialize_lock)--;
1273 
1274 		zval_ptr_dtor(&user_func);
1275 		zval_ptr_dtor(&args[0]);
1276 		break;
1277 	} while (1);
1278 
1279 	*p = YYCURSOR;
1280 
1281 	if (custom_object) {
1282 		int ret;
1283 
1284 		ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
1285 
1286 		if (ret && incomplete_class) {
1287 			php_store_class_name(rval, ZSTR_VAL(class_name), len2);
1288 		}
1289 		zend_string_release_ex(class_name, 0);
1290 		return ret;
1291 	}
1292 
1293 	elements = object_common1(UNSERIALIZE_PASSTHRU, ce);
1294 
1295 	if (elements < 0) {
1296 	   zend_string_release_ex(class_name, 0);
1297 	   return 0;
1298 	}
1299 
1300 	if (incomplete_class) {
1301 		php_store_class_name(rval, ZSTR_VAL(class_name), len2);
1302 	}
1303 	zend_string_release_ex(class_name, 0);
1304 
1305 	return object_common2(UNSERIALIZE_PASSTHRU, elements);
1306 }
1307 yy80:
1308 	++YYCURSOR;
1309 	{
1310 	size_t len, maxlen;
1311 	zend_string *str;
1312 
1313 	len = parse_uiv(start + 2);
1314 	maxlen = max - YYCURSOR;
1315 	if (maxlen < len) {
1316 		*p = start + 2;
1317 		return 0;
1318 	}
1319 
1320 	if ((str = unserialize_str(&YYCURSOR, len, maxlen)) == NULL) {
1321 		return 0;
1322 	}
1323 
1324 	if (*(YYCURSOR) != '"') {
1325 		zend_string_efree(str);
1326 		*p = YYCURSOR;
1327 		return 0;
1328 	}
1329 
1330 	if (*(YYCURSOR + 1) != ';') {
1331 		efree(str);
1332 		*p = YYCURSOR + 1;
1333 		return 0;
1334 	}
1335 
1336 	YYCURSOR += 2;
1337 	*p = YYCURSOR;
1338 
1339 	ZVAL_STR(rval, str);
1340 	return 1;
1341 }
1342 yy82:
1343 	++YYCURSOR;
1344 	{
1345 	zend_long elements = parse_iv(start + 2);
1346 	/* use iv() not uiv() in order to check data range */
1347 	*p = YYCURSOR;
1348     if (!var_hash) return 0;
1349 
1350 	if (elements < 0 || elements >= HT_MAX_SIZE) {
1351 		return 0;
1352 	}
1353 
1354 	if (elements) {
1355 		array_init_size(rval, elements);
1356 		/* we can't convert from packed to hash during unserialization, because
1357 		   reference to some zvals might be keept in var_hash (to support references) */
1358 		zend_hash_real_init_mixed(Z_ARRVAL_P(rval));
1359 	} else {
1360 		ZVAL_EMPTY_ARRAY(rval);
1361 		return finish_nested_data(UNSERIALIZE_PASSTHRU);
1362 	}
1363 
1364 	/* The array may contain references to itself, in which case we'll be modifying an
1365 	 * rc>1 array. This is okay, since the array is, ostensibly, only visible to
1366 	 * unserialize (in practice unserialization handlers also see it). Ideally we should
1367 	 * prohibit "r:" references to non-objects, as we only generate them for objects. */
1368 	HT_ALLOW_COW_VIOLATION(Z_ARRVAL_P(rval));
1369 
1370 	if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements, 0)) {
1371 		return 0;
1372 	}
1373 
1374 	return finish_nested_data(UNSERIALIZE_PASSTHRU);
1375 }
1376 yy84:
1377 	yych = *++YYCURSOR;
1378 	if (yych <= '/') goto yy18;
1379 	if (yych >= ':') goto yy18;
1380 yy85:
1381 	++YYCURSOR;
1382 	if (YYLIMIT <= YYCURSOR) YYFILL(1);
1383 	yych = *YYCURSOR;
1384 	if (yych <= '/') goto yy18;
1385 	if (yych <= '9') goto yy85;
1386 	if (yych == ';') goto yy67;
1387 	goto yy18;
1388 yy87:
1389 	yych = *++YYCURSOR;
1390 	if (yych == ';') goto yy92;
1391 	goto yy18;
1392 yy88:
1393 	++YYCURSOR;
1394 	{
1395 	zend_long elements;
1396     if (!var_hash) return 0;
1397 
1398 	elements = object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR);
1399 	if (elements < 0 || elements >= HT_MAX_SIZE) {
1400 		return 0;
1401 	}
1402 	return object_common2(UNSERIALIZE_PASSTHRU, elements);
1403 }
1404 yy90:
1405 	++YYCURSOR;
1406 	{
1407 	size_t len, maxlen;
1408 	char *str;
1409 
1410 	len = parse_uiv(start + 2);
1411 	maxlen = max - YYCURSOR;
1412 	if (maxlen < len) {
1413 		*p = start + 2;
1414 		return 0;
1415 	}
1416 
1417 	str = (char*)YYCURSOR;
1418 
1419 	YYCURSOR += len;
1420 
1421 	if (*(YYCURSOR) != '"') {
1422 		*p = YYCURSOR;
1423 		return 0;
1424 	}
1425 
1426 	if (*(YYCURSOR + 1) != ';') {
1427 		*p = YYCURSOR + 1;
1428 		return 0;
1429 	}
1430 
1431 	YYCURSOR += 2;
1432 	*p = YYCURSOR;
1433 
1434 	if (len == 0) {
1435 		ZVAL_EMPTY_STRING(rval);
1436 	} else if (len == 1) {
1437 		ZVAL_INTERNED_STR(rval, ZSTR_CHAR((zend_uchar)*str));
1438 	} else if (as_key) {
1439 		ZVAL_STR(rval, zend_string_init_interned(str, len, 0));
1440 	} else {
1441 		ZVAL_STRINGL(rval, str, len);
1442 	}
1443 	return 1;
1444 }
1445 yy92:
1446 	++YYCURSOR;
1447 	{
1448 	*p = YYCURSOR;
1449 
1450 	if (!strncmp((char*)start + 2, "NAN", 3)) {
1451 		ZVAL_DOUBLE(rval, ZEND_NAN);
1452 	} else if (!strncmp((char*)start + 2, "INF", 3)) {
1453 		ZVAL_DOUBLE(rval, ZEND_INFINITY);
1454 	} else if (!strncmp((char*)start + 2, "-INF", 4)) {
1455 		ZVAL_DOUBLE(rval, -ZEND_INFINITY);
1456 	} else {
1457 		ZVAL_NULL(rval);
1458 	}
1459 
1460 	return 1;
1461 }
1462 }
1463 
1464 
1465 	return 0;
1466 }
1467