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
75
#define VAR_ENTRIES_MAX 1018     /* 1024 - offsetof(php_unserialize_data, entries) / sizeof(void*) */
27
2
#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
6
#define VAR_WAKEUP_FLAG 1
33
5
#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
33
  ((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
48
PHPAPI php_unserialize_data_t php_var_unserialize_init(void) {
63
48
  php_unserialize_data_t d;
64
  /* fprintf(stderr, "UNSERIALIZE_INIT    == lock: %u, level: %u\n", BG(serialize_lock), BG(unserialize).level); */
65
48
  if (BG(serialize_lock) || !BG(unserialize).level) {
66
48
    d = emalloc(sizeof(struct php_unserialize_data));
67
48
    d->last = &d->entries;
68
48
    d->first_dtor = d->last_dtor = NULL;
69
48
    d->allowed_classes = NULL;
70
48
    d->ref_props = NULL;
71
48
    d->cur_depth = 0;
72
48
    d->max_depth = BG(unserialize_max_depth);
73
48
    d->entries.used_slots = 0;
74
48
    d->entries.next = NULL;
75
48
    if (!BG(serialize_lock)) {
76
48
      BG(unserialize).data = d;
77
48
      BG(unserialize).level = 1;
78
48
    }
79
48
  } else {
80
0
    d = BG(unserialize).data;
81
0
    ++BG(unserialize).level;
82
0
  }
83
48
  return d;
84
48
}
85
86
48
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
48
  if (BG(serialize_lock) || BG(unserialize).level == 1) {
89
48
    var_destroy(&d);
90
48
    efree(d);
91
48
  }
92
48
  if (!BG(serialize_lock) && !--BG(unserialize).level) {
93
48
    BG(unserialize).data = NULL;
94
48
  }
95
48
}
96
97
48
PHPAPI HashTable *php_var_unserialize_get_allowed_classes(php_unserialize_data_t d) {
98
48
  return d->allowed_classes;
99
48
}
100
48
PHPAPI void php_var_unserialize_set_allowed_classes(php_unserialize_data_t d, HashTable *classes) {
101
48
  d->allowed_classes = classes;
102
48
}
103
104
48
PHPAPI void php_var_unserialize_set_max_depth(php_unserialize_data_t d, zend_long max_depth) {
105
48
  d->max_depth = max_depth;
106
48
}
107
48
PHPAPI zend_long php_var_unserialize_get_max_depth(php_unserialize_data_t d) {
108
48
  return d->max_depth;
109
48
}
110
111
48
PHPAPI void php_var_unserialize_set_cur_depth(php_unserialize_data_t d, zend_long cur_depth) {
112
48
  d->cur_depth = cur_depth;
113
48
}
114
48
PHPAPI zend_long php_var_unserialize_get_cur_depth(php_unserialize_data_t d) {
115
48
  return d->cur_depth;
116
48
}
117
118
static inline void var_push(php_unserialize_data_t *var_hashx, zval *rval)
119
73
{
120
73
  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
73
  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
73
  var_hash->data[var_hash->used_slots++] = rval;
135
73
}
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
2
{
150
2
  if (Z_REFCOUNTED_P(rval)) {
151
2
    zval *tmp_var = var_tmp_var(var_hashx);
152
2
    if (!tmp_var) {
153
0
      return;
154
0
    }
155
2
    ZVAL_COPY_VALUE(tmp_var, rval);
156
2
  }
157
2
}
158
159
static zend_always_inline zval *tmp_var(php_unserialize_data_t *var_hashx, zend_long num)
160
4
{
161
4
    var_dtor_entries *var_hash;
162
4
  zend_long used_slots;
163
164
4
    if (!var_hashx || !*var_hashx || num < 1) {
165
0
        return NULL;
166
0
    }
167
168
4
    var_hash = (*var_hashx)->last_dtor;
169
4
    if (!var_hash || var_hash->used_slots + num > VAR_DTOR_ENTRIES_MAX) {
170
2
        var_hash = emalloc(sizeof(var_dtor_entries));
171
2
        var_hash->used_slots = 0;
172
2
        var_hash->next = 0;
173
174
2
        if (!(*var_hashx)->first_dtor) {
175
2
            (*var_hashx)->first_dtor = var_hash;
176
2
        } else {
177
0
            (*var_hashx)->last_dtor->next = var_hash;
178
0
        }
179
180
2
        (*var_hashx)->last_dtor = var_hash;
181
2
    }
182
9
  for (used_slots = var_hash->used_slots; var_hash->used_slots < used_slots + num; var_hash->used_slots++) {
183
5
    ZVAL_UNDEF(&var_hash->data[var_hash->used_slots]);
184
5
    Z_EXTRA(var_hash->data[var_hash->used_slots]) = 0;
185
5
  }
186
4
    return &var_hash->data[used_slots];
187
4
}
188
189
PHPAPI zval *var_tmp_var(php_unserialize_data_t *var_hashx)
190
3
{
191
3
    return tmp_var(var_hashx, 1);
192
3
}
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
1
{
215
1
  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
1
  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
1
  if (!var_hash) return NULL;
226
227
1
  if (id < 0 || id >= var_hash->used_slots) return NULL;
228
229
1
  return var_hash->data[id];
230
1
}
231
232
PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
233
48
{
234
48
  void *next;
235
48
  zend_long i;
236
48
  var_entries *var_hash = (*var_hashx)->entries.next;
237
48
  var_dtor_entries *var_dtor_hash = (*var_hashx)->first_dtor;
238
48
  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
48
  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
50
  while (var_dtor_hash) {
251
7
    for (i = 0; i < var_dtor_hash->used_slots; i++) {
252
5
      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
5
      if (Z_EXTRA_P(zv) == VAR_WAKEUP_FLAG) {
258
        /* Perform delayed __wakeup calls */
259
1
        if (!delayed_call_failed) {
260
1
          zval retval;
261
1
          zend_fcall_info fci;
262
1
          zend_fcall_info_cache fci_cache;
263
264
1
          ZEND_ASSERT(Z_TYPE_P(zv) == IS_OBJECT);
265
266
1
          fci.size = sizeof(fci);
267
1
          fci.object = Z_OBJ_P(zv);
268
1
          fci.retval = &retval;
269
1
          fci.param_count = 0;
270
1
          fci.params = NULL;
271
1
          fci.named_params = NULL;
272
1
          ZVAL_UNDEF(&fci.function_name);
273
274
1
          fci_cache.function_handler = zend_hash_find_ptr(
275
1
            &fci.object->ce->function_table, ZSTR_KNOWN(ZEND_STR_WAKEUP));
276
1
          fci_cache.object = fci.object;
277
1
          fci_cache.called_scope = fci.object->ce;
278
279
1
          BG(serialize_lock)++;
280
1
          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
1
          BG(serialize_lock)--;
285
286
1
          zval_ptr_dtor(&retval);
287
1
        } else {
288
0
          GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
289
0
        }
290
4
      } else if (Z_EXTRA_P(zv) == VAR_UNSERIALIZE_FLAG) {
291
        /* Perform delayed __unserialize calls */
292
1
        if (!delayed_call_failed) {
293
1
          zval param;
294
1
          ZVAL_COPY(&param, &var_dtor_hash->data[i + 1]);
295
296
1
          BG(serialize_lock)++;
297
1
          zend_call_known_instance_method_with_1_params(
298
1
            Z_OBJCE_P(zv)->__unserialize, Z_OBJ_P(zv), NULL, &param);
299
1
          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
1
          BG(serialize_lock)--;
304
1
          zval_ptr_dtor(&param);
305
1
        } else {
306
0
          GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
307
0
        }
308
1
      }
309
310
5
      i_zval_ptr_dtor(zv);
311
5
    }
312
2
    next = var_dtor_hash->next;
313
2
    efree_size(var_dtor_hash, sizeof(var_dtor_entries));
314
2
    var_dtor_hash = next;
315
2
  }
316
317
48
  if ((*var_hashx)->ref_props) {
318
1
    zend_hash_destroy((*var_hashx)->ref_props);
319
1
    FREE_HASHTABLE((*var_hashx)->ref_props);
320
1
  }
321
48
}
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
20
{
366
20
  HashTable *classes = (*var_hashx)->allowed_classes;
367
368
20
  if(classes == NULL) {
369
20
    return 1;
370
20
  }
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
5
#define YYFILL(n) do { } while (0)
379
103
#define YYCTYPE unsigned char
380
1.85k
#define YYCURSOR cursor
381
459
#define YYLIMIT limit
382
114
#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
48
{
392
48
  zend_ulong result = 0;
393
48
  zend_ulong neg = 0;
394
48
  const unsigned char *start;
395
396
48
  if (*p == '-') {
397
0
    neg = 1;
398
0
    p++;
399
48
  } else if (UNEXPECTED(*p == '+')) {
400
0
    p++;
401
0
  }
402
403
65
  while (UNEXPECTED(*p == '0')) {
404
17
    p++;
405
17
  }
406
407
48
  start = p;
408
409
123
  while (*p >= '0' && *p <= '9') {
410
75
    result = result * 10 + ((zend_ulong)(*p) - '0');
411
75
    p++;
412
75
  }
413
414
48
  if (q) {
415
20
    *q = p;
416
20
  }
417
418
  /* number too long or overflow */
419
48
  if (UNEXPECTED(p - start > MAX_LENGTH_OF_LONG - 1)
420
48
   || (SIZEOF_ZEND_LONG == 4
421
0
    && UNEXPECTED(p - start == MAX_LENGTH_OF_LONG - 1)
422
0
    && UNEXPECTED(*start > '2'))
423
48
   || 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
48
  return (zend_long) ((!neg) ? result : -result);
429
48
}
430
431
static inline zend_long parse_iv(const unsigned char *p)
432
28
{
433
28
  return parse_iv2(p, NULL);
434
28
}
435
436
/* no need to check for length - re2c already did */
437
static inline size_t parse_uiv(const unsigned char *p)
438
58
{
439
58
  unsigned char cursor;
440
58
  size_t result = 0;
441
442
219
  while (1) {
443
219
    cursor = *p;
444
219
    if (cursor >= '0' && cursor <= '9') {
445
161
      result = result * 10 + (size_t)(cursor - (unsigned char)'0');
446
161
    } else {
447
58
      break;
448
58
    }
449
161
    p++;
450
161
  }
451
58
  return result;
452
58
}
453
454
#define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash
455
97
#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
13
{
461
13
  if (var_hash) {
462
13
    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
13
    (*var_hash)->cur_depth++;
471
13
  }
472
473
19
  while (elements-- > 0) {
474
15
    zval key, *data;
475
15
    zend_ulong idx;
476
477
15
    ZVAL_UNDEF(&key);
478
479
15
    if (!php_var_unserialize_internal(&key, p, max, NULL)) {
480
1
      zval_ptr_dtor(&key);
481
1
      goto failure;
482
1
    }
483
484
14
    if (Z_TYPE(key) == IS_LONG) {
485
8
      idx = Z_LVAL(key);
486
8
numeric_key:
487
8
      data = zend_hash_index_lookup(ht, idx);
488
8
      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
8
    } else if (Z_TYPE(key) == IS_STRING) {
493
6
      if (UNEXPECTED(ZEND_HANDLE_NUMERIC(Z_STR(key), idx))) {
494
0
        zval_ptr_dtor_str(&key);
495
0
        goto numeric_key;
496
0
      }
497
6
      data = zend_hash_lookup(ht, Z_STR(key));
498
6
      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
6
      zval_ptr_dtor_str(&key);
503
6
    } else {
504
0
      zval_ptr_dtor(&key);
505
0
      goto failure;
506
0
    }
507
508
14
    if (!php_var_unserialize_internal(data, p, max, var_hash)) {
509
8
      goto failure;
510
8
    }
511
512
6
    if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
513
0
      (*p)--;
514
0
      goto failure;
515
0
    }
516
6
  }
517
518
4
  if (var_hash) {
519
4
    (*var_hash)->cur_depth--;
520
4
  }
521
4
  return 1;
522
523
9
failure:
524
9
  if (var_hash) {
525
9
    (*var_hash)->cur_depth--;
526
9
  }
527
9
  return 0;
528
13
}
529
530
static int is_property_visibility_changed(zend_class_entry *ce, zval *key)
531
5
{
532
5
  if (zend_hash_num_elements(&ce->properties_info) > 0) {
533
1
    zend_property_info *existing_propinfo = NULL;
534
1
    const char *unmangled_class = NULL;
535
1
    const char *unmangled_prop;
536
1
    size_t unmangled_prop_len;
537
538
1
    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
1
    if (unmangled_class == NULL) {
544
0
      existing_propinfo = zend_hash_find_ptr(&ce->properties_info, Z_STR_P(key));
545
1
    } else {
546
1
      if (!strcmp(unmangled_class, "*")
547
1
       || !strcasecmp(unmangled_class, ZSTR_VAL(ce->name))) {
548
1
        existing_propinfo = zend_hash_str_find_ptr(
549
1
          &ce->properties_info, unmangled_prop, unmangled_prop_len);
550
1
      }
551
1
    }
552
553
1
    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
1
  }
567
5
  return 0;
568
5
}
569
570
571
static zend_always_inline int process_nested_object_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, zend_object *obj)
572
9
{
573
9
  if (var_hash) {
574
9
    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
9
    (*var_hash)->cur_depth++;
583
9
  }
584
585
17
  while (elements-- > 0) {
586
14
    zval key, *data;
587
14
    zend_property_info *info = NULL;
588
589
14
    ZVAL_UNDEF(&key);
590
591
14
    if (!php_var_unserialize_internal(&key, p, max, NULL)) {
592
1
      zval_ptr_dtor(&key);
593
1
      goto failure;
594
1
    }
595
596
13
    if (EXPECTED(Z_TYPE(key) == IS_STRING)) {
597
13
string_key:
598
13
      data = zend_hash_find(ht, Z_STR(key));
599
13
      if (data != NULL) {
600
8
        if (Z_TYPE_P(data) == IS_INDIRECT) {
601
8
declared_property:
602
          /* This is a property with a declaration */
603
8
          data = Z_INDIRECT_P(data);
604
8
          info = zend_get_typed_property_info_for_slot(obj, data);
605
8
          if (info) {
606
5
            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
5
            if ((*var_hash)->ref_props) {
612
              /* Remove old entry from ref_props table, if it exists. */
613
4
              zend_hash_index_del(
614
4
                (*var_hash)->ref_props, (uintptr_t) data);
615
4
            }
616
5
          }
617
          /* We may override default property value, but they are usually immutable */
618
8
          if (Z_REFCOUNTED_P(data)) {
619
2
            var_push_dtor_value(var_hash, data);
620
2
          }
621
8
          ZVAL_NULL(data);
622
8
        } 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
8
      } else {
636
5
        int ret = is_property_visibility_changed(obj->ce, &key);
637
638
5
        if (EXPECTED(!ret)) {
639
5
          if (UNEXPECTED(obj->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) {
640
1
            zend_throw_error(NULL, "Cannot create dynamic property %s::$%s",
641
1
              ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key)));
642
1
            zval_ptr_dtor_str(&key);
643
1
            goto failure;
644
4
          } else if (!(obj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) {
645
1
            zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated",
646
1
              ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key)));
647
1
            if (EG(exception)) {
648
0
              zval_ptr_dtor_str(&key);
649
0
              goto failure;
650
0
            }
651
1
          }
652
653
4
          data = zend_hash_add_new(ht, Z_STR(key), &EG(uninitialized_zval));
654
4
        } 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
5
      }
667
12
      zval_ptr_dtor_str(&key);
668
12
    } else if (Z_TYPE(key) == IS_LONG) {
669
      /* object properties should include no integers */
670
2
      convert_to_string(&key);
671
2
      goto string_key;
672
2
    } else {
673
0
      zval_ptr_dtor(&key);
674
0
      goto failure;
675
0
    }
676
677
12
    if (!php_var_unserialize_internal(data, p, max, var_hash)) {
678
4
      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
4
      goto failure;
684
4
    }
685
686
8
    if (UNEXPECTED(info)) {
687
5
      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
5
      if (Z_ISREF_P(data)) {
694
0
        ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), info);
695
5
      } 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
5
        if (!(*var_hash)->ref_props) {
699
1
          (*var_hash)->ref_props = emalloc(sizeof(HashTable));
700
1
          zend_hash_init((*var_hash)->ref_props, 8, NULL, NULL, 0);
701
1
        }
702
5
        zend_hash_index_update_ptr(
703
5
          (*var_hash)->ref_props, (uintptr_t) data, info);
704
5
      }
705
5
    }
706
707
8
    if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
708
0
      (*p)--;
709
0
      goto failure;
710
0
    }
711
8
  }
712
713
3
  if (var_hash) {
714
3
    (*var_hash)->cur_depth--;
715
3
  }
716
3
  return 1;
717
718
6
failure:
719
6
  if (var_hash) {
720
6
    (*var_hash)->cur_depth--;
721
6
  }
722
6
  return 0;
723
9
}
724
725
static inline int finish_nested_data(UNSERIALIZE_PARAMETER)
726
12
{
727
12
  if (*p >= max || **p != '}') {
728
2
    return 0;
729
2
  }
730
731
10
  (*p)++;
732
10
  return 1;
733
12
}
734
735
static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
736
2
{
737
2
  zend_long datalen;
738
739
2
  datalen = parse_iv2((*p) + 2, p);
740
741
2
  if (max - (*p) < 2) {
742
0
    return 0;
743
0
  }
744
745
2
  if ((*p)[0] != ':') {
746
1
    return 0;
747
1
  }
748
749
1
  if ((*p)[1] != '{') {
750
0
    (*p) += 1;
751
0
    return 0;
752
0
  }
753
754
1
  (*p) += 2;
755
756
1
  if (datalen < 0 || (max - (*p)) <= datalen) {
757
1
    zend_error(E_WARNING, "Insufficient data for unserializing - " ZEND_LONG_FMT " required, " ZEND_LONG_FMT " present", datalen, (zend_long)(max - (*p)));
758
1
    return 0;
759
1
  }
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
13
{
785
13
  HashTable *ht;
786
13
  bool has_wakeup;
787
788
13
  if (has_unserialize) {
789
4
    zval ary, *tmp;
790
791
4
    if (elements >= HT_MAX_SIZE) {
792
0
      return 0;
793
0
    }
794
795
4
    array_init_size(&ary, elements);
796
    /* Avoid reallocation due to packed -> mixed conversion. */
797
4
    zend_hash_real_init_mixed(Z_ARRVAL(ary));
798
4
    if (!process_nested_array_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL(ary), elements)) {
799
3
      ZVAL_DEREF(rval);
800
3
      GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED);
801
3
      zval_ptr_dtor(&ary);
802
3
      return 0;
803
3
    }
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
1
    ZVAL_DEREF(rval);
808
1
    tmp = tmp_var(var_hash, 2);
809
1
    ZVAL_COPY(tmp, rval);
810
1
    Z_EXTRA_P(tmp) = VAR_UNSERIALIZE_FLAG;
811
1
    tmp++;
812
1
    ZVAL_COPY_VALUE(tmp, &ary);
813
814
1
    return finish_nested_data(UNSERIALIZE_PASSTHRU);
815
4
  }
816
817
9
  has_wakeup = Z_OBJCE_P(rval) != PHP_IC_ENTRY
818
7
    && zend_hash_exists(&Z_OBJCE_P(rval)->function_table, ZSTR_KNOWN(ZEND_STR_WAKEUP));
819
820
9
  ht = Z_OBJPROP_P(rval);
821
9
  if (elements >= (zend_long)(HT_MAX_SIZE - zend_hash_num_elements(ht))) {
822
0
    return 0;
823
0
  }
824
825
9
  zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, HT_IS_PACKED(ht));
826
9
  if (!process_nested_object_data(UNSERIALIZE_PASSTHRU, ht, elements, Z_OBJ_P(rval))) {
827
6
    if (has_wakeup) {
828
2
      ZVAL_DEREF(rval);
829
2
      GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED);
830
2
    }
831
6
    return 0;
832
6
  }
833
834
3
  ZVAL_DEREF(rval);
835
3
  if (has_wakeup) {
836
    /* Delay __wakeup call until end of serialization */
837
1
    zval *wakeup_var = var_tmp_var(var_hash);
838
1
    ZVAL_COPY(wakeup_var, rval);
839
1
    Z_EXTRA_P(wakeup_var) = VAR_WAKEUP_FLAG;
840
1
  }
841
842
3
  return finish_nested_data(UNSERIALIZE_PASSTHRU);
843
9
}
844
#ifdef PHP_WIN32
845
# pragma optimize("", on)
846
#endif
847
848
PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
849
48
{
850
48
  var_entries *orig_var_entries = (*var_hash)->last;
851
48
  zend_long orig_used_slots = orig_var_entries ? orig_var_entries->used_slots : 0;
852
48
  int result;
853
854
48
  result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU);
855
856
48
  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
42
    var_entries *e = orig_var_entries;
861
42
    zend_long s = orig_used_slots;
862
84
    while (e) {
863
96
      for (; s < e->used_slots; s++) {
864
54
        e->data[s] = NULL;
865
54
      }
866
867
42
      e = e->next;
868
42
      s = 0;
869
42
    }
870
42
  }
871
872
48
  return result;
873
48
}
874
875
static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
876
103
{
877
103
  const unsigned char *cursor, *limit, *marker, *start;
878
103
  zval *rval_ref;
879
880
103
  limit = max;
881
103
  cursor = *p;
882
883
103
  if (YYCURSOR >= YYLIMIT) {
884
0
    return 0;
885
0
  }
886
887
103
  if (var_hash && (*p)[0] != 'R') {
888
73
    var_push(var_hash, rval);
889
73
  }
890
891
103
  start = cursor;
892
893
894
103
#line 895 "ext/standard/var_unserializer.c"
895
103
{
896
103
  YYCTYPE yych;
897
103
  static const unsigned char yybm[] = {
898
103
      0,   0,   0,   0,   0,   0,   0,   0, 
899
103
      0,   0,   0,   0,   0,   0,   0,   0, 
900
103
      0,   0,   0,   0,   0,   0,   0,   0, 
901
103
      0,   0,   0,   0,   0,   0,   0,   0, 
902
103
      0,   0,   0,   0,   0,   0,   0,   0, 
903
103
      0,   0,   0,   0,   0,   0,   0,   0, 
904
103
    128, 128, 128, 128, 128, 128, 128, 128, 
905
103
    128, 128,   0,   0,   0,   0,   0,   0, 
906
103
      0,   0,   0,   0,   0,   0,   0,   0, 
907
103
      0,   0,   0,   0,   0,   0,   0,   0, 
908
103
      0,   0,   0,   0,   0,   0,   0,   0, 
909
103
      0,   0,   0,   0,   0,   0,   0,   0, 
910
103
      0,   0,   0,   0,   0,   0,   0,   0, 
911
103
      0,   0,   0,   0,   0,   0,   0,   0, 
912
103
      0,   0,   0,   0,   0,   0,   0,   0, 
913
103
      0,   0,   0,   0,   0,   0,   0,   0, 
914
103
      0,   0,   0,   0,   0,   0,   0,   0, 
915
103
      0,   0,   0,   0,   0,   0,   0,   0, 
916
103
      0,   0,   0,   0,   0,   0,   0,   0, 
917
103
      0,   0,   0,   0,   0,   0,   0,   0, 
918
103
      0,   0,   0,   0,   0,   0,   0,   0, 
919
103
      0,   0,   0,   0,   0,   0,   0,   0, 
920
103
      0,   0,   0,   0,   0,   0,   0,   0, 
921
103
      0,   0,   0,   0,   0,   0,   0,   0, 
922
103
      0,   0,   0,   0,   0,   0,   0,   0, 
923
103
      0,   0,   0,   0,   0,   0,   0,   0, 
924
103
      0,   0,   0,   0,   0,   0,   0,   0, 
925
103
      0,   0,   0,   0,   0,   0,   0,   0, 
926
103
      0,   0,   0,   0,   0,   0,   0,   0, 
927
103
      0,   0,   0,   0,   0,   0,   0,   0, 
928
103
      0,   0,   0,   0,   0,   0,   0,   0, 
929
103
      0,   0,   0,   0,   0,   0,   0,   0, 
930
103
  };
931
103
  if ((YYLIMIT - YYCURSOR) < 7) YYFILL(7);
932
103
  yych = *YYCURSOR;
933
103
  switch (yych) {
934
2
  case 'C':
935
36
  case 'O': goto yy4;
936
13
  case 'E': goto yy5;
937
1
  case 'N': goto yy6;
938
1
  case 'R': goto yy7;
939
0
  case 'S': goto yy8;
940
16
  case 'a': goto yy9;
941
0
  case 'b': goto yy10;
942
0
  case 'd': goto yy11;
943
13
  case 'i': goto yy12;
944
0
  case 'r': goto yy13;
945
22
  case 's': goto yy14;
946
0
  case '}': goto yy15;
947
1
  default:  goto yy2;
948
103
  }
949
1
yy2:
950
1
  ++YYCURSOR;
951
15
yy3:
952
15
#line 1437 "ext/standard/var_unserializer.re"
953
15
  { return 0; }
954
0
#line 955 "ext/standard/var_unserializer.c"
955
36
yy4:
956
36
  yych = *(YYMARKER = ++YYCURSOR);
957
36
  if (yych == ':') goto yy17;
958
0
  goto yy3;
959
13
yy5:
960
13
  yych = *(YYMARKER = ++YYCURSOR);
961
13
  if (yych == ':') goto yy19;
962
1
  goto yy3;
963
1
yy6:
964
1
  yych = *++YYCURSOR;
965
1
  if (yych == ';') goto yy20;
966
0
  goto yy3;
967
1
yy7:
968
1
  yych = *(YYMARKER = ++YYCURSOR);
969
1
  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
16
yy9:
976
16
  yych = *(YYMARKER = ++YYCURSOR);
977
16
  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
13
yy12:
988
13
  yych = *(YYMARKER = ++YYCURSOR);
989
13
  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
22
yy14:
996
22
  yych = *(YYMARKER = ++YYCURSOR);
997
22
  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
22
}
1007
0
#line 1008 "ext/standard/var_unserializer.c"
1008
36
yy17:
1009
36
  yych = *++YYCURSOR;
1010
36
  if (yybm[0+yych] & 128) {
1011
35
    goto yy30;
1012
35
  }
1013
13
yy18:
1014
13
  YYCURSOR = YYMARKER;
1015
13
  goto yy3;
1016
12
yy19:
1017
12
  yych = *++YYCURSOR;
1018
12
  if (yych <= '/') goto yy18;
1019
11
  if (yych <= '9') goto yy32;
1020
1
  goto yy18;
1021
1
yy20:
1022
1
  ++YYCURSOR;
1023
1
#line 955 "ext/standard/var_unserializer.re"
1024
1
  {
1025
1
  *p = YYCURSOR;
1026
1
  ZVAL_NULL(rval);
1027
1
  return 1;
1028
11
}
1029
0
#line 1030 "ext/standard/var_unserializer.c"
1030
1
yy22:
1031
1
  yych = *++YYCURSOR;
1032
1
  if (yych <= '/') goto yy18;
1033
1
  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
16
yy24:
1041
16
  yych = *++YYCURSOR;
1042
16
  if (yych <= '/') goto yy18;
1043
16
  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
13
yy27:
1073
13
  yych = *++YYCURSOR;
1074
13
  if (yych <= ',') {
1075
0
    if (yych == '+') goto yy49;
1076
0
    goto yy18;
1077
13
  } else {
1078
13
    if (yych <= '-') goto yy49;
1079
13
    if (yych <= '/') goto yy18;
1080
13
    if (yych <= '9') goto yy50;
1081
0
    goto yy18;
1082
13
  }
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
22
yy29:
1089
22
  yych = *++YYCURSOR;
1090
22
  if (yych <= '/') goto yy18;
1091
22
  if (yych <= '9') goto yy54;
1092
1
  goto yy18;
1093
156
yy30:
1094
156
  ++YYCURSOR;
1095
156
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1096
156
  yych = *YYCURSOR;
1097
156
  if (yybm[0+yych] & 128) {
1098
121
    goto yy30;
1099
121
  }
1100
35
  if (yych <= '/') goto yy18;
1101
34
  if (yych <= ':') goto yy56;
1102
3
  goto yy18;
1103
13
yy32:
1104
13
  ++YYCURSOR;
1105
13
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1106
13
  yych = *YYCURSOR;
1107
13
  if (yych <= '/') goto yy18;
1108
13
  if (yych <= '9') goto yy32;
1109
10
  if (yych <= ':') goto yy57;
1110
2
  goto yy18;
1111
2
yy34:
1112
1
  ++YYCURSOR;
1113
1
  if (YYLIMIT <= YYCURSOR) YYFILL(1);
1114
1
  yych = *YYCURSOR;
1115
1
  if (yych <= '/') goto yy18;
1116
1
  if (yych <= '9') goto yy34;
1117
1
  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
20
yy38:
1128
20
  ++YYCURSOR;
1129
20
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1130
20
  yych = *YYCURSOR;
1131
20
  if (yych <= '/') goto yy18;
1132
20
  if (yych <= '9') goto yy38;
1133
16
  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
34
yy50:
1199
34
  ++YYCURSOR;
1200
34
  if (YYLIMIT <= YYCURSOR) YYFILL(1);
1201
34
  yych = *YYCURSOR;
1202
34
  if (yych <= '/') goto yy18;
1203
34
  if (yych <= '9') goto yy50;
1204
13
  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
29
yy54:
1215
29
  ++YYCURSOR;
1216
29
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1217
29
  yych = *YYCURSOR;
1218
29
  if (yych <= '/') goto yy18;
1219
29
  if (yych <= '9') goto yy54;
1220
21
  if (yych <= ':') goto yy77;
1221
0
  goto yy18;
1222
31
yy56:
1223
31
  yych = *++YYCURSOR;
1224
31
  if (yych == '"') goto yy78;
1225
2
  goto yy18;
1226
8
yy57:
1227
8
  yych = *++YYCURSOR;
1228
8
  if (yych == '"') goto yy80;
1229
0
  goto yy18;
1230
1
yy58:
1231
1
  ++YYCURSOR;
1232
1
#line 899 "ext/standard/var_unserializer.re"
1233
1
  {
1234
1
  zend_long id;
1235
1236
1
  *p = YYCURSOR;
1237
1
  if (!var_hash) return 0;
1238
1239
1
  id = parse_uiv(start + 2) - 1;
1240
1
  if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) {
1241
0
    return 0;
1242
0
  }
1243
1244
1
  if (rval_ref == rval || (Z_ISREF_P(rval_ref) && Z_REFVAL_P(rval_ref) == rval)) {
1245
0
    return 0;
1246
0
  }
1247
1248
1
  if (!Z_ISREF_P(rval_ref)) {
1249
1
    zend_property_info *info = NULL;
1250
1
    if ((*var_hash)->ref_props) {
1251
0
      info = zend_hash_index_find_ptr((*var_hash)->ref_props, (uintptr_t) rval_ref);
1252
0
    }
1253
1
    ZVAL_NEW_REF(rval_ref, rval_ref);
1254
1
    if (info) {
1255
0
      ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(rval_ref), info);
1256
0
    }
1257
1
  }
1258
1259
1
  ZVAL_COPY(rval, rval_ref);
1260
1261
1
  return 1;
1262
1
}
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
16
yy61:
1269
16
  yych = *++YYCURSOR;
1270
16
  if (yych == '{') goto yy84;
1271
1
  goto yy18;
1272
1
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
16
}
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
16
}
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
13
yy73:
1339
13
  ++YYCURSOR;
1340
13
#line 973 "ext/standard/var_unserializer.re"
1341
13
  {
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
13
  *p = YYCURSOR;
1363
13
  ZVAL_LONG(rval, parse_iv(start + 2));
1364
13
  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
21
yy77:
1396
21
  yych = *++YYCURSOR;
1397
21
  if (yych == '"') goto yy90;
1398
0
  goto yy18;
1399
29
yy78:
1400
29
  ++YYCURSOR;
1401
29
#line 1131 "ext/standard/var_unserializer.re"
1402
29
  {
1403
29
  size_t len, maxlen;
1404
29
  zend_long elements;
1405
29
  char *str;
1406
29
  zend_string *class_name;
1407
29
  zend_class_entry *ce;
1408
29
  bool incomplete_class = 0;
1409
29
  bool custom_object = 0;
1410
29
  bool has_unserialize = 0;
1411
1412
29
  zval user_func;
1413
29
  zval retval;
1414
29
  zval args[1];
1415
1416
29
    if (!var_hash) return 0;
1417
28
  if (*start == 'C') {
1418
2
    custom_object = 1;
1419
2
  }
1420
1421
28
  len = parse_uiv(start + 2);
1422
28
  maxlen = max - YYCURSOR;
1423
28
  if (maxlen < len || len == 0) {
1424
5
    *p = start + 2;
1425
5
    return 0;
1426
5
  }
1427
1428
23
  str = (char*)YYCURSOR;
1429
1430
23
  YYCURSOR += len;
1431
1432
23
  if (*(YYCURSOR) != '"') {
1433
1
    *p = YYCURSOR;
1434
1
    return 0;
1435
1
  }
1436
22
  if (*(YYCURSOR+1) != ':') {
1437
0
    *p = YYCURSOR+1;
1438
0
    return 0;
1439
0
  }
1440
1441
22
  if (len == 0) {
1442
    /* empty class names are not allowed */
1443
0
    return 0;
1444
0
  }
1445
1446
22
  if (str[0] == '\000') {
1447
    /* runtime definition keys are not allowed */
1448
1
    return 0;
1449
1
  }
1450
1451
21
  if (str[0] == '\\') {
1452
    /* class name can't start from namespace separator */
1453
0
    return 0;
1454
0
  }
1455
1456
21
  class_name = zend_string_init_interned(str, len, 0);
1457
1458
21
  do {
1459
21
    zend_string *lc_name;
1460
1461
21
    if (!(*var_hash)->allowed_classes && ZSTR_HAS_CE_CACHE(class_name)) {
1462
12
      ce = ZSTR_GET_CE_CACHE(class_name);
1463
12
      if (ce) {
1464
1
        break;
1465
1
      }
1466
12
    }
1467
1468
20
    lc_name = zend_string_tolower(class_name);
1469
20
    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
20
    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
20
    ce = zend_hash_find_ptr(EG(class_table), lc_name);
1489
20
    if (ce
1490
13
     && (ce->ce_flags & ZEND_ACC_LINKED)
1491
13
     && !(ce->ce_flags & ZEND_ACC_ANON_CLASS)) {
1492
13
      zend_string_release_ex(lc_name, 0);
1493
13
      break;
1494
13
    }
1495
1496
7
    if (!ZSTR_HAS_CE_CACHE(class_name) && !zend_is_valid_class_name(class_name)) {
1497
1
      zend_string_release_ex(lc_name, 0);
1498
1
      zend_string_release_ex(class_name, 0);
1499
1
      return 0;
1500
1
    }
1501
1502
    /* Try to find class directly */
1503
6
    BG(serialize_lock)++;
1504
6
    ce = zend_lookup_class_ex(class_name, lc_name, 0);
1505
6
    BG(serialize_lock)--;
1506
6
    zend_string_release_ex(lc_name, 0);
1507
6
    if (EG(exception)) {
1508
0
      zend_string_release_ex(class_name, 0);
1509
0
      return 0;
1510
0
    }
1511
1512
6
    if (ce) {
1513
0
      break;
1514
0
    }
1515
1516
    /* Check for unserialize callback */
1517
6
    if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
1518
6
      incomplete_class = 1;
1519
6
      ce = PHP_IC_ENTRY;
1520
6
      break;
1521
6
    }
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
20
  *p = YYCURSOR;
1551
1552
20
  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
20
  if (custom_object) {
1560
2
    int ret;
1561
1562
2
    ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
1563
1564
2
    if (ret && incomplete_class) {
1565
0
      php_store_class_name(rval, class_name);
1566
0
    }
1567
2
    zend_string_release_ex(class_name, 0);
1568
2
    return ret;
1569
2
  }
1570
1571
18
  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
18
  elements = parse_iv2(*p + 2, p);
1578
18
  if (elements < 0 || IS_FAKE_ELEM_COUNT(elements, max - YYCURSOR)) {
1579
3
    zend_string_release_ex(class_name, 0);
1580
3
    return 0;
1581
3
  }
1582
1583
15
  YYCURSOR = *p;
1584
1585
15
  if (*(YYCURSOR) != ':') {
1586
1
    zend_string_release_ex(class_name, 0);
1587
1
    return 0;
1588
1
  }
1589
14
  if (*(YYCURSOR+1) != '{') {
1590
1
    *p = YYCURSOR+1;
1591
1
    zend_string_release_ex(class_name, 0);
1592
1
    return 0;
1593
1
  }
1594
1595
13
  *p += 2;
1596
1597
13
  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
13
  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
13
  if (object_init_ex(rval, ce) == FAILURE) {
1610
0
    zend_string_release_ex(class_name, 0);
1611
0
    return 0;
1612
0
  }
1613
1614
13
  if (incomplete_class) {
1615
2
    php_store_class_name(rval, class_name);
1616
2
  }
1617
13
  zend_string_release_ex(class_name, 0);
1618
1619
13
  return object_common(UNSERIALIZE_PASSTHRU, elements, has_unserialize);
1620
13
}
1621
0
#line 1622 "ext/standard/var_unserializer.c"
1622
8
yy80:
1623
8
  ++YYCURSOR;
1624
8
#line 1351 "ext/standard/var_unserializer.re"
1625
8
  {
1626
8
  if (!var_hash) return 0;
1627
1628
8
  size_t len = parse_uiv(start + 2);
1629
8
  size_t maxlen = max - YYCURSOR;
1630
8
  if (maxlen < len || len == 0) {
1631
0
    *p = start + 2;
1632
0
    return 0;
1633
0
  }
1634
1635
8
  char *str = (char *) YYCURSOR;
1636
8
  YYCURSOR += len;
1637
1638
8
  if (*(YYCURSOR) != '"') {
1639
0
    *p = YYCURSOR;
1640
0
    return 0;
1641
0
  }
1642
8
  if (*(YYCURSOR+1) != ';') {
1643
1
    *p = YYCURSOR+1;
1644
1
    return 0;
1645
1
  }
1646
1647
7
  char *colon_ptr = memchr(str, ':', len);
1648
7
  if (colon_ptr == NULL) {
1649
1
    php_error_docref(NULL, E_WARNING, "Invalid enum name '%.*s' (missing colon)", (int) len, str);
1650
1
    return 0;
1651
1
  }
1652
6
  size_t colon_pos = colon_ptr - str;
1653
1654
6
  zend_string *enum_name = zend_string_init(str, colon_pos, 0);
1655
6
  zend_string *case_name = zend_string_init(&str[colon_pos + 1], len - colon_pos - 1, 0);
1656
1657
6
  if (!zend_is_valid_class_name(enum_name)) {
1658
0
    goto fail;
1659
0
  }
1660
1661
6
  zend_class_entry *ce = zend_lookup_class(enum_name);
1662
6
  if (!ce) {
1663
1
    php_error_docref(NULL, E_WARNING, "Class '%s' not found", ZSTR_VAL(enum_name));
1664
1
    goto fail;
1665
1
  }
1666
5
  if (!(ce->ce_flags & ZEND_ACC_ENUM)) {
1667
1
    php_error_docref(NULL, E_WARNING, "Class '%s' is not an enum", ZSTR_VAL(enum_name));
1668
1
    goto fail;
1669
1
  }
1670
1671
4
  YYCURSOR += 2;
1672
4
  *p = YYCURSOR;
1673
1674
4
  zend_class_constant *c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), case_name);
1675
4
  if (!c) {
1676
1
    php_error_docref(NULL, E_WARNING, "Undefined constant %s::%s", ZSTR_VAL(enum_name), ZSTR_VAL(case_name));
1677
1
    goto fail;
1678
1
  }
1679
1680
3
  if (!(ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE)) {
1681
1
    php_error_docref(NULL, E_WARNING, "%s::%s is not an enum case", ZSTR_VAL(enum_name), ZSTR_VAL(case_name));
1682
1
    goto fail;
1683
1
  }
1684
1685
2
  zend_string_release_ex(enum_name, 0);
1686
2
  zend_string_release_ex(case_name, 0);
1687
1688
2
  zval *value = &c->value;
1689
2
  if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
1690
1
    if (zval_update_constant_ex(value, c->ce) == FAILURE) {
1691
0
      return 0;
1692
0
    }
1693
1
  }
1694
2
  ZEND_ASSERT(Z_TYPE_P(value) == IS_OBJECT);
1695
2
  ZVAL_COPY(rval, value);
1696
1697
2
  return 1;
1698
1699
4
fail:
1700
4
  zend_string_release_ex(enum_name, 0);
1701
4
  zend_string_release_ex(case_name, 0);
1702
4
  return 0;
1703
2
}
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
15
yy84:
1746
15
  ++YYCURSOR;
1747
15
#line 1098 "ext/standard/var_unserializer.re"
1748
15
  {
1749
15
  zend_long elements = parse_iv(start + 2);
1750
  /* use iv() not uiv() in order to check data range */
1751
15
  *p = YYCURSOR;
1752
15
    if (!var_hash) return 0;
1753
1754
15
  if (elements < 0 || elements >= HT_MAX_SIZE || IS_FAKE_ELEM_COUNT(elements, max - YYCURSOR)) {
1755
1
    return 0;
1756
1
  }
1757
1758
14
  if (elements) {
1759
9
    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
9
    zend_hash_real_init_mixed(Z_ARRVAL_P(rval));
1763
9
  } else {
1764
5
    ZVAL_EMPTY_ARRAY(rval);
1765
5
    return finish_nested_data(UNSERIALIZE_PASSTHRU);
1766
5
  }
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
14
  HT_ALLOW_COW_VIOLATION(Z_ARRVAL_P(rval));
1773
1774
9
  if (!process_nested_array_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements)) {
1775
6
    return 0;
1776
6
  }
1777
1778
3
  return finish_nested_data(UNSERIALIZE_PASSTHRU);
1779
9
}
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
21
yy90:
1798
21
  ++YYCURSOR;
1799
21
#line 1024 "ext/standard/var_unserializer.re"
1800
21
  {
1801
21
  size_t len, maxlen;
1802
21
  char *str;
1803
1804
21
  len = parse_uiv(start + 2);
1805
21
  maxlen = max - YYCURSOR;
1806
21
  if (maxlen < len) {
1807
1
    *p = start + 2;
1808
1
    return 0;
1809
1
  }
1810
1811
20
  str = (char*)YYCURSOR;
1812
1813
20
  YYCURSOR += len;
1814
1815
20
  if (*(YYCURSOR) != '"') {
1816
0
    *p = YYCURSOR;
1817
0
    return 0;
1818
0
  }
1819
1820
20
  if (*(YYCURSOR + 1) != ';') {
1821
0
    *p = YYCURSOR + 1;
1822
0
    return 0;
1823
0
  }
1824
1825
20
  YYCURSOR += 2;
1826
20
  *p = YYCURSOR;
1827
1828
20
  if (!var_hash) {
1829
    /* Array or object key unserialization */
1830
17
    ZVAL_STR(rval, zend_string_init_existing_interned(str, len, 0));
1831
17
  } else {
1832
3
    ZVAL_STRINGL_FAST(rval, str, len);
1833
3
  }
1834
20
  return 1;
1835
20
}
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
20
}
1855
20
#line 1856 "ext/standard/var_unserializer.c"
1856
20
}
1857
0
#line 1439 "ext/standard/var_unserializer.re"
1858
1859
1860
0
  return 0;
1861
20
}