Coverage Report

Created: 2026-06-02 06:36

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