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