1 /* Generated by re2c 2.1.1 */
2 /*
3 +----------------------------------------------------------------------+
4 | Copyright (c) The PHP Group |
5 +----------------------------------------------------------------------+
6 | This source file is subject to version 3.01 of the PHP license, |
7 | that is bundled with this package in the file LICENSE, and is |
8 | available through the world-wide-web at the following url: |
9 | https://www.php.net/license/3_01.txt |
10 | If you did not receive a copy of the PHP license and are unable to |
11 | obtain it through the world-wide-web, please send a note to |
12 | license@php.net so we can mail you a copy immediately. |
13 +----------------------------------------------------------------------+
14 | Author: Sascha Schumann <sascha@schumann.cx> |
15 +----------------------------------------------------------------------+
16 */
17
18 #include "php.h"
19 #include "ext/standard/php_var.h"
20 #include "php_incomplete_class.h"
21 #include "zend_portability.h"
22 #include "zend_exceptions.h"
23
24 /* {{{ reference-handling for unserializer: var_* */
25 #define VAR_ENTRIES_MAX 1018 /* 1024 - offsetof(php_unserialize_data, entries) / sizeof(void*) */
26 #define VAR_DTOR_ENTRIES_MAX 255 /* 256 - offsetof(var_dtor_entries, data) / sizeof(zval) */
27 #define VAR_ENTRIES_DBG 0
28
29 /* VAR_FLAG used in var_dtor entries to signify an entry on which
30 * __wakeup/__unserialize should be called */
31 #define VAR_WAKEUP_FLAG 1
32 #define VAR_UNSERIALIZE_FLAG 2
33
34 /* Each element is encoded using at least 2 characters. */
35 #define IS_FAKE_ELEM_COUNT(num_elems, serialized_len) \
36 ((num_elems) > (serialized_len) / 2)
37
38 typedef struct {
39 zend_long used_slots;
40 void *next;
41 zval *data[VAR_ENTRIES_MAX];
42 } var_entries;
43
44 typedef struct {
45 zend_long used_slots;
46 void *next;
47 zval data[VAR_DTOR_ENTRIES_MAX];
48 } var_dtor_entries;
49
50 struct php_unserialize_data {
51 var_entries *last;
52 var_dtor_entries *first_dtor;
53 var_dtor_entries *last_dtor;
54 HashTable *allowed_classes;
55 HashTable *ref_props;
56 zend_long cur_depth;
57 zend_long max_depth;
58 var_entries entries;
59 };
60
php_var_unserialize_init(void)61 PHPAPI php_unserialize_data_t php_var_unserialize_init(void) {
62 php_unserialize_data_t d;
63 /* fprintf(stderr, "UNSERIALIZE_INIT == lock: %u, level: %u\n", BG(serialize_lock), BG(unserialize).level); */
64 if (BG(serialize_lock) || !BG(unserialize).level) {
65 d = emalloc(sizeof(struct php_unserialize_data));
66 d->last = &d->entries;
67 d->first_dtor = d->last_dtor = NULL;
68 d->allowed_classes = NULL;
69 d->ref_props = NULL;
70 d->cur_depth = 0;
71 d->max_depth = BG(unserialize_max_depth);
72 d->entries.used_slots = 0;
73 d->entries.next = NULL;
74 if (!BG(serialize_lock)) {
75 BG(unserialize).data = d;
76 BG(unserialize).level = 1;
77 }
78 } else {
79 d = BG(unserialize).data;
80 ++BG(unserialize).level;
81 }
82 return d;
83 }
84
php_var_unserialize_destroy(php_unserialize_data_t d)85 PHPAPI void php_var_unserialize_destroy(php_unserialize_data_t d) {
86 /* fprintf(stderr, "UNSERIALIZE_DESTROY == lock: %u, level: %u\n", BG(serialize_lock), BG(unserialize).level); */
87 if (BG(serialize_lock) || BG(unserialize).level == 1) {
88 var_destroy(&d);
89 efree(d);
90 }
91 if (!BG(serialize_lock) && !--BG(unserialize).level) {
92 BG(unserialize).data = NULL;
93 }
94 }
95
php_var_unserialize_get_allowed_classes(php_unserialize_data_t d)96 PHPAPI HashTable *php_var_unserialize_get_allowed_classes(php_unserialize_data_t d) {
97 return d->allowed_classes;
98 }
php_var_unserialize_set_allowed_classes(php_unserialize_data_t d,HashTable * classes)99 PHPAPI void php_var_unserialize_set_allowed_classes(php_unserialize_data_t d, HashTable *classes) {
100 d->allowed_classes = classes;
101 }
102
php_var_unserialize_set_max_depth(php_unserialize_data_t d,zend_long max_depth)103 PHPAPI void php_var_unserialize_set_max_depth(php_unserialize_data_t d, zend_long max_depth) {
104 d->max_depth = max_depth;
105 }
php_var_unserialize_get_max_depth(php_unserialize_data_t d)106 PHPAPI zend_long php_var_unserialize_get_max_depth(php_unserialize_data_t d) {
107 return d->max_depth;
108 }
109
php_var_unserialize_set_cur_depth(php_unserialize_data_t d,zend_long cur_depth)110 PHPAPI void php_var_unserialize_set_cur_depth(php_unserialize_data_t d, zend_long cur_depth) {
111 d->cur_depth = cur_depth;
112 }
php_var_unserialize_get_cur_depth(php_unserialize_data_t d)113 PHPAPI zend_long php_var_unserialize_get_cur_depth(php_unserialize_data_t d) {
114 return d->cur_depth;
115 }
116
var_push(php_unserialize_data_t * var_hashx,zval * rval)117 static inline void var_push(php_unserialize_data_t *var_hashx, zval *rval)
118 {
119 var_entries *var_hash = (*var_hashx)->last;
120 #if VAR_ENTRIES_DBG
121 fprintf(stderr, "var_push(" ZEND_LONG_FMT "): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_P(rval));
122 #endif
123
124 if (var_hash->used_slots == VAR_ENTRIES_MAX) {
125 var_hash = emalloc(sizeof(var_entries));
126 var_hash->used_slots = 0;
127 var_hash->next = 0;
128
129 (*var_hashx)->last->next = var_hash;
130 (*var_hashx)->last = var_hash;
131 }
132
133 var_hash->data[var_hash->used_slots++] = rval;
134 }
135
var_push_dtor(php_unserialize_data_t * var_hashx,zval * rval)136 PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval *rval)
137 {
138 if (Z_REFCOUNTED_P(rval)) {
139 zval *tmp_var = var_tmp_var(var_hashx);
140 if (!tmp_var) {
141 return;
142 }
143 ZVAL_COPY(tmp_var, rval);
144 }
145 }
146
var_push_dtor_value(php_unserialize_data_t * var_hashx,zval * rval)147 static zend_never_inline void var_push_dtor_value(php_unserialize_data_t *var_hashx, zval *rval)
148 {
149 if (Z_REFCOUNTED_P(rval)) {
150 zval *tmp_var = var_tmp_var(var_hashx);
151 if (!tmp_var) {
152 return;
153 }
154 ZVAL_COPY_VALUE(tmp_var, rval);
155 }
156 }
157
tmp_var(php_unserialize_data_t * var_hashx,zend_long num)158 static zend_always_inline zval *tmp_var(php_unserialize_data_t *var_hashx, zend_long num)
159 {
160 var_dtor_entries *var_hash;
161 zend_long used_slots;
162
163 if (!var_hashx || !*var_hashx || num < 1) {
164 return NULL;
165 }
166
167 var_hash = (*var_hashx)->last_dtor;
168 if (!var_hash || var_hash->used_slots + num > VAR_DTOR_ENTRIES_MAX) {
169 var_hash = emalloc(sizeof(var_dtor_entries));
170 var_hash->used_slots = 0;
171 var_hash->next = 0;
172
173 if (!(*var_hashx)->first_dtor) {
174 (*var_hashx)->first_dtor = var_hash;
175 } else {
176 (*var_hashx)->last_dtor->next = var_hash;
177 }
178
179 (*var_hashx)->last_dtor = var_hash;
180 }
181 for (used_slots = var_hash->used_slots; var_hash->used_slots < used_slots + num; var_hash->used_slots++) {
182 ZVAL_UNDEF(&var_hash->data[var_hash->used_slots]);
183 Z_EXTRA(var_hash->data[var_hash->used_slots]) = 0;
184 }
185 return &var_hash->data[used_slots];
186 }
187
var_tmp_var(php_unserialize_data_t * var_hashx)188 PHPAPI zval *var_tmp_var(php_unserialize_data_t *var_hashx)
189 {
190 return tmp_var(var_hashx, 1);
191 }
192
var_replace(php_unserialize_data_t * var_hashx,zval * ozval,zval * nzval)193 PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval *nzval)
194 {
195 zend_long i;
196 var_entries *var_hash = &(*var_hashx)->entries;
197 #if VAR_ENTRIES_DBG
198 fprintf(stderr, "var_replace(" ZEND_LONG_FMT "): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_P(nzval));
199 #endif
200
201 while (var_hash) {
202 for (i = 0; i < var_hash->used_slots; i++) {
203 if (var_hash->data[i] == ozval) {
204 var_hash->data[i] = nzval;
205 /* do not break here */
206 }
207 }
208 var_hash = var_hash->next;
209 }
210 }
211
var_access(php_unserialize_data_t * var_hashx,zend_long id)212 static zval *var_access(php_unserialize_data_t *var_hashx, zend_long id)
213 {
214 var_entries *var_hash = &(*var_hashx)->entries;
215 #if VAR_ENTRIES_DBG
216 fprintf(stderr, "var_access(" ZEND_LONG_FMT "): " ZEND_LONG_FMT "\n", var_hash?var_hash->used_slots:-1L, id);
217 #endif
218
219 while (id >= VAR_ENTRIES_MAX && var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) {
220 var_hash = var_hash->next;
221 id -= VAR_ENTRIES_MAX;
222 }
223
224 if (!var_hash) return NULL;
225
226 if (id < 0 || id >= var_hash->used_slots) return NULL;
227
228 return var_hash->data[id];
229 }
230
var_destroy(php_unserialize_data_t * var_hashx)231 PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
232 {
233 void *next;
234 zend_long i;
235 var_entries *var_hash = (*var_hashx)->entries.next;
236 var_dtor_entries *var_dtor_hash = (*var_hashx)->first_dtor;
237 bool delayed_call_failed = 0;
238
239 #if VAR_ENTRIES_DBG
240 fprintf(stderr, "var_destroy( " ZEND_LONG_FMT ")\n", var_hash?var_hash->used_slots:-1L);
241 #endif
242
243 while (var_hash) {
244 next = var_hash->next;
245 efree_size(var_hash, sizeof(var_entries));
246 var_hash = next;
247 }
248
249 while (var_dtor_hash) {
250 for (i = 0; i < var_dtor_hash->used_slots; i++) {
251 zval *zv = &var_dtor_hash->data[i];
252 #if VAR_ENTRIES_DBG
253 fprintf(stderr, "var_destroy dtor(%p, %ld)\n", &var_dtor_hash->data[i], Z_REFCOUNT_P(&var_dtor_hash->data[i]));
254 #endif
255
256 if (Z_EXTRA_P(zv) == VAR_WAKEUP_FLAG) {
257 /* Perform delayed __wakeup calls */
258 if (!delayed_call_failed) {
259 zval retval;
260 zend_fcall_info fci;
261 zend_fcall_info_cache fci_cache;
262
263 ZEND_ASSERT(Z_TYPE_P(zv) == IS_OBJECT);
264
265 fci.size = sizeof(fci);
266 fci.object = Z_OBJ_P(zv);
267 fci.retval = &retval;
268 fci.param_count = 0;
269 fci.params = NULL;
270 fci.named_params = NULL;
271 ZVAL_UNDEF(&fci.function_name);
272
273 fci_cache.function_handler = zend_hash_find_ptr(
274 &fci.object->ce->function_table, ZSTR_KNOWN(ZEND_STR_WAKEUP));
275 fci_cache.object = fci.object;
276 fci_cache.called_scope = fci.object->ce;
277
278 BG(serialize_lock)++;
279 if (zend_call_function(&fci, &fci_cache) == FAILURE || Z_ISUNDEF(retval)) {
280 delayed_call_failed = 1;
281 GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
282 }
283 BG(serialize_lock)--;
284
285 zval_ptr_dtor(&retval);
286 } else {
287 GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
288 }
289 } else if (Z_EXTRA_P(zv) == VAR_UNSERIALIZE_FLAG) {
290 /* Perform delayed __unserialize calls */
291 if (!delayed_call_failed) {
292 zval param;
293 ZVAL_COPY(¶m, &var_dtor_hash->data[i + 1]);
294
295 BG(serialize_lock)++;
296 zend_call_known_instance_method_with_1_params(
297 Z_OBJCE_P(zv)->__unserialize, Z_OBJ_P(zv), NULL, ¶m);
298 if (EG(exception)) {
299 delayed_call_failed = 1;
300 GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
301 }
302 BG(serialize_lock)--;
303 zval_ptr_dtor(¶m);
304 } else {
305 GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
306 }
307 }
308
309 i_zval_ptr_dtor(zv);
310 }
311 next = var_dtor_hash->next;
312 efree_size(var_dtor_hash, sizeof(var_dtor_entries));
313 var_dtor_hash = next;
314 }
315
316 if ((*var_hashx)->ref_props) {
317 zend_hash_destroy((*var_hashx)->ref_props);
318 FREE_HASHTABLE((*var_hashx)->ref_props);
319 }
320 }
321
322 /* }}} */
323
unserialize_str(const unsigned char ** p,size_t len,size_t maxlen)324 static zend_string *unserialize_str(const unsigned char **p, size_t len, size_t maxlen)
325 {
326 size_t i, j;
327 zend_string *str = zend_string_safe_alloc(1, len, 0, 0);
328 unsigned char *end = *(unsigned char **)p+maxlen;
329
330 if (end < *p) {
331 zend_string_efree(str);
332 return NULL;
333 }
334
335 for (i = 0; i < len; i++) {
336 if (*p >= end) {
337 zend_string_efree(str);
338 return NULL;
339 }
340 if (**p != '\\') {
341 ZSTR_VAL(str)[i] = (char)**p;
342 } else {
343 unsigned char ch = 0;
344
345 for (j = 0; j < 2; j++) {
346 (*p)++;
347 if (**p >= '0' && **p <= '9') {
348 ch = (ch << 4) + (**p -'0');
349 } else if (**p >= 'a' && **p <= 'f') {
350 ch = (ch << 4) + (**p -'a'+10);
351 } else if (**p >= 'A' && **p <= 'F') {
352 ch = (ch << 4) + (**p -'A'+10);
353 } else {
354 zend_string_efree(str);
355 return NULL;
356 }
357 }
358 ZSTR_VAL(str)[i] = (char)ch;
359 }
360 (*p)++;
361 }
362 ZSTR_VAL(str)[i] = 0;
363 ZSTR_LEN(str) = i;
364 return str;
365 }
366
unserialize_allowed_class(zend_string * lcname,php_unserialize_data_t * var_hashx)367 static inline int unserialize_allowed_class(
368 zend_string *lcname, php_unserialize_data_t *var_hashx)
369 {
370 HashTable *classes = (*var_hashx)->allowed_classes;
371
372 if(classes == NULL) {
373 return 1;
374 }
375 if(!zend_hash_num_elements(classes)) {
376 return 0;
377 }
378
379 return zend_hash_exists(classes, lcname);
380 }
381
382 #define YYFILL(n) do { } while (0)
383 #define YYCTYPE unsigned char
384 #define YYCURSOR cursor
385 #define YYLIMIT limit
386 #define YYMARKER marker
387
388
389
390
391
392
parse_iv2(const unsigned char * p,const unsigned char ** q)393 static inline zend_long parse_iv2(const unsigned char *p, const unsigned char **q)
394 {
395 zend_ulong result = 0;
396 zend_ulong neg = 0;
397 const unsigned char *start;
398
399 if (*p == '-') {
400 neg = 1;
401 p++;
402 } else if (UNEXPECTED(*p == '+')) {
403 p++;
404 }
405
406 while (UNEXPECTED(*p == '0')) {
407 p++;
408 }
409
410 start = p;
411
412 while (*p >= '0' && *p <= '9') {
413 result = result * 10 + ((zend_ulong)(*p) - '0');
414 p++;
415 }
416
417 if (q) {
418 *q = p;
419 }
420
421 /* number too long or overflow */
422 if (UNEXPECTED(p - start > MAX_LENGTH_OF_LONG - 1)
423 || (SIZEOF_ZEND_LONG == 4
424 && UNEXPECTED(p - start == MAX_LENGTH_OF_LONG - 1)
425 && UNEXPECTED(*start > '2'))
426 || UNEXPECTED(result > ZEND_LONG_MAX + neg)) {
427 php_error_docref(NULL, E_WARNING, "Numerical result out of range");
428 return (!neg) ? ZEND_LONG_MAX : ZEND_LONG_MIN;
429 }
430
431 return (zend_long) ((!neg) ? result : -result);
432 }
433
parse_iv(const unsigned char * p)434 static inline zend_long parse_iv(const unsigned char *p)
435 {
436 return parse_iv2(p, NULL);
437 }
438
439 /* no need to check for length - re2c already did */
parse_uiv(const unsigned char * p)440 static inline size_t parse_uiv(const unsigned char *p)
441 {
442 unsigned char cursor;
443 size_t result = 0;
444
445 while (1) {
446 cursor = *p;
447 if (cursor >= '0' && cursor <= '9') {
448 result = result * 10 + (size_t)(cursor - (unsigned char)'0');
449 } else {
450 break;
451 }
452 p++;
453 }
454 return result;
455 }
456
457 #define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash
458 #define UNSERIALIZE_PASSTHRU rval, p, max, var_hash
459
460 static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER);
461
process_nested_array_data(UNSERIALIZE_PARAMETER,HashTable * ht,zend_long elements)462 static zend_always_inline int process_nested_array_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements)
463 {
464 if (var_hash) {
465 if ((*var_hash)->max_depth > 0 && (*var_hash)->cur_depth >= (*var_hash)->max_depth) {
466 php_error_docref(NULL, E_WARNING,
467 "Maximum depth of " ZEND_LONG_FMT " exceeded. "
468 "The depth limit can be changed using the max_depth unserialize() option "
469 "or the unserialize_max_depth ini setting",
470 (*var_hash)->max_depth);
471 return 0;
472 }
473 (*var_hash)->cur_depth++;
474 }
475
476 while (elements-- > 0) {
477 zval key, *data;
478 zend_ulong idx;
479
480 ZVAL_UNDEF(&key);
481
482 if (!php_var_unserialize_internal(&key, p, max, NULL)) {
483 zval_ptr_dtor(&key);
484 goto failure;
485 }
486
487 if (Z_TYPE(key) == IS_LONG) {
488 idx = Z_LVAL(key);
489 numeric_key:
490 data = zend_hash_index_lookup(ht, idx);
491 if (UNEXPECTED(Z_TYPE_INFO_P(data) != IS_NULL)) {
492 var_push_dtor_value(var_hash, data);
493 ZVAL_NULL(data);
494 }
495 } else if (Z_TYPE(key) == IS_STRING) {
496 if (UNEXPECTED(ZEND_HANDLE_NUMERIC(Z_STR(key), idx))) {
497 zval_ptr_dtor_str(&key);
498 goto numeric_key;
499 }
500 data = zend_hash_lookup(ht, Z_STR(key));
501 if (UNEXPECTED(Z_TYPE_INFO_P(data) != IS_NULL)) {
502 var_push_dtor_value(var_hash, data);
503 ZVAL_NULL(data);
504 }
505 zval_ptr_dtor_str(&key);
506 } else {
507 zval_ptr_dtor(&key);
508 goto failure;
509 }
510
511 if (!php_var_unserialize_internal(data, p, max, var_hash)) {
512 goto failure;
513 }
514
515 if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
516 (*p)--;
517 goto failure;
518 }
519 }
520
521 if (var_hash) {
522 (*var_hash)->cur_depth--;
523 }
524 return 1;
525
526 failure:
527 if (var_hash) {
528 (*var_hash)->cur_depth--;
529 }
530 return 0;
531 }
532
is_property_visibility_changed(zend_class_entry * ce,zval * key)533 static int is_property_visibility_changed(zend_class_entry *ce, zval *key)
534 {
535 if (zend_hash_num_elements(&ce->properties_info) > 0) {
536 zend_property_info *existing_propinfo;
537 const char *unmangled_class = NULL;
538 const char *unmangled_prop;
539 size_t unmangled_prop_len;
540
541 if (UNEXPECTED(zend_unmangle_property_name_ex(Z_STR_P(key), &unmangled_class, &unmangled_prop, &unmangled_prop_len) == FAILURE)) {
542 zval_ptr_dtor_str(key);
543 return -1;
544 }
545
546 if (unmangled_class == NULL) {
547 existing_propinfo = zend_hash_find_ptr(&ce->properties_info, Z_STR_P(key));
548 if (existing_propinfo != NULL) {
549 zval_ptr_dtor_str(key);
550 ZVAL_STR_COPY(key, existing_propinfo->name);
551 return 1;
552 }
553 } else {
554 if (!strcmp(unmangled_class, "*")
555 || !strcasecmp(unmangled_class, ZSTR_VAL(ce->name))) {
556 existing_propinfo = zend_hash_str_find_ptr(
557 &ce->properties_info, unmangled_prop, unmangled_prop_len);
558 if (existing_propinfo != NULL) {
559 zval_ptr_dtor_str(key);
560 ZVAL_STR_COPY(key, existing_propinfo->name);
561 return 1;
562 }
563 }
564 }
565 }
566 return 0;
567 }
568
569
process_nested_object_data(UNSERIALIZE_PARAMETER,HashTable * ht,zend_long elements,zend_object * obj)570 static zend_always_inline int process_nested_object_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, zend_object *obj)
571 {
572 if (var_hash) {
573 if ((*var_hash)->max_depth > 0 && (*var_hash)->cur_depth >= (*var_hash)->max_depth) {
574 php_error_docref(NULL, E_WARNING,
575 "Maximum depth of " ZEND_LONG_FMT " exceeded. "
576 "The depth limit can be changed using the max_depth unserialize() option "
577 "or the unserialize_max_depth ini setting",
578 (*var_hash)->max_depth);
579 return 0;
580 }
581 (*var_hash)->cur_depth++;
582 }
583
584 while (elements-- > 0) {
585 zval key, *data;
586 zend_property_info *info = NULL;
587
588 ZVAL_UNDEF(&key);
589
590 if (!php_var_unserialize_internal(&key, p, max, NULL)) {
591 zval_ptr_dtor(&key);
592 goto failure;
593 }
594
595 if (EXPECTED(Z_TYPE(key) == IS_STRING)) {
596 string_key:
597 data = zend_hash_find(ht, Z_STR(key));
598 if (data != NULL) {
599 if (Z_TYPE_P(data) == IS_INDIRECT) {
600 declared_property:
601 /* This is a property with a declaration */
602 data = Z_INDIRECT_P(data);
603 info = zend_get_typed_property_info_for_slot(obj, data);
604 if (info) {
605 if (Z_ISREF_P(data)) {
606 /* If the value is overwritten, remove old type source from ref. */
607 ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(data), info);
608 }
609
610 if ((*var_hash)->ref_props) {
611 /* Remove old entry from ref_props table, if it exists. */
612 zend_hash_index_del(
613 (*var_hash)->ref_props, (zend_uintptr_t) data);
614 }
615 }
616 /* We may override default property value, but they are usually immutable */
617 if (Z_REFCOUNTED_P(data)) {
618 var_push_dtor_value(var_hash, data);
619 }
620 ZVAL_NULL(data);
621 } else {
622 /* Unusual override of dynamic property */
623 int ret = is_property_visibility_changed(obj->ce, &key);
624
625 if (ret > 0) {
626 goto second_try;
627 } else if (!ret) {
628 var_push_dtor_value(var_hash, data);
629 ZVAL_NULL(data);
630 } else if (ret < 0) {
631 goto failure;
632 }
633 }
634 } else {
635 int ret = is_property_visibility_changed(obj->ce, &key);
636
637 if (EXPECTED(!ret)) {
638 data = zend_hash_add_new(ht, Z_STR(key), &EG(uninitialized_zval));
639 } else if (ret < 0) {
640 goto failure;
641 } else {
642 second_try:
643 data = zend_hash_lookup(ht, Z_STR(key));
644 if (Z_TYPE_P(data) == IS_INDIRECT) {
645 goto declared_property;
646 } else if (UNEXPECTED(Z_TYPE_INFO_P(data) != IS_NULL)) {
647 var_push_dtor_value(var_hash, data);
648 ZVAL_NULL(data);
649 }
650 }
651 }
652 zval_ptr_dtor_str(&key);
653 } else if (Z_TYPE(key) == IS_LONG) {
654 /* object properties should include no integers */
655 convert_to_string(&key);
656 goto string_key;
657 } else {
658 zval_ptr_dtor(&key);
659 goto failure;
660 }
661
662 if (!php_var_unserialize_internal(data, p, max, var_hash)) {
663 if (info && Z_ISREF_P(data)) {
664 /* Add type source even if we failed to unserialize.
665 * The data is still stored in the property. */
666 ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), info);
667 }
668 goto failure;
669 }
670
671 if (UNEXPECTED(info)) {
672 if (!zend_verify_prop_assignable_by_ref(info, data, /* strict */ 1)) {
673 zval_ptr_dtor(data);
674 ZVAL_UNDEF(data);
675 goto failure;
676 }
677
678 if (Z_ISREF_P(data)) {
679 ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), info);
680 } else {
681 /* Remember to which property this slot belongs, so we can add a
682 * type source if it is turned into a reference lateron. */
683 if (!(*var_hash)->ref_props) {
684 (*var_hash)->ref_props = emalloc(sizeof(HashTable));
685 zend_hash_init((*var_hash)->ref_props, 8, NULL, NULL, 0);
686 }
687 zend_hash_index_update_ptr(
688 (*var_hash)->ref_props, (zend_uintptr_t) data, info);
689 }
690 }
691
692 if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
693 (*p)--;
694 goto failure;
695 }
696 }
697
698 if (var_hash) {
699 (*var_hash)->cur_depth--;
700 }
701 return 1;
702
703 failure:
704 if (var_hash) {
705 (*var_hash)->cur_depth--;
706 }
707 return 0;
708 }
709
finish_nested_data(UNSERIALIZE_PARAMETER)710 static inline int finish_nested_data(UNSERIALIZE_PARAMETER)
711 {
712 if (*p >= max || **p != '}') {
713 return 0;
714 }
715
716 (*p)++;
717 return 1;
718 }
719
object_custom(UNSERIALIZE_PARAMETER,zend_class_entry * ce)720 static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
721 {
722 zend_long datalen;
723
724 datalen = parse_iv2((*p) + 2, p);
725
726 (*p) += 2;
727
728 if (datalen < 0 || (max - (*p)) <= datalen) {
729 zend_error(E_WARNING, "Insufficient data for unserializing - " ZEND_LONG_FMT " required, " ZEND_LONG_FMT " present", datalen, (zend_long)(max - (*p)));
730 return 0;
731 }
732
733 /* Check that '}' is present before calling ce->unserialize() to mitigate issues
734 * with unserialize reading past the end of the passed buffer if the string is not
735 * appropriately terminated (usually NUL terminated, but '}' is also sufficient.) */
736 if ((*p)[datalen] != '}') {
737 return 0;
738 }
739
740 if (ce->unserialize == NULL) {
741 zend_error(E_WARNING, "Class %s has no unserializer", ZSTR_VAL(ce->name));
742 object_init_ex(rval, ce);
743 } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash) != SUCCESS) {
744 return 0;
745 }
746
747 (*p) += datalen + 1; /* +1 for '}' */
748 return 1;
749 }
750
751 #ifdef PHP_WIN32
752 # pragma optimize("", off)
753 #endif
object_common(UNSERIALIZE_PARAMETER,zend_long elements,bool has_unserialize)754 static inline int object_common(UNSERIALIZE_PARAMETER, zend_long elements, bool has_unserialize)
755 {
756 HashTable *ht;
757 bool has_wakeup;
758
759 if (has_unserialize) {
760 zval ary, *tmp;
761
762 if (elements >= HT_MAX_SIZE) {
763 return 0;
764 }
765
766 array_init_size(&ary, elements);
767 /* Avoid reallocation due to packed -> mixed conversion. */
768 zend_hash_real_init_mixed(Z_ARRVAL(ary));
769 if (!process_nested_array_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL(ary), elements)) {
770 ZVAL_DEREF(rval);
771 GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED);
772 zval_ptr_dtor(&ary);
773 return 0;
774 }
775
776 /* Delay __unserialize() call until end of serialization. We use two slots here to
777 * store both the object and the unserialized data array. */
778 ZVAL_DEREF(rval);
779 tmp = tmp_var(var_hash, 2);
780 ZVAL_COPY(tmp, rval);
781 Z_EXTRA_P(tmp) = VAR_UNSERIALIZE_FLAG;
782 tmp++;
783 ZVAL_COPY_VALUE(tmp, &ary);
784
785 return finish_nested_data(UNSERIALIZE_PASSTHRU);
786 }
787
788 has_wakeup = Z_OBJCE_P(rval) != PHP_IC_ENTRY
789 && zend_hash_exists(&Z_OBJCE_P(rval)->function_table, ZSTR_KNOWN(ZEND_STR_WAKEUP));
790
791 ht = Z_OBJPROP_P(rval);
792 if (elements >= (zend_long)(HT_MAX_SIZE - zend_hash_num_elements(ht))) {
793 return 0;
794 }
795
796 zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, HT_FLAGS(ht) & HASH_FLAG_PACKED);
797 if (!process_nested_object_data(UNSERIALIZE_PASSTHRU, ht, elements, Z_OBJ_P(rval))) {
798 if (has_wakeup) {
799 ZVAL_DEREF(rval);
800 GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED);
801 }
802 return 0;
803 }
804
805 ZVAL_DEREF(rval);
806 if (has_wakeup) {
807 /* Delay __wakeup call until end of serialization */
808 zval *wakeup_var = var_tmp_var(var_hash);
809 ZVAL_COPY(wakeup_var, rval);
810 Z_EXTRA_P(wakeup_var) = VAR_WAKEUP_FLAG;
811 }
812
813 return finish_nested_data(UNSERIALIZE_PASSTHRU);
814 }
815 #ifdef PHP_WIN32
816 # pragma optimize("", on)
817 #endif
818
php_var_unserialize(UNSERIALIZE_PARAMETER)819 PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
820 {
821 var_entries *orig_var_entries = (*var_hash)->last;
822 zend_long orig_used_slots = orig_var_entries ? orig_var_entries->used_slots : 0;
823 int result;
824
825 result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU);
826
827 if (!result) {
828 /* If the unserialization failed, mark all elements that have been added to var_hash
829 * as NULL. This will forbid their use by other unserialize() calls in the same
830 * unserialization context. */
831 var_entries *e = orig_var_entries;
832 zend_long s = orig_used_slots;
833 while (e) {
834 for (; s < e->used_slots; s++) {
835 e->data[s] = NULL;
836 }
837
838 e = e->next;
839 s = 0;
840 }
841 }
842
843 return result;
844 }
845
php_var_unserialize_internal(UNSERIALIZE_PARAMETER)846 static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
847 {
848 const unsigned char *cursor, *limit, *marker, *start;
849 zval *rval_ref;
850
851 limit = max;
852 cursor = *p;
853
854 if (YYCURSOR >= YYLIMIT) {
855 return 0;
856 }
857
858 if (var_hash && (*p)[0] != 'R') {
859 var_push(var_hash, rval);
860 }
861
862 start = cursor;
863
864
865 {
866 YYCTYPE yych;
867 static const unsigned char yybm[] = {
868 0, 0, 0, 0, 0, 0, 0, 0,
869 0, 0, 0, 0, 0, 0, 0, 0,
870 0, 0, 0, 0, 0, 0, 0, 0,
871 0, 0, 0, 0, 0, 0, 0, 0,
872 0, 0, 0, 0, 0, 0, 0, 0,
873 0, 0, 0, 0, 0, 0, 0, 0,
874 128, 128, 128, 128, 128, 128, 128, 128,
875 128, 128, 0, 0, 0, 0, 0, 0,
876 0, 0, 0, 0, 0, 0, 0, 0,
877 0, 0, 0, 0, 0, 0, 0, 0,
878 0, 0, 0, 0, 0, 0, 0, 0,
879 0, 0, 0, 0, 0, 0, 0, 0,
880 0, 0, 0, 0, 0, 0, 0, 0,
881 0, 0, 0, 0, 0, 0, 0, 0,
882 0, 0, 0, 0, 0, 0, 0, 0,
883 0, 0, 0, 0, 0, 0, 0, 0,
884 0, 0, 0, 0, 0, 0, 0, 0,
885 0, 0, 0, 0, 0, 0, 0, 0,
886 0, 0, 0, 0, 0, 0, 0, 0,
887 0, 0, 0, 0, 0, 0, 0, 0,
888 0, 0, 0, 0, 0, 0, 0, 0,
889 0, 0, 0, 0, 0, 0, 0, 0,
890 0, 0, 0, 0, 0, 0, 0, 0,
891 0, 0, 0, 0, 0, 0, 0, 0,
892 0, 0, 0, 0, 0, 0, 0, 0,
893 0, 0, 0, 0, 0, 0, 0, 0,
894 0, 0, 0, 0, 0, 0, 0, 0,
895 0, 0, 0, 0, 0, 0, 0, 0,
896 0, 0, 0, 0, 0, 0, 0, 0,
897 0, 0, 0, 0, 0, 0, 0, 0,
898 0, 0, 0, 0, 0, 0, 0, 0,
899 0, 0, 0, 0, 0, 0, 0, 0,
900 };
901 if ((YYLIMIT - YYCURSOR) < 7) YYFILL(7);
902 yych = *YYCURSOR;
903 switch (yych) {
904 case 'C':
905 case 'O': goto yy4;
906 case 'E': goto yy5;
907 case 'N': goto yy6;
908 case 'R': goto yy7;
909 case 'S': goto yy8;
910 case 'a': goto yy9;
911 case 'b': goto yy10;
912 case 'd': goto yy11;
913 case 'i': goto yy12;
914 case 'r': goto yy13;
915 case 's': goto yy14;
916 case '}': goto yy15;
917 default: goto yy2;
918 }
919 yy2:
920 ++YYCURSOR;
921 yy3:
922 { return 0; }
923 yy4:
924 yych = *(YYMARKER = ++YYCURSOR);
925 if (yych == ':') goto yy17;
926 goto yy3;
927 yy5:
928 yych = *(YYMARKER = ++YYCURSOR);
929 if (yych == ':') goto yy19;
930 goto yy3;
931 yy6:
932 yych = *++YYCURSOR;
933 if (yych == ';') goto yy20;
934 goto yy3;
935 yy7:
936 yych = *(YYMARKER = ++YYCURSOR);
937 if (yych == ':') goto yy22;
938 goto yy3;
939 yy8:
940 yych = *(YYMARKER = ++YYCURSOR);
941 if (yych == ':') goto yy23;
942 goto yy3;
943 yy9:
944 yych = *(YYMARKER = ++YYCURSOR);
945 if (yych == ':') goto yy24;
946 goto yy3;
947 yy10:
948 yych = *(YYMARKER = ++YYCURSOR);
949 if (yych == ':') goto yy25;
950 goto yy3;
951 yy11:
952 yych = *(YYMARKER = ++YYCURSOR);
953 if (yych == ':') goto yy26;
954 goto yy3;
955 yy12:
956 yych = *(YYMARKER = ++YYCURSOR);
957 if (yych == ':') goto yy27;
958 goto yy3;
959 yy13:
960 yych = *(YYMARKER = ++YYCURSOR);
961 if (yych == ':') goto yy28;
962 goto yy3;
963 yy14:
964 yych = *(YYMARKER = ++YYCURSOR);
965 if (yych == ':') goto yy29;
966 goto yy3;
967 yy15:
968 ++YYCURSOR;
969 {
970 /* this is the case where we have less data than planned */
971 php_error_docref(NULL, E_NOTICE, "Unexpected end of serialized data");
972 return 0; /* not sure if it should be 0 or 1 here? */
973 }
974 yy17:
975 yych = *++YYCURSOR;
976 if (yybm[0+yych] & 128) {
977 goto yy30;
978 }
979 yy18:
980 YYCURSOR = YYMARKER;
981 goto yy3;
982 yy19:
983 yych = *++YYCURSOR;
984 if (yych <= '/') goto yy18;
985 if (yych <= '9') goto yy32;
986 goto yy18;
987 yy20:
988 ++YYCURSOR;
989 {
990 *p = YYCURSOR;
991 ZVAL_NULL(rval);
992 return 1;
993 }
994 yy22:
995 yych = *++YYCURSOR;
996 if (yych <= '/') goto yy18;
997 if (yych <= '9') goto yy34;
998 goto yy18;
999 yy23:
1000 yych = *++YYCURSOR;
1001 if (yych <= '/') goto yy18;
1002 if (yych <= '9') goto yy36;
1003 goto yy18;
1004 yy24:
1005 yych = *++YYCURSOR;
1006 if (yych <= '/') goto yy18;
1007 if (yych <= '9') goto yy38;
1008 goto yy18;
1009 yy25:
1010 yych = *++YYCURSOR;
1011 if (yych <= '/') goto yy18;
1012 if (yych <= '0') goto yy40;
1013 if (yych <= '1') goto yy41;
1014 goto yy18;
1015 yy26:
1016 yych = *++YYCURSOR;
1017 if (yych <= '/') {
1018 if (yych <= ',') {
1019 if (yych == '+') goto yy42;
1020 goto yy18;
1021 } else {
1022 if (yych <= '-') goto yy43;
1023 if (yych <= '.') goto yy44;
1024 goto yy18;
1025 }
1026 } else {
1027 if (yych <= 'I') {
1028 if (yych <= '9') goto yy45;
1029 if (yych <= 'H') goto yy18;
1030 goto yy47;
1031 } else {
1032 if (yych == 'N') goto yy48;
1033 goto yy18;
1034 }
1035 }
1036 yy27:
1037 yych = *++YYCURSOR;
1038 if (yych <= ',') {
1039 if (yych == '+') goto yy49;
1040 goto yy18;
1041 } else {
1042 if (yych <= '-') goto yy49;
1043 if (yych <= '/') goto yy18;
1044 if (yych <= '9') goto yy50;
1045 goto yy18;
1046 }
1047 yy28:
1048 yych = *++YYCURSOR;
1049 if (yych <= '/') goto yy18;
1050 if (yych <= '9') goto yy52;
1051 goto yy18;
1052 yy29:
1053 yych = *++YYCURSOR;
1054 if (yych <= '/') goto yy18;
1055 if (yych <= '9') goto yy54;
1056 goto yy18;
1057 yy30:
1058 ++YYCURSOR;
1059 if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1060 yych = *YYCURSOR;
1061 if (yybm[0+yych] & 128) {
1062 goto yy30;
1063 }
1064 if (yych <= '/') goto yy18;
1065 if (yych <= ':') goto yy56;
1066 goto yy18;
1067 yy32:
1068 ++YYCURSOR;
1069 if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1070 yych = *YYCURSOR;
1071 if (yych <= '/') goto yy18;
1072 if (yych <= '9') goto yy32;
1073 if (yych <= ':') goto yy57;
1074 goto yy18;
1075 yy34:
1076 ++YYCURSOR;
1077 if (YYLIMIT <= YYCURSOR) YYFILL(1);
1078 yych = *YYCURSOR;
1079 if (yych <= '/') goto yy18;
1080 if (yych <= '9') goto yy34;
1081 if (yych == ';') goto yy58;
1082 goto yy18;
1083 yy36:
1084 ++YYCURSOR;
1085 if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1086 yych = *YYCURSOR;
1087 if (yych <= '/') goto yy18;
1088 if (yych <= '9') goto yy36;
1089 if (yych <= ':') goto yy60;
1090 goto yy18;
1091 yy38:
1092 ++YYCURSOR;
1093 if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1094 yych = *YYCURSOR;
1095 if (yych <= '/') goto yy18;
1096 if (yych <= '9') goto yy38;
1097 if (yych <= ':') goto yy61;
1098 goto yy18;
1099 yy40:
1100 yych = *++YYCURSOR;
1101 if (yych == ';') goto yy62;
1102 goto yy18;
1103 yy41:
1104 yych = *++YYCURSOR;
1105 if (yych == ';') goto yy64;
1106 goto yy18;
1107 yy42:
1108 yych = *++YYCURSOR;
1109 if (yych == '.') goto yy44;
1110 if (yych <= '/') goto yy18;
1111 if (yych <= '9') goto yy45;
1112 goto yy18;
1113 yy43:
1114 yych = *++YYCURSOR;
1115 if (yych <= '/') {
1116 if (yych != '.') goto yy18;
1117 } else {
1118 if (yych <= '9') goto yy45;
1119 if (yych == 'I') goto yy47;
1120 goto yy18;
1121 }
1122 yy44:
1123 yych = *++YYCURSOR;
1124 if (yych <= '/') goto yy18;
1125 if (yych <= '9') goto yy66;
1126 goto yy18;
1127 yy45:
1128 ++YYCURSOR;
1129 if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
1130 yych = *YYCURSOR;
1131 if (yych <= ':') {
1132 if (yych <= '.') {
1133 if (yych <= '-') goto yy18;
1134 goto yy66;
1135 } else {
1136 if (yych <= '/') goto yy18;
1137 if (yych <= '9') goto yy45;
1138 goto yy18;
1139 }
1140 } else {
1141 if (yych <= 'E') {
1142 if (yych <= ';') goto yy68;
1143 if (yych <= 'D') goto yy18;
1144 goto yy70;
1145 } else {
1146 if (yych == 'e') goto yy70;
1147 goto yy18;
1148 }
1149 }
1150 yy47:
1151 yych = *++YYCURSOR;
1152 if (yych == 'N') goto yy71;
1153 goto yy18;
1154 yy48:
1155 yych = *++YYCURSOR;
1156 if (yych == 'A') goto yy72;
1157 goto yy18;
1158 yy49:
1159 yych = *++YYCURSOR;
1160 if (yych <= '/') goto yy18;
1161 if (yych >= ':') goto yy18;
1162 yy50:
1163 ++YYCURSOR;
1164 if (YYLIMIT <= YYCURSOR) YYFILL(1);
1165 yych = *YYCURSOR;
1166 if (yych <= '/') goto yy18;
1167 if (yych <= '9') goto yy50;
1168 if (yych == ';') goto yy73;
1169 goto yy18;
1170 yy52:
1171 ++YYCURSOR;
1172 if (YYLIMIT <= YYCURSOR) YYFILL(1);
1173 yych = *YYCURSOR;
1174 if (yych <= '/') goto yy18;
1175 if (yych <= '9') goto yy52;
1176 if (yych == ';') goto yy75;
1177 goto yy18;
1178 yy54:
1179 ++YYCURSOR;
1180 if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1181 yych = *YYCURSOR;
1182 if (yych <= '/') goto yy18;
1183 if (yych <= '9') goto yy54;
1184 if (yych <= ':') goto yy77;
1185 goto yy18;
1186 yy56:
1187 yych = *++YYCURSOR;
1188 if (yych == '"') goto yy78;
1189 goto yy18;
1190 yy57:
1191 yych = *++YYCURSOR;
1192 if (yych == '"') goto yy80;
1193 goto yy18;
1194 yy58:
1195 ++YYCURSOR;
1196 {
1197 zend_long id;
1198
1199 *p = YYCURSOR;
1200 if (!var_hash) return 0;
1201
1202 id = parse_uiv(start + 2) - 1;
1203 if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) {
1204 return 0;
1205 }
1206
1207 if (rval_ref == rval || (Z_ISREF_P(rval_ref) && Z_REFVAL_P(rval_ref) == rval)) {
1208 return 0;
1209 }
1210
1211 if (!Z_ISREF_P(rval_ref)) {
1212 zend_property_info *info = NULL;
1213 if ((*var_hash)->ref_props) {
1214 info = zend_hash_index_find_ptr((*var_hash)->ref_props, (zend_uintptr_t) rval_ref);
1215 }
1216 ZVAL_NEW_REF(rval_ref, rval_ref);
1217 if (info) {
1218 ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(rval_ref), info);
1219 }
1220 }
1221
1222 ZVAL_COPY(rval, rval_ref);
1223
1224 return 1;
1225 }
1226 yy60:
1227 yych = *++YYCURSOR;
1228 if (yych == '"') goto yy82;
1229 goto yy18;
1230 yy61:
1231 yych = *++YYCURSOR;
1232 if (yych == '{') goto yy84;
1233 goto yy18;
1234 yy62:
1235 ++YYCURSOR;
1236 {
1237 *p = YYCURSOR;
1238 ZVAL_FALSE(rval);
1239 return 1;
1240 }
1241 yy64:
1242 ++YYCURSOR;
1243 {
1244 *p = YYCURSOR;
1245 ZVAL_TRUE(rval);
1246 return 1;
1247 }
1248 yy66:
1249 ++YYCURSOR;
1250 if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
1251 yych = *YYCURSOR;
1252 if (yych <= ';') {
1253 if (yych <= '/') goto yy18;
1254 if (yych <= '9') goto yy66;
1255 if (yych <= ':') goto yy18;
1256 } else {
1257 if (yych <= 'E') {
1258 if (yych <= 'D') goto yy18;
1259 goto yy70;
1260 } else {
1261 if (yych == 'e') goto yy70;
1262 goto yy18;
1263 }
1264 }
1265 yy68:
1266 ++YYCURSOR;
1267 {
1268 #if SIZEOF_ZEND_LONG == 4
1269 use_double:
1270 #endif
1271 *p = YYCURSOR;
1272 ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL));
1273 return 1;
1274 }
1275 yy70:
1276 yych = *++YYCURSOR;
1277 if (yych <= ',') {
1278 if (yych == '+') goto yy86;
1279 goto yy18;
1280 } else {
1281 if (yych <= '-') goto yy86;
1282 if (yych <= '/') goto yy18;
1283 if (yych <= '9') goto yy87;
1284 goto yy18;
1285 }
1286 yy71:
1287 yych = *++YYCURSOR;
1288 if (yych == 'F') goto yy89;
1289 goto yy18;
1290 yy72:
1291 yych = *++YYCURSOR;
1292 if (yych == 'N') goto yy89;
1293 goto yy18;
1294 yy73:
1295 ++YYCURSOR;
1296 {
1297 #if SIZEOF_ZEND_LONG == 4
1298 int digits = YYCURSOR - start - 3;
1299
1300 if (start[2] == '-' || start[2] == '+') {
1301 digits--;
1302 }
1303
1304 /* Use double for large zend_long values that were serialized on a 64-bit system */
1305 if (digits >= MAX_LENGTH_OF_LONG - 1) {
1306 if (digits == MAX_LENGTH_OF_LONG - 1) {
1307 int cmp = strncmp((char*)YYCURSOR - MAX_LENGTH_OF_LONG, long_min_digits, MAX_LENGTH_OF_LONG - 1);
1308
1309 if (!(cmp < 0 || (cmp == 0 && start[2] == '-'))) {
1310 goto use_double;
1311 }
1312 } else {
1313 goto use_double;
1314 }
1315 }
1316 #endif
1317 *p = YYCURSOR;
1318 ZVAL_LONG(rval, parse_iv(start + 2));
1319 return 1;
1320 }
1321 yy75:
1322 ++YYCURSOR;
1323 {
1324 zend_long id;
1325
1326 *p = YYCURSOR;
1327 if (!var_hash) return 0;
1328
1329 id = parse_uiv(start + 2) - 1;
1330 if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) {
1331 return 0;
1332 }
1333
1334 if (rval_ref == rval) {
1335 return 0;
1336 }
1337
1338 ZVAL_DEREF(rval_ref);
1339 if (Z_TYPE_P(rval_ref) != IS_OBJECT) {
1340 return 0;
1341 }
1342
1343 ZVAL_COPY(rval, rval_ref);
1344
1345 return 1;
1346 }
1347 yy77:
1348 yych = *++YYCURSOR;
1349 if (yych == '"') goto yy90;
1350 goto yy18;
1351 yy78:
1352 ++YYCURSOR;
1353 {
1354 size_t len, maxlen;
1355 zend_long elements;
1356 char *str;
1357 zend_string *class_name;
1358 zend_class_entry *ce;
1359 bool incomplete_class = 0;
1360 bool custom_object = 0;
1361 bool has_unserialize = 0;
1362
1363 zval user_func;
1364 zval retval;
1365 zval args[1];
1366
1367 if (!var_hash) return 0;
1368 if (*start == 'C') {
1369 custom_object = 1;
1370 }
1371
1372 len = parse_uiv(start + 2);
1373 maxlen = max - YYCURSOR;
1374 if (maxlen < len || len == 0) {
1375 *p = start + 2;
1376 return 0;
1377 }
1378
1379 str = (char*)YYCURSOR;
1380
1381 YYCURSOR += len;
1382
1383 if (*(YYCURSOR) != '"') {
1384 *p = YYCURSOR;
1385 return 0;
1386 }
1387 if (*(YYCURSOR+1) != ':') {
1388 *p = YYCURSOR+1;
1389 return 0;
1390 }
1391
1392 if (len == 0) {
1393 /* empty class names are not allowed */
1394 return 0;
1395 }
1396
1397 if (str[0] == '\000') {
1398 /* runtime definition keys are not allowed */
1399 return 0;
1400 }
1401
1402 if (str[0] == '\\') {
1403 /* class name can't start from namespace separator */
1404 return 0;
1405 }
1406
1407 class_name = zend_string_init_interned(str, len, 0);
1408
1409 do {
1410 zend_string *lc_name;
1411
1412 if (!(*var_hash)->allowed_classes && ZSTR_HAS_CE_CACHE(class_name)) {
1413 ce = ZSTR_GET_CE_CACHE(class_name);
1414 if (ce) {
1415 break;
1416 }
1417 }
1418
1419 lc_name = zend_string_tolower(class_name);
1420 if(!unserialize_allowed_class(lc_name, var_hash)) {
1421 zend_string_release_ex(lc_name, 0);
1422 if (!zend_is_valid_class_name(class_name)) {
1423 zend_string_release_ex(class_name, 0);
1424 return 0;
1425 }
1426 incomplete_class = 1;
1427 ce = PHP_IC_ENTRY;
1428 break;
1429 }
1430
1431 if ((*var_hash)->allowed_classes && ZSTR_HAS_CE_CACHE(class_name)) {
1432 ce = ZSTR_GET_CE_CACHE(class_name);
1433 if (ce) {
1434 zend_string_release_ex(lc_name, 0);
1435 break;
1436 }
1437 }
1438
1439 ce = zend_hash_find_ptr(EG(class_table), lc_name);
1440 if (ce
1441 && (ce->ce_flags & ZEND_ACC_LINKED)
1442 && !(ce->ce_flags & ZEND_ACC_ANON_CLASS)) {
1443 zend_string_release_ex(lc_name, 0);
1444 break;
1445 }
1446
1447 if (!ZSTR_HAS_CE_CACHE(class_name) && !zend_is_valid_class_name(class_name)) {
1448 zend_string_release_ex(lc_name, 0);
1449 zend_string_release_ex(class_name, 0);
1450 return 0;
1451 }
1452
1453 /* Try to find class directly */
1454 BG(serialize_lock)++;
1455 ce = zend_lookup_class_ex(class_name, lc_name, 0);
1456 zend_string_release_ex(lc_name, 0);
1457 if (ce) {
1458 BG(serialize_lock)--;
1459 if (EG(exception)) {
1460 zend_string_release_ex(class_name, 0);
1461 return 0;
1462 }
1463 break;
1464 }
1465 BG(serialize_lock)--;
1466
1467 if (EG(exception)) {
1468 zend_string_release_ex(class_name, 0);
1469 return 0;
1470 }
1471
1472 /* Check for unserialize callback */
1473 if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
1474 incomplete_class = 1;
1475 ce = PHP_IC_ENTRY;
1476 break;
1477 }
1478
1479 /* Call unserialize callback */
1480 ZVAL_STRING(&user_func, PG(unserialize_callback_func));
1481
1482 ZVAL_STR_COPY(&args[0], class_name);
1483 BG(serialize_lock)++;
1484 if (call_user_function(NULL, NULL, &user_func, &retval, 1, args) != SUCCESS) {
1485 BG(serialize_lock)--;
1486 if (EG(exception)) {
1487 zend_string_release_ex(class_name, 0);
1488 zval_ptr_dtor(&user_func);
1489 zval_ptr_dtor(&args[0]);
1490 return 0;
1491 }
1492 php_error_docref(NULL, E_WARNING, "defined (%s) but not found", Z_STRVAL(user_func));
1493 incomplete_class = 1;
1494 ce = PHP_IC_ENTRY;
1495 zval_ptr_dtor(&user_func);
1496 zval_ptr_dtor(&args[0]);
1497 break;
1498 }
1499 BG(serialize_lock)--;
1500 zval_ptr_dtor(&retval);
1501 if (EG(exception)) {
1502 zend_string_release_ex(class_name, 0);
1503 zval_ptr_dtor(&user_func);
1504 zval_ptr_dtor(&args[0]);
1505 return 0;
1506 }
1507
1508 /* The callback function may have defined the class */
1509 BG(serialize_lock)++;
1510 if ((ce = zend_lookup_class(class_name)) == NULL) {
1511 php_error_docref(NULL, E_WARNING, "Function %s() hasn't defined the class it was called for", Z_STRVAL(user_func));
1512 incomplete_class = 1;
1513 ce = PHP_IC_ENTRY;
1514 }
1515 BG(serialize_lock)--;
1516
1517 zval_ptr_dtor(&user_func);
1518 zval_ptr_dtor(&args[0]);
1519 } while (0);
1520
1521 *p = YYCURSOR;
1522
1523 if (ce->ce_flags & ZEND_ACC_NOT_SERIALIZABLE) {
1524 zend_throw_exception_ex(NULL, 0, "Unserialization of '%s' is not allowed",
1525 ZSTR_VAL(ce->name));
1526 zend_string_release_ex(class_name, 0);
1527 return 0;
1528 }
1529
1530 if (custom_object) {
1531 int ret;
1532
1533 ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
1534
1535 if (ret && incomplete_class) {
1536 php_store_class_name(rval, class_name);
1537 }
1538 zend_string_release_ex(class_name, 0);
1539 return ret;
1540 }
1541
1542 if (*p >= max - 2) {
1543 zend_error(E_WARNING, "Bad unserialize data");
1544 zend_string_release_ex(class_name, 0);
1545 return 0;
1546 }
1547
1548 elements = parse_iv2(*p + 2, p);
1549 if (elements < 0 || IS_FAKE_ELEM_COUNT(elements, max - YYCURSOR)) {
1550 zend_string_release_ex(class_name, 0);
1551 return 0;
1552 }
1553
1554 *p += 2;
1555
1556 has_unserialize = !incomplete_class && ce->__unserialize;
1557
1558 /* If this class implements Serializable, it should not land here but in object_custom().
1559 * The passed string obviously doesn't descend from the regular serializer. However, if
1560 * there is both Serializable::unserialize() and __unserialize(), then both may be used,
1561 * depending on the serialization format. */
1562 if (ce->serialize != NULL && !has_unserialize) {
1563 zend_error(E_WARNING, "Erroneous data format for unserializing '%s'", ZSTR_VAL(ce->name));
1564 zend_string_release_ex(class_name, 0);
1565 return 0;
1566 }
1567
1568 if (object_init_ex(rval, ce) == FAILURE) {
1569 zend_string_release_ex(class_name, 0);
1570 return 0;
1571 }
1572
1573 if (incomplete_class) {
1574 php_store_class_name(rval, class_name);
1575 }
1576 zend_string_release_ex(class_name, 0);
1577
1578 return object_common(UNSERIALIZE_PASSTHRU, elements, has_unserialize);
1579 }
1580 yy80:
1581 ++YYCURSOR;
1582 {
1583 if (!var_hash) return 0;
1584
1585 size_t len = parse_uiv(start + 2);
1586 size_t maxlen = max - YYCURSOR;
1587 if (maxlen < len || len == 0) {
1588 *p = start + 2;
1589 return 0;
1590 }
1591
1592 char *str = (char *) YYCURSOR;
1593 YYCURSOR += len;
1594
1595 if (*(YYCURSOR) != '"') {
1596 *p = YYCURSOR;
1597 return 0;
1598 }
1599 if (*(YYCURSOR+1) != ';') {
1600 *p = YYCURSOR+1;
1601 return 0;
1602 }
1603
1604 char *colon_ptr = memchr(str, ':', len);
1605 if (colon_ptr == NULL) {
1606 php_error_docref(NULL, E_WARNING, "Invalid enum name '%.*s' (missing colon)", (int) len, str);
1607 return 0;
1608 }
1609 size_t colon_pos = colon_ptr - str;
1610
1611 zend_string *enum_name = zend_string_init(str, colon_pos, 0);
1612 zend_string *case_name = zend_string_init(&str[colon_pos + 1], len - colon_pos - 1, 0);
1613
1614 if (!zend_is_valid_class_name(enum_name)) {
1615 goto fail;
1616 }
1617
1618 zend_class_entry *ce = zend_lookup_class(enum_name);
1619 if (!ce) {
1620 php_error_docref(NULL, E_WARNING, "Class '%s' not found", ZSTR_VAL(enum_name));
1621 goto fail;
1622 }
1623 if (!(ce->ce_flags & ZEND_ACC_ENUM)) {
1624 php_error_docref(NULL, E_WARNING, "Class '%s' is not an enum", ZSTR_VAL(enum_name));
1625 goto fail;
1626 }
1627
1628 YYCURSOR += 2;
1629 *p = YYCURSOR;
1630
1631 zend_class_constant *c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), case_name);
1632 if (!c) {
1633 php_error_docref(NULL, E_WARNING, "Undefined constant %s::%s", ZSTR_VAL(enum_name), ZSTR_VAL(case_name));
1634 goto fail;
1635 }
1636
1637 if (!(ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE)) {
1638 php_error_docref(NULL, E_WARNING, "%s::%s is not an enum case", ZSTR_VAL(enum_name), ZSTR_VAL(case_name));
1639 goto fail;
1640 }
1641
1642 zend_string_release_ex(enum_name, 0);
1643 zend_string_release_ex(case_name, 0);
1644
1645 zval *value = &c->value;
1646 if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
1647 if (zval_update_constant_ex(value, c->ce) == FAILURE) {
1648 return 0;
1649 }
1650 }
1651 ZEND_ASSERT(Z_TYPE_P(value) == IS_OBJECT);
1652 ZVAL_COPY(rval, value);
1653
1654 return 1;
1655
1656 fail:
1657 zend_string_release_ex(enum_name, 0);
1658 zend_string_release_ex(case_name, 0);
1659 return 0;
1660 }
1661 yy82:
1662 ++YYCURSOR;
1663 {
1664 size_t len, maxlen;
1665 zend_string *str;
1666
1667 len = parse_uiv(start + 2);
1668 maxlen = max - YYCURSOR;
1669 if (maxlen < len) {
1670 *p = start + 2;
1671 return 0;
1672 }
1673
1674 if ((str = unserialize_str(&YYCURSOR, len, maxlen)) == NULL) {
1675 return 0;
1676 }
1677
1678 if (*(YYCURSOR) != '"') {
1679 zend_string_efree(str);
1680 *p = YYCURSOR;
1681 return 0;
1682 }
1683
1684 if (*(YYCURSOR + 1) != ';') {
1685 efree(str);
1686 *p = YYCURSOR + 1;
1687 return 0;
1688 }
1689
1690 YYCURSOR += 2;
1691 *p = YYCURSOR;
1692
1693 ZVAL_STR(rval, str);
1694 return 1;
1695 }
1696 yy84:
1697 ++YYCURSOR;
1698 {
1699 zend_long elements = parse_iv(start + 2);
1700 /* use iv() not uiv() in order to check data range */
1701 *p = YYCURSOR;
1702 if (!var_hash) return 0;
1703
1704 if (elements < 0 || elements >= HT_MAX_SIZE || IS_FAKE_ELEM_COUNT(elements, max - YYCURSOR)) {
1705 return 0;
1706 }
1707
1708 if (elements) {
1709 array_init_size(rval, elements);
1710 /* we can't convert from packed to hash during unserialization, because
1711 reference to some zvals might be kept in var_hash (to support references) */
1712 zend_hash_real_init_mixed(Z_ARRVAL_P(rval));
1713 } else {
1714 ZVAL_EMPTY_ARRAY(rval);
1715 return finish_nested_data(UNSERIALIZE_PASSTHRU);
1716 }
1717
1718 /* The array may contain references to itself, in which case we'll be modifying an
1719 * rc>1 array. This is okay, since the array is, ostensibly, only visible to
1720 * unserialize (in practice unserialization handlers also see it). Ideally we should
1721 * prohibit "r:" references to non-objects, as we only generate them for objects. */
1722 HT_ALLOW_COW_VIOLATION(Z_ARRVAL_P(rval));
1723
1724 if (!process_nested_array_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements)) {
1725 return 0;
1726 }
1727
1728 return finish_nested_data(UNSERIALIZE_PASSTHRU);
1729 }
1730 yy86:
1731 yych = *++YYCURSOR;
1732 if (yych <= '/') goto yy18;
1733 if (yych >= ':') goto yy18;
1734 yy87:
1735 ++YYCURSOR;
1736 if (YYLIMIT <= YYCURSOR) YYFILL(1);
1737 yych = *YYCURSOR;
1738 if (yych <= '/') goto yy18;
1739 if (yych <= '9') goto yy87;
1740 if (yych == ';') goto yy68;
1741 goto yy18;
1742 yy89:
1743 yych = *++YYCURSOR;
1744 if (yych == ';') goto yy92;
1745 goto yy18;
1746 yy90:
1747 ++YYCURSOR;
1748 {
1749 size_t len, maxlen;
1750 char *str;
1751
1752 len = parse_uiv(start + 2);
1753 maxlen = max - YYCURSOR;
1754 if (maxlen < len) {
1755 *p = start + 2;
1756 return 0;
1757 }
1758
1759 str = (char*)YYCURSOR;
1760
1761 YYCURSOR += len;
1762
1763 if (*(YYCURSOR) != '"') {
1764 *p = YYCURSOR;
1765 return 0;
1766 }
1767
1768 if (*(YYCURSOR + 1) != ';') {
1769 *p = YYCURSOR + 1;
1770 return 0;
1771 }
1772
1773 YYCURSOR += 2;
1774 *p = YYCURSOR;
1775
1776 if (!var_hash) {
1777 /* Array or object key unserialization */
1778 ZVAL_STR(rval, zend_string_init_existing_interned(str, len, 0));
1779 } else {
1780 ZVAL_STRINGL_FAST(rval, str, len);
1781 }
1782 return 1;
1783 }
1784 yy92:
1785 ++YYCURSOR;
1786 {
1787 *p = YYCURSOR;
1788
1789 if (!strncmp((char*)start + 2, "NAN", 3)) {
1790 ZVAL_DOUBLE(rval, ZEND_NAN);
1791 } else if (!strncmp((char*)start + 2, "INF", 3)) {
1792 ZVAL_DOUBLE(rval, ZEND_INFINITY);
1793 } else if (!strncmp((char*)start + 2, "-INF", 4)) {
1794 ZVAL_DOUBLE(rval, -ZEND_INFINITY);
1795 } else {
1796 ZVAL_NULL(rval);
1797 }
1798
1799 return 1;
1800 }
1801 }
1802
1803
1804 return 0;
1805 }
1806