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