Coverage Report

Created: 2025-12-14 06:05

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