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