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