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
75
#define VAR_ENTRIES_MAX 1018     /* 1024 - offsetof(php_unserialize_data, entries) / sizeof(void*) */
25
2
#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
6
#define VAR_WAKEUP_FLAG 1
31
5
#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
35
  ((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
48
PHPAPI php_unserialize_data_t php_var_unserialize_init(void) {
61
48
  php_unserialize_data_t d;
62
  /* fprintf(stderr, "UNSERIALIZE_INIT    == lock: %u, level: %u\n", BG(serialize_lock), BG(unserialize).level); */
63
48
  if (BG(serialize_lock) || !BG(unserialize).level) {
64
48
    d = emalloc(sizeof(struct php_unserialize_data));
65
48
    d->last = &d->entries;
66
48
    d->first_dtor = d->last_dtor = NULL;
67
48
    d->allowed_classes = NULL;
68
48
    d->ref_props = NULL;
69
48
    d->cur_depth = 0;
70
48
    d->max_depth = BG(unserialize_max_depth);
71
48
    d->entries.used_slots = 0;
72
48
    d->entries.next = NULL;
73
48
    if (!BG(serialize_lock)) {
74
48
      BG(unserialize).data = d;
75
48
      BG(unserialize).level = 1;
76
48
    }
77
48
  } else {
78
0
    d = BG(unserialize).data;
79
0
    ++BG(unserialize).level;
80
0
  }
81
48
  return d;
82
48
}
83
84
48
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
48
  if (BG(serialize_lock) || BG(unserialize).level == 1) {
87
48
    var_destroy(&d);
88
48
    efree(d);
89
48
  }
90
48
  if (!BG(serialize_lock) && !--BG(unserialize).level) {
91
48
    BG(unserialize).data = NULL;
92
48
  }
93
48
}
94
95
48
PHPAPI HashTable *php_var_unserialize_get_allowed_classes(php_unserialize_data_t d) {
96
48
  return d->allowed_classes;
97
48
}
98
48
PHPAPI void php_var_unserialize_set_allowed_classes(php_unserialize_data_t d, HashTable *classes) {
99
48
  d->allowed_classes = classes;
100
48
}
101
102
48
PHPAPI void php_var_unserialize_set_max_depth(php_unserialize_data_t d, zend_long max_depth) {
103
48
  d->max_depth = max_depth;
104
48
}
105
48
PHPAPI zend_long php_var_unserialize_get_max_depth(php_unserialize_data_t d) {
106
48
  return d->max_depth;
107
48
}
108
109
48
PHPAPI void php_var_unserialize_set_cur_depth(php_unserialize_data_t d, zend_long cur_depth) {
110
48
  d->cur_depth = cur_depth;
111
48
}
112
48
PHPAPI zend_long php_var_unserialize_get_cur_depth(php_unserialize_data_t d) {
113
48
  return d->cur_depth;
114
48
}
115
116
static inline void var_push(php_unserialize_data_t *var_hashx, zval *rval)
117
73
{
118
73
  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
73
  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
73
  var_hash->data[var_hash->used_slots++] = rval;
133
73
}
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
2
{
148
2
  if (Z_REFCOUNTED_P(rval)) {
149
2
    zval *tmp_var = var_tmp_var(var_hashx);
150
2
    if (!tmp_var) {
151
0
      return;
152
0
    }
153
2
    ZVAL_COPY_VALUE(tmp_var, rval);
154
2
  }
155
2
}
156
157
static zend_always_inline zval *tmp_var(php_unserialize_data_t *var_hashx, zend_long num)
158
4
{
159
4
    var_dtor_entries *var_hash;
160
4
  zend_long used_slots;
161
162
4
    if (!var_hashx || !*var_hashx || num < 1) {
163
0
        return NULL;
164
0
    }
165
166
4
    var_hash = (*var_hashx)->last_dtor;
167
4
    if (!var_hash || var_hash->used_slots + num > VAR_DTOR_ENTRIES_MAX) {
168
2
        var_hash = emalloc(sizeof(var_dtor_entries));
169
2
        var_hash->used_slots = 0;
170
2
        var_hash->next = 0;
171
172
2
        if (!(*var_hashx)->first_dtor) {
173
2
            (*var_hashx)->first_dtor = var_hash;
174
2
        } else {
175
0
            (*var_hashx)->last_dtor->next = var_hash;
176
0
        }
177
178
2
        (*var_hashx)->last_dtor = var_hash;
179
2
    }
180
9
  for (used_slots = var_hash->used_slots; var_hash->used_slots < used_slots + num; var_hash->used_slots++) {
181
5
    ZVAL_UNDEF(&var_hash->data[var_hash->used_slots]);
182
5
    Z_EXTRA(var_hash->data[var_hash->used_slots]) = 0;
183
5
  }
184
4
    return &var_hash->data[used_slots];
185
4
}
186
187
PHPAPI zval *var_tmp_var(php_unserialize_data_t *var_hashx)
188
3
{
189
3
    return tmp_var(var_hashx, 1);
190
3
}
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
1
{
213
1
  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
1
  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
1
  if (!var_hash) return NULL;
224
225
1
  if (id < 0 || id >= var_hash->used_slots) return NULL;
226
227
1
  return var_hash->data[id];
228
1
}
229
230
PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
231
48
{
232
48
  void *next;
233
48
  zend_long i;
234
48
  var_entries *var_hash = (*var_hashx)->entries.next;
235
48
  var_dtor_entries *var_dtor_hash = (*var_hashx)->first_dtor;
236
48
  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
48
  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
50
  while (var_dtor_hash) {
249
7
    for (i = 0; i < var_dtor_hash->used_slots; i++) {
250
5
      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
5
      if (Z_EXTRA_P(zv) == VAR_WAKEUP_FLAG) {
256
        /* Perform delayed __wakeup calls */
257
1
        if (!delayed_call_failed) {
258
1
          zval retval;
259
1
          zend_fcall_info fci;
260
1
          zend_fcall_info_cache fci_cache;
261
262
1
          ZEND_ASSERT(Z_TYPE_P(zv) == IS_OBJECT);
263
264
1
          fci.size = sizeof(fci);
265
1
          fci.object = Z_OBJ_P(zv);
266
1
          fci.retval = &retval;
267
1
          fci.param_count = 0;
268
1
          fci.params = NULL;
269
1
          fci.named_params = NULL;
270
1
          ZVAL_UNDEF(&fci.function_name);
271
272
1
          fci_cache.function_handler = zend_hash_find_ptr(
273
1
            &fci.object->ce->function_table, ZSTR_KNOWN(ZEND_STR_WAKEUP));
274
1
          fci_cache.object = fci.object;
275
1
          fci_cache.called_scope = fci.object->ce;
276
277
1
          BG(serialize_lock)++;
278
1
          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
1
          BG(serialize_lock)--;
283
284
1
          zval_ptr_dtor(&retval);
285
1
        } else {
286
0
          GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
287
0
        }
288
4
      } else if (Z_EXTRA_P(zv) == VAR_UNSERIALIZE_FLAG) {
289
        /* Perform delayed __unserialize calls */
290
1
        if (!delayed_call_failed) {
291
1
          zval param;
292
1
          ZVAL_COPY(&param, &var_dtor_hash->data[i + 1]);
293
294
1
          BG(serialize_lock)++;
295
1
          zend_call_known_instance_method_with_1_params(
296
1
            Z_OBJCE_P(zv)->__unserialize, Z_OBJ_P(zv), NULL, &param);
297
1
          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
1
          BG(serialize_lock)--;
302
1
          zval_ptr_dtor(&param);
303
1
        } else {
304
0
          GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
305
0
        }
306
1
      }
307
308
5
      i_zval_ptr_dtor(zv);
309
5
    }
310
2
    next = var_dtor_hash->next;
311
2
    efree_size(var_dtor_hash, sizeof(var_dtor_entries));
312
2
    var_dtor_hash = next;
313
2
  }
314
315
48
  if ((*var_hashx)->ref_props) {
316
1
    zend_hash_destroy((*var_hashx)->ref_props);
317
1
    FREE_HASHTABLE((*var_hashx)->ref_props);
318
1
  }
319
48
}
320
321
/* }}} */
322
323
static zend_string *unserialize_str(const unsigned char **p, size_t len, size_t maxlen)
324
2
{
325
2
  size_t i, j;
326
2
  zend_string *str = zend_string_safe_alloc(1, len, 0, 0);
327
2
  unsigned char *end = *(unsigned char **)p+maxlen;
328
329
26
  for (i = 0; i < len; i++) {
330
24
    if (*p >= end) {
331
0
      zend_string_efree(str);
332
0
      return NULL;
333
0
    }
334
24
    if (**p != '\\') {
335
24
      ZSTR_VAL(str)[i] = (char)**p;
336
24
    } 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
24
    (*p)++;
355
24
  }
356
2
  ZSTR_VAL(str)[i] = 0;
357
2
  ZSTR_LEN(str) = i;
358
2
  return str;
359
2
}
360
361
static inline int unserialize_allowed_class(
362
    zend_string *lcname, php_unserialize_data_t *var_hashx)
363
15
{
364
15
  HashTable *classes = (*var_hashx)->allowed_classes;
365
366
15
  if(classes == NULL) {
367
15
    return 1;
368
15
  }
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
5
#define YYFILL(n) do { } while (0)
377
106
#define YYCTYPE unsigned char
378
1.58k
#define YYCURSOR cursor
379
376
#define YYLIMIT limit
380
114
#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
46
{
390
46
  zend_ulong result = 0;
391
46
  zend_ulong neg = 0;
392
46
  const unsigned char *start;
393
394
46
  if (*p == '-') {
395
0
    neg = 1;
396
0
    p++;
397
46
  } else if (UNEXPECTED(*p == '+')) {
398
0
    p++;
399
0
  }
400
401
62
  while (UNEXPECTED(*p == '0')) {
402
16
    p++;
403
16
  }
404
405
46
  start = p;
406
407
102
  while (*p >= '0' && *p <= '9') {
408
56
    result = result * 10 + ((zend_ulong)(*p) - '0');
409
56
    p++;
410
56
  }
411
412
46
  if (q) {
413
16
    *q = p;
414
16
  }
415
416
  /* number too long or overflow */
417
46
  if (UNEXPECTED(p - start > MAX_LENGTH_OF_LONG - 1)
418
46
   || (SIZEOF_ZEND_LONG == 4
419
0
    && UNEXPECTED(p - start == MAX_LENGTH_OF_LONG - 1)
420
0
    && UNEXPECTED(*start > '2'))
421
46
   || 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
46
  return (zend_long) ((!neg) ? result : -result);
427
46
}
428
429
static inline zend_long parse_iv(const unsigned char *p)
430
30
{
431
30
  return parse_iv2(p, NULL);
432
30
}
433
434
/* no need to check for length - re2c already did */
435
static inline size_t parse_uiv(const unsigned char *p)
436
55
{
437
55
  unsigned char cursor;
438
55
  size_t result = 0;
439
440
160
  while (1) {
441
160
    cursor = *p;
442
160
    if (cursor >= '0' && cursor <= '9') {
443
105
      result = result * 10 + (size_t)(cursor - (unsigned char)'0');
444
105
    } else {
445
55
      break;
446
55
    }
447
105
    p++;
448
105
  }
449
55
  return result;
450
55
}
451
452
#define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash
453
98
#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
11
{
459
11
  if (var_hash) {
460
11
    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
11
    (*var_hash)->cur_depth++;
469
11
  }
470
471
22
  while (elements-- > 0) {
472
17
    zval key, *data;
473
17
    zend_ulong idx;
474
475
17
    ZVAL_UNDEF(&key);
476
477
17
    if (!php_var_unserialize_internal(&key, p, max, NULL)) {
478
1
      zval_ptr_dtor(&key);
479
1
      goto failure;
480
1
    }
481
482
16
    if (Z_TYPE(key) == IS_LONG) {
483
6
      idx = Z_LVAL(key);
484
6
numeric_key:
485
6
      data = zend_hash_index_lookup(ht, idx);
486
6
      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
10
    } else if (Z_TYPE(key) == IS_STRING) {
491
10
      if (UNEXPECTED(ZEND_HANDLE_NUMERIC(Z_STR(key), idx))) {
492
0
        zval_ptr_dtor_str(&key);
493
0
        goto numeric_key;
494
0
      }
495
10
      data = zend_hash_lookup(ht, Z_STR(key));
496
10
      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
10
      zval_ptr_dtor_str(&key);
501
10
    } else {
502
0
      zval_ptr_dtor(&key);
503
0
      goto failure;
504
0
    }
505
506
16
    if (!php_var_unserialize_internal(data, p, max, var_hash)) {
507
5
      goto failure;
508
5
    }
509
510
11
    if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
511
0
      (*p)--;
512
0
      goto failure;
513
0
    }
514
11
  }
515
516
5
  if (var_hash) {
517
5
    (*var_hash)->cur_depth--;
518
5
  }
519
5
  return 1;
520
521
6
failure:
522
6
  if (var_hash) {
523
6
    (*var_hash)->cur_depth--;
524
6
  }
525
6
  return 0;
526
11
}
527
528
static int is_property_visibility_changed(zend_class_entry *ce, zval *key)
529
3
{
530
3
  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
3
  return 0;
566
3
}
567
568
569
static zend_always_inline int process_nested_object_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, zend_object *obj)
570
9
{
571
9
  if (var_hash) {
572
9
    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
9
    (*var_hash)->cur_depth++;
581
9
  }
582
583
17
  while (elements-- > 0) {
584
15
    zval key, *data;
585
15
    zend_property_info *info = NULL;
586
587
15
    ZVAL_UNDEF(&key);
588
589
15
    if (!php_var_unserialize_internal(&key, p, max, NULL)) {
590
3
      zval_ptr_dtor(&key);
591
3
      goto failure;
592
3
    }
593
594
12
    if (EXPECTED(Z_TYPE(key) == IS_STRING)) {
595
11
string_key:
596
11
      data = zend_hash_find(ht, Z_STR(key));
597
11
      if (data != NULL) {
598
8
        if (Z_TYPE_P(data) == IS_INDIRECT) {
599
8
declared_property:
600
          /* This is a property with a declaration */
601
8
          data = Z_INDIRECT_P(data);
602
8
          info = zend_get_typed_property_info_for_slot(obj, data);
603
8
          if (info) {
604
5
            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
5
            if ((*var_hash)->ref_props) {
610
              /* Remove old entry from ref_props table, if it exists. */
611
4
              zend_hash_index_del(
612
4
                (*var_hash)->ref_props, (uintptr_t) data);
613
4
            }
614
5
          }
615
          /* We may override default property value, but they are usually immutable */
616
8
          if (Z_REFCOUNTED_P(data)) {
617
2
            var_push_dtor_value(var_hash, data);
618
2
          }
619
8
          ZVAL_NULL(data);
620
8
        } 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
8
      } else {
634
3
        int ret = is_property_visibility_changed(obj->ce, &key);
635
636
3
        if (EXPECTED(!ret)) {
637
3
          if (UNEXPECTED(obj->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) {
638
1
            zend_throw_error(NULL, "Cannot create dynamic property %s::$%s",
639
1
              ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key)));
640
1
            zval_ptr_dtor_str(&key);
641
1
            goto failure;
642
2
          } 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
2
          data = zend_hash_add_new(ht, Z_STR(key), &EG(uninitialized_zval));
652
2
        } 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
3
      }
665
10
      zval_ptr_dtor_str(&key);
666
10
    } else if (Z_TYPE(key) == IS_LONG) {
667
      /* object properties should include no integers */
668
1
      convert_to_string(&key);
669
1
      goto string_key;
670
1
    } else {
671
1
      zval_ptr_dtor(&key);
672
1
      goto failure;
673
1
    }
674
675
10
    if (!php_var_unserialize_internal(data, p, max, var_hash)) {
676
2
      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
2
      goto failure;
682
2
    }
683
684
8
    if (UNEXPECTED(info)) {
685
5
      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
5
      if (Z_ISREF_P(data)) {
692
0
        ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), info);
693
5
      } 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
5
        if (!(*var_hash)->ref_props) {
697
1
          (*var_hash)->ref_props = emalloc(sizeof(HashTable));
698
1
          zend_hash_init((*var_hash)->ref_props, 8, NULL, NULL, 0);
699
1
        }
700
5
        zend_hash_index_update_ptr(
701
5
          (*var_hash)->ref_props, (uintptr_t) data, info);
702
5
      }
703
5
    }
704
705
8
    if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
706
0
      (*p)--;
707
0
      goto failure;
708
0
    }
709
8
  }
710
711
2
  if (var_hash) {
712
2
    (*var_hash)->cur_depth--;
713
2
  }
714
2
  return 1;
715
716
7
failure:
717
7
  if (var_hash) {
718
7
    (*var_hash)->cur_depth--;
719
7
  }
720
7
  return 0;
721
9
}
722
723
static inline int finish_nested_data(UNSERIALIZE_PARAMETER)
724
17
{
725
17
  if (*p >= max || **p != '}') {
726
1
    return 0;
727
1
  }
728
729
16
  (*p)++;
730
16
  return 1;
731
17
}
732
733
static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
734
1
{
735
1
  zend_long datalen;
736
737
1
  datalen = parse_iv2((*p) + 2, p);
738
739
1
  if (max - (*p) < 2) {
740
0
    return 0;
741
0
  }
742
743
1
  if ((*p)[0] != ':') {
744
1
    return 0;
745
1
  }
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
12
{
783
12
  HashTable *ht;
784
12
  bool has_wakeup;
785
786
12
  if (has_unserialize) {
787
3
    zval ary, *tmp;
788
789
3
    if (elements >= HT_MAX_SIZE) {
790
0
      return 0;
791
0
    }
792
793
3
    array_init_size(&ary, elements);
794
    /* Avoid reallocation due to packed -> mixed conversion. */
795
3
    zend_hash_real_init_mixed(Z_ARRVAL(ary));
796
3
    if (!process_nested_array_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL(ary), elements)) {
797
2
      ZVAL_DEREF(rval);
798
2
      GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED);
799
2
      zval_ptr_dtor(&ary);
800
2
      return 0;
801
2
    }
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
1
    ZVAL_DEREF(rval);
806
1
    tmp = tmp_var(var_hash, 2);
807
1
    ZVAL_COPY(tmp, rval);
808
1
    Z_EXTRA_P(tmp) = VAR_UNSERIALIZE_FLAG;
809
1
    tmp++;
810
1
    ZVAL_COPY_VALUE(tmp, &ary);
811
812
1
    return finish_nested_data(UNSERIALIZE_PASSTHRU);
813
3
  }
814
815
9
  has_wakeup = Z_OBJCE_P(rval) != PHP_IC_ENTRY
816
5
    && zend_hash_exists(&Z_OBJCE_P(rval)->function_table, ZSTR_KNOWN(ZEND_STR_WAKEUP));
817
818
9
  ht = Z_OBJPROP_P(rval);
819
9
  if (elements >= (zend_long)(HT_MAX_SIZE - zend_hash_num_elements(ht))) {
820
0
    return 0;
821
0
  }
822
823
9
  zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, HT_IS_PACKED(ht));
824
9
  if (!process_nested_object_data(UNSERIALIZE_PASSTHRU, ht, elements, Z_OBJ_P(rval))) {
825
7
    if (has_wakeup) {
826
1
      ZVAL_DEREF(rval);
827
1
      GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED);
828
1
    }
829
7
    return 0;
830
7
  }
831
832
2
  ZVAL_DEREF(rval);
833
2
  if (has_wakeup) {
834
    /* Delay __wakeup call until end of serialization */
835
1
    zval *wakeup_var = var_tmp_var(var_hash);
836
1
    ZVAL_COPY(wakeup_var, rval);
837
1
    Z_EXTRA_P(wakeup_var) = VAR_WAKEUP_FLAG;
838
1
  }
839
840
2
  return finish_nested_data(UNSERIALIZE_PASSTHRU);
841
9
}
842
#ifdef PHP_WIN32
843
# pragma optimize("", on)
844
#endif
845
846
PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
847
48
{
848
48
  var_entries *orig_var_entries = (*var_hash)->last;
849
48
  zend_long orig_used_slots = orig_var_entries ? orig_var_entries->used_slots : 0;
850
48
  int result;
851
852
48
  result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU);
853
854
48
  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
42
    var_entries *e = orig_var_entries;
859
42
    zend_long s = orig_used_slots;
860
84
    while (e) {
861
91
      for (; s < e->used_slots; s++) {
862
49
        e->data[s] = NULL;
863
49
      }
864
865
42
      e = e->next;
866
42
      s = 0;
867
42
    }
868
42
  }
869
870
48
  return result;
871
48
}
872
873
static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
874
106
{
875
106
  const unsigned char *cursor, *limit, *marker, *start;
876
106
  zval *rval_ref;
877
878
106
  limit = max;
879
106
  cursor = *p;
880
881
106
  if (YYCURSOR >= YYLIMIT) {
882
0
    return 0;
883
0
  }
884
885
106
  if (var_hash && (*p)[0] != 'R') {
886
73
    var_push(var_hash, rval);
887
73
  }
888
889
106
  start = cursor;
890
891
892
106
#line 893 "ext/standard/var_unserializer.c"
893
106
{
894
106
  YYCTYPE yych;
895
106
  static const unsigned char yybm[] = {
896
106
      0,   0,   0,   0,   0,   0,   0,   0, 
897
106
      0,   0,   0,   0,   0,   0,   0,   0, 
898
106
      0,   0,   0,   0,   0,   0,   0,   0, 
899
106
      0,   0,   0,   0,   0,   0,   0,   0, 
900
106
      0,   0,   0,   0,   0,   0,   0,   0, 
901
106
      0,   0,   0,   0,   0,   0,   0,   0, 
902
106
    128, 128, 128, 128, 128, 128, 128, 128, 
903
106
    128, 128,   0,   0,   0,   0,   0,   0, 
904
106
      0,   0,   0,   0,   0,   0,   0,   0, 
905
106
      0,   0,   0,   0,   0,   0,   0,   0, 
906
106
      0,   0,   0,   0,   0,   0,   0,   0, 
907
106
      0,   0,   0,   0,   0,   0,   0,   0, 
908
106
      0,   0,   0,   0,   0,   0,   0,   0, 
909
106
      0,   0,   0,   0,   0,   0,   0,   0, 
910
106
      0,   0,   0,   0,   0,   0,   0,   0, 
911
106
      0,   0,   0,   0,   0,   0,   0,   0, 
912
106
      0,   0,   0,   0,   0,   0,   0,   0, 
913
106
      0,   0,   0,   0,   0,   0,   0,   0, 
914
106
      0,   0,   0,   0,   0,   0,   0,   0, 
915
106
      0,   0,   0,   0,   0,   0,   0,   0, 
916
106
      0,   0,   0,   0,   0,   0,   0,   0, 
917
106
      0,   0,   0,   0,   0,   0,   0,   0, 
918
106
      0,   0,   0,   0,   0,   0,   0,   0, 
919
106
      0,   0,   0,   0,   0,   0,   0,   0, 
920
106
      0,   0,   0,   0,   0,   0,   0,   0, 
921
106
      0,   0,   0,   0,   0,   0,   0,   0, 
922
106
      0,   0,   0,   0,   0,   0,   0,   0, 
923
106
      0,   0,   0,   0,   0,   0,   0,   0, 
924
106
      0,   0,   0,   0,   0,   0,   0,   0, 
925
106
      0,   0,   0,   0,   0,   0,   0,   0, 
926
106
      0,   0,   0,   0,   0,   0,   0,   0, 
927
106
      0,   0,   0,   0,   0,   0,   0,   0, 
928
106
  };
929
106
  if ((YYLIMIT - YYCURSOR) < 7) YYFILL(7);
930
106
  yych = *YYCURSOR;
931
106
  switch (yych) {
932
1
  case 'C':
933
26
  case 'O': goto yy4;
934
14
  case 'E': goto yy5;
935
3
  case 'N': goto yy6;
936
2
  case 'R': goto yy7;
937
3
  case 'S': goto yy8;
938
22
  case 'a': goto yy9;
939
0
  case 'b': goto yy10;
940
1
  case 'd': goto yy11;
941
10
  case 'i': goto yy12;
942
0
  case 'r': goto yy13;
943
24
  case 's': goto yy14;
944
0
  case '}': goto yy15;
945
1
  default:  goto yy2;
946
106
  }
947
1
yy2:
948
1
  ++YYCURSOR;
949
18
yy3:
950
18
#line 1435 "ext/standard/var_unserializer.re"
951
18
  { return 0; }
952
0
#line 953 "ext/standard/var_unserializer.c"
953
26
yy4:
954
26
  yych = *(YYMARKER = ++YYCURSOR);
955
26
  if (yych == ':') goto yy17;
956
1
  goto yy3;
957
14
yy5:
958
14
  yych = *(YYMARKER = ++YYCURSOR);
959
14
  if (yych == ':') goto yy19;
960
1
  goto yy3;
961
3
yy6:
962
3
  yych = *++YYCURSOR;
963
3
  if (yych == ';') goto yy20;
964
1
  goto yy3;
965
2
yy7:
966
2
  yych = *(YYMARKER = ++YYCURSOR);
967
2
  if (yych == ':') goto yy22;
968
1
  goto yy3;
969
3
yy8:
970
3
  yych = *(YYMARKER = ++YYCURSOR);
971
3
  if (yych == ':') goto yy23;
972
0
  goto yy3;
973
22
yy9:
974
22
  yych = *(YYMARKER = ++YYCURSOR);
975
22
  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
1
yy11:
982
1
  yych = *(YYMARKER = ++YYCURSOR);
983
1
  if (yych == ':') goto yy26;
984
1
  goto yy3;
985
10
yy12:
986
10
  yych = *(YYMARKER = ++YYCURSOR);
987
10
  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
24
yy14:
994
24
  yych = *(YYMARKER = ++YYCURSOR);
995
24
  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
24
}
1005
0
#line 1006 "ext/standard/var_unserializer.c"
1006
25
yy17:
1007
25
  yych = *++YYCURSOR;
1008
25
  if (yybm[0+yych] & 128) {
1009
25
    goto yy30;
1010
25
  }
1011
12
yy18:
1012
12
  YYCURSOR = YYMARKER;
1013
12
  goto yy3;
1014
13
yy19:
1015
13
  yych = *++YYCURSOR;
1016
13
  if (yych <= '/') goto yy18;
1017
13
  if (yych <= '9') goto yy32;
1018
1
  goto yy18;
1019
2
yy20:
1020
2
  ++YYCURSOR;
1021
2
#line 953 "ext/standard/var_unserializer.re"
1022
2
  {
1023
2
  *p = YYCURSOR;
1024
2
  ZVAL_NULL(rval);
1025
2
  return 1;
1026
13
}
1027
0
#line 1028 "ext/standard/var_unserializer.c"
1028
1
yy22:
1029
1
  yych = *++YYCURSOR;
1030
1
  if (yych <= '/') goto yy18;
1031
1
  if (yych <= '9') goto yy34;
1032
0
  goto yy18;
1033
3
yy23:
1034
3
  yych = *++YYCURSOR;
1035
3
  if (yych <= '/') goto yy18;
1036
3
  if (yych <= '9') goto yy36;
1037
1
  goto yy18;
1038
22
yy24:
1039
22
  yych = *++YYCURSOR;
1040
22
  if (yych <= '/') goto yy18;
1041
22
  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
10
yy27:
1071
10
  yych = *++YYCURSOR;
1072
10
  if (yych <= ',') {
1073
0
    if (yych == '+') goto yy49;
1074
0
    goto yy18;
1075
10
  } else {
1076
10
    if (yych <= '-') goto yy49;
1077
10
    if (yych <= '/') goto yy18;
1078
10
    if (yych <= '9') goto yy50;
1079
0
    goto yy18;
1080
10
  }
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
24
yy29:
1087
24
  yych = *++YYCURSOR;
1088
24
  if (yych <= '/') goto yy18;
1089
24
  if (yych <= '9') goto yy54;
1090
0
  goto yy18;
1091
50
yy30:
1092
50
  ++YYCURSOR;
1093
50
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1094
50
  yych = *YYCURSOR;
1095
50
  if (yybm[0+yych] & 128) {
1096
25
    goto yy30;
1097
25
  }
1098
25
  if (yych <= '/') goto yy18;
1099
24
  if (yych <= ':') goto yy56;
1100
3
  goto yy18;
1101
33
yy32:
1102
33
  ++YYCURSOR;
1103
33
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1104
33
  yych = *YYCURSOR;
1105
33
  if (yych <= '/') goto yy18;
1106
32
  if (yych <= '9') goto yy32;
1107
11
  if (yych <= ':') goto yy57;
1108
1
  goto yy18;
1109
1
yy34:
1110
1
  ++YYCURSOR;
1111
1
  if (YYLIMIT <= YYCURSOR) YYFILL(1);
1112
1
  yych = *YYCURSOR;
1113
1
  if (yych <= '/') goto yy18;
1114
1
  if (yych <= '9') goto yy34;
1115
1
  if (yych == ';') goto yy58;
1116
0
  goto yy18;
1117
4
yy36:
1118
4
  ++YYCURSOR;
1119
4
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1120
4
  yych = *YYCURSOR;
1121
4
  if (yych <= '/') goto yy18;
1122
4
  if (yych <= '9') goto yy36;
1123
2
  if (yych <= ':') goto yy60;
1124
0
  goto yy18;
1125
33
yy38:
1126
33
  ++YYCURSOR;
1127
33
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1128
33
  yych = *YYCURSOR;
1129
33
  if (yych <= '/') goto yy18;
1130
33
  if (yych <= '9') goto yy38;
1131
22
  if (yych <= ':') goto yy61;
1132
1
  goto yy18;
1133
1
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
12
yy50:
1197
12
  ++YYCURSOR;
1198
12
  if (YYLIMIT <= YYCURSOR) YYFILL(1);
1199
12
  yych = *YYCURSOR;
1200
12
  if (yych <= '/') goto yy18;
1201
12
  if (yych <= '9') goto yy50;
1202
10
  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
31
yy54:
1213
31
  ++YYCURSOR;
1214
31
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1215
31
  yych = *YYCURSOR;
1216
31
  if (yych <= '/') goto yy18;
1217
31
  if (yych <= '9') goto yy54;
1218
24
  if (yych <= ':') goto yy77;
1219
0
  goto yy18;
1220
21
yy56:
1221
21
  yych = *++YYCURSOR;
1222
21
  if (yych == '"') goto yy78;
1223
1
  goto yy18;
1224
10
yy57:
1225
10
  yych = *++YYCURSOR;
1226
10
  if (yych == '"') goto yy80;
1227
1
  goto yy18;
1228
1
yy58:
1229
1
  ++YYCURSOR;
1230
1
#line 897 "ext/standard/var_unserializer.re"
1231
1
  {
1232
1
  zend_long id;
1233
1234
1
  *p = YYCURSOR;
1235
1
  if (!var_hash) return 0;
1236
1237
1
  id = parse_uiv(start + 2) - 1;
1238
1
  if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) {
1239
0
    return 0;
1240
0
  }
1241
1242
1
  if (rval_ref == rval || (Z_ISREF_P(rval_ref) && Z_REFVAL_P(rval_ref) == rval)) {
1243
0
    return 0;
1244
0
  }
1245
1246
1
  if (!Z_ISREF_P(rval_ref)) {
1247
1
    zend_property_info *info = NULL;
1248
1
    if ((*var_hash)->ref_props) {
1249
0
      info = zend_hash_index_find_ptr((*var_hash)->ref_props, (uintptr_t) rval_ref);
1250
0
    }
1251
1
    ZVAL_NEW_REF(rval_ref, rval_ref);
1252
1
    if (info) {
1253
0
      ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(rval_ref), info);
1254
0
    }
1255
1
  }
1256
1257
1
  ZVAL_COPY(rval, rval_ref);
1258
1259
1
  return 1;
1260
1
}
1261
0
#line 1262 "ext/standard/var_unserializer.c"
1262
2
yy60:
1263
2
  yych = *++YYCURSOR;
1264
2
  if (yych == '"') goto yy82;
1265
0
  goto yy18;
1266
21
yy61:
1267
21
  yych = *++YYCURSOR;
1268
21
  if (yych == '{') goto yy84;
1269
1
  goto yy18;
1270
1
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
21
}
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
21
}
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
10
yy73:
1337
10
  ++YYCURSOR;
1338
10
#line 971 "ext/standard/var_unserializer.re"
1339
10
  {
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
10
  *p = YYCURSOR;
1361
10
  ZVAL_LONG(rval, parse_iv(start + 2));
1362
10
  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
24
yy77:
1394
24
  yych = *++YYCURSOR;
1395
24
  if (yych == '"') goto yy90;
1396
0
  goto yy18;
1397
20
yy78:
1398
20
  ++YYCURSOR;
1399
20
#line 1129 "ext/standard/var_unserializer.re"
1400
20
  {
1401
20
  size_t len, maxlen;
1402
20
  zend_long elements;
1403
20
  char *str;
1404
20
  zend_string *class_name;
1405
20
  zend_class_entry *ce;
1406
20
  bool incomplete_class = 0;
1407
20
  bool custom_object = 0;
1408
20
  bool has_unserialize = 0;
1409
1410
20
  zval user_func;
1411
20
  zval retval;
1412
20
  zval args[1];
1413
1414
20
    if (!var_hash) return 0;
1415
19
  if (*start == 'C') {
1416
1
    custom_object = 1;
1417
1
  }
1418
1419
19
  len = parse_uiv(start + 2);
1420
19
  maxlen = max - YYCURSOR;
1421
19
  if (maxlen < len || len == 0) {
1422
2
    *p = start + 2;
1423
2
    return 0;
1424
2
  }
1425
1426
17
  str = (char*)YYCURSOR;
1427
1428
17
  YYCURSOR += len;
1429
1430
17
  if (*(YYCURSOR) != '"') {
1431
0
    *p = YYCURSOR;
1432
0
    return 0;
1433
0
  }
1434
17
  if (*(YYCURSOR+1) != ':') {
1435
0
    *p = YYCURSOR+1;
1436
0
    return 0;
1437
0
  }
1438
1439
17
  if (len == 0) {
1440
    /* empty class names are not allowed */
1441
0
    return 0;
1442
0
  }
1443
1444
17
  if (str[0] == '\000') {
1445
    /* runtime definition keys are not allowed */
1446
1
    return 0;
1447
1
  }
1448
1449
16
  if (str[0] == '\\') {
1450
    /* class name can't start from namespace separator */
1451
0
    return 0;
1452
0
  }
1453
1454
16
  class_name = zend_string_init_interned(str, len, 0);
1455
1456
16
  do {
1457
16
    zend_string *lc_name;
1458
1459
16
    if (!(*var_hash)->allowed_classes && ZSTR_HAS_CE_CACHE(class_name)) {
1460
8
      ce = ZSTR_GET_CE_CACHE(class_name);
1461
8
      if (ce) {
1462
1
        break;
1463
1
      }
1464
8
    }
1465
1466
15
    lc_name = zend_string_tolower(class_name);
1467
15
    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
15
    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
15
    ce = zend_hash_find_ptr(EG(class_table), lc_name);
1487
15
    if (ce
1488
9
     && (ce->ce_flags & ZEND_ACC_LINKED)
1489
9
     && !(ce->ce_flags & ZEND_ACC_ANON_CLASS)) {
1490
9
      zend_string_release_ex(lc_name, 0);
1491
9
      break;
1492
9
    }
1493
1494
6
    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
6
    BG(serialize_lock)++;
1502
6
    ce = zend_lookup_class_ex(class_name, lc_name, 0);
1503
6
    BG(serialize_lock)--;
1504
6
    zend_string_release_ex(lc_name, 0);
1505
6
    if (EG(exception)) {
1506
0
      zend_string_release_ex(class_name, 0);
1507
0
      return 0;
1508
0
    }
1509
1510
6
    if (ce) {
1511
0
      break;
1512
0
    }
1513
1514
    /* Check for unserialize callback */
1515
6
    if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
1516
6
      incomplete_class = 1;
1517
6
      ce = PHP_IC_ENTRY;
1518
6
      break;
1519
6
    }
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
16
  *p = YYCURSOR;
1549
1550
16
  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
16
  if (custom_object) {
1558
1
    int ret;
1559
1560
1
    ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
1561
1562
1
    if (ret && incomplete_class) {
1563
0
      php_store_class_name(rval, class_name);
1564
0
    }
1565
1
    zend_string_release_ex(class_name, 0);
1566
1
    return ret;
1567
1
  }
1568
1569
15
  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
15
  elements = parse_iv2(*p + 2, p);
1576
15
  if (elements < 0 || IS_FAKE_ELEM_COUNT(elements, max - YYCURSOR)) {
1577
2
    zend_string_release_ex(class_name, 0);
1578
2
    return 0;
1579
2
  }
1580
1581
13
  YYCURSOR = *p;
1582
1583
13
  if (*(YYCURSOR) != ':') {
1584
1
    zend_string_release_ex(class_name, 0);
1585
1
    return 0;
1586
1
  }
1587
12
  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
12
  *p += 2;
1594
1595
12
  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
12
  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
12
  if (object_init_ex(rval, ce) == FAILURE) {
1608
0
    zend_string_release_ex(class_name, 0);
1609
0
    return 0;
1610
0
  }
1611
1612
12
  if (incomplete_class) {
1613
4
    php_store_class_name(rval, class_name);
1614
4
  }
1615
12
  zend_string_release_ex(class_name, 0);
1616
1617
12
  return object_common(UNSERIALIZE_PASSTHRU, elements, has_unserialize);
1618
12
}
1619
0
#line 1620 "ext/standard/var_unserializer.c"
1620
9
yy80:
1621
9
  ++YYCURSOR;
1622
9
#line 1349 "ext/standard/var_unserializer.re"
1623
9
  {
1624
9
  if (!var_hash) return 0;
1625
1626
9
  size_t len = parse_uiv(start + 2);
1627
9
  size_t maxlen = max - YYCURSOR;
1628
9
  if (maxlen < len || len == 0) {
1629
2
    *p = start + 2;
1630
2
    return 0;
1631
2
  }
1632
1633
7
  char *str = (char *) YYCURSOR;
1634
7
  YYCURSOR += len;
1635
1636
7
  if (*(YYCURSOR) != '"') {
1637
0
    *p = YYCURSOR;
1638
0
    return 0;
1639
0
  }
1640
7
  if (*(YYCURSOR+1) != ';') {
1641
1
    *p = YYCURSOR+1;
1642
1
    return 0;
1643
1
  }
1644
1645
6
  char *colon_ptr = memchr(str, ':', len);
1646
6
  if (colon_ptr == NULL) {
1647
1
    php_error_docref(NULL, E_WARNING, "Invalid enum name '%.*s' (missing colon)", (int) len, str);
1648
1
    return 0;
1649
1
  }
1650
5
  size_t colon_pos = colon_ptr - str;
1651
1652
5
  zend_string *enum_name = zend_string_init(str, colon_pos, 0);
1653
5
  zend_string *case_name = zend_string_init(&str[colon_pos + 1], len - colon_pos - 1, 0);
1654
1655
5
  if (!zend_is_valid_class_name(enum_name)) {
1656
0
    goto fail;
1657
0
  }
1658
1659
5
  zend_class_entry *ce = zend_lookup_class(enum_name);
1660
5
  if (!ce) {
1661
1
    php_error_docref(NULL, E_WARNING, "Class '%s' not found", ZSTR_VAL(enum_name));
1662
1
    goto fail;
1663
1
  }
1664
4
  if (!(ce->ce_flags & ZEND_ACC_ENUM)) {
1665
1
    php_error_docref(NULL, E_WARNING, "Class '%s' is not an enum", ZSTR_VAL(enum_name));
1666
1
    goto fail;
1667
1
  }
1668
1669
3
  YYCURSOR += 2;
1670
3
  *p = YYCURSOR;
1671
1672
3
  zend_class_constant *c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), case_name);
1673
3
  if (!c) {
1674
1
    php_error_docref(NULL, E_WARNING, "Undefined constant %s::%s", ZSTR_VAL(enum_name), ZSTR_VAL(case_name));
1675
1
    goto fail;
1676
1
  }
1677
1678
2
  if (!(ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE)) {
1679
1
    php_error_docref(NULL, E_WARNING, "%s::%s is not an enum case", ZSTR_VAL(enum_name), ZSTR_VAL(case_name));
1680
1
    goto fail;
1681
1
  }
1682
1683
1
  zend_string_release_ex(enum_name, 0);
1684
1
  zend_string_release_ex(case_name, 0);
1685
1686
1
  zval *value = &c->value;
1687
1
  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
1
  ZEND_ASSERT(Z_TYPE_P(value) == IS_OBJECT);
1693
1
  ZVAL_COPY(rval, value);
1694
1695
1
  return 1;
1696
1697
4
fail:
1698
4
  zend_string_release_ex(enum_name, 0);
1699
4
  zend_string_release_ex(case_name, 0);
1700
4
  return 0;
1701
1
}
1702
0
#line 1703 "ext/standard/var_unserializer.c"
1703
2
yy82:
1704
2
  ++YYCURSOR;
1705
2
#line 1059 "ext/standard/var_unserializer.re"
1706
2
  {
1707
2
  size_t len, maxlen;
1708
2
  zend_string *str;
1709
1710
2
  len = parse_uiv(start + 2);
1711
2
  maxlen = max - YYCURSOR;
1712
2
  if (maxlen < len) {
1713
0
    *p = start + 2;
1714
0
    return 0;
1715
0
  }
1716
1717
2
  if ((str = unserialize_str(&YYCURSOR, len, maxlen)) == NULL) {
1718
0
    return 0;
1719
0
  }
1720
1721
2
  if (*(YYCURSOR) != '"') {
1722
1
    zend_string_efree(str);
1723
1
    *p = YYCURSOR;
1724
1
    return 0;
1725
1
  }
1726
1727
1
  if (*(YYCURSOR + 1) != ';') {
1728
1
    efree(str);
1729
1
    *p = YYCURSOR + 1;
1730
1
    return 0;
1731
1
  }
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
1
}
1742
0
#line 1743 "ext/standard/var_unserializer.c"
1743
20
yy84:
1744
20
  ++YYCURSOR;
1745
20
#line 1096 "ext/standard/var_unserializer.re"
1746
20
  {
1747
20
  zend_long elements = parse_iv(start + 2);
1748
  /* use iv() not uiv() in order to check data range */
1749
20
  *p = YYCURSOR;
1750
20
    if (!var_hash) return 0;
1751
1752
20
  if (elements < 0 || elements >= HT_MAX_SIZE || IS_FAKE_ELEM_COUNT(elements, max - YYCURSOR)) {
1753
2
    return 0;
1754
2
  }
1755
1756
18
  if (elements) {
1757
8
    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
8
    zend_hash_real_init_mixed(Z_ARRVAL_P(rval));
1761
10
  } else {
1762
10
    ZVAL_EMPTY_ARRAY(rval);
1763
10
    return finish_nested_data(UNSERIALIZE_PASSTHRU);
1764
10
  }
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
18
  HT_ALLOW_COW_VIOLATION(Z_ARRVAL_P(rval));
1771
1772
8
  if (!process_nested_array_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements)) {
1773
4
    return 0;
1774
4
  }
1775
1776
4
  return finish_nested_data(UNSERIALIZE_PASSTHRU);
1777
8
}
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
24
yy90:
1796
24
  ++YYCURSOR;
1797
24
#line 1022 "ext/standard/var_unserializer.re"
1798
24
  {
1799
24
  size_t len, maxlen;
1800
24
  char *str;
1801
1802
24
  len = parse_uiv(start + 2);
1803
24
  maxlen = max - YYCURSOR;
1804
24
  if (maxlen < len) {
1805
1
    *p = start + 2;
1806
1
    return 0;
1807
1
  }
1808
1809
23
  str = (char*)YYCURSOR;
1810
1811
23
  YYCURSOR += len;
1812
1813
23
  if (*(YYCURSOR) != '"') {
1814
0
    *p = YYCURSOR;
1815
0
    return 0;
1816
0
  }
1817
1818
23
  if (*(YYCURSOR + 1) != ';') {
1819
0
    *p = YYCURSOR + 1;
1820
0
    return 0;
1821
0
  }
1822
1823
23
  YYCURSOR += 2;
1824
23
  *p = YYCURSOR;
1825
1826
23
  if (!var_hash) {
1827
    /* Array or object key unserialization */
1828
20
    ZVAL_STR(rval, zend_string_init_existing_interned(str, len, 0));
1829
20
  } else {
1830
3
    ZVAL_STRINGL_FAST(rval, str, len);
1831
3
  }
1832
23
  return 1;
1833
23
}
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
23
}
1853
23
#line 1854 "ext/standard/var_unserializer.c"
1854
23
}
1855
0
#line 1437 "ext/standard/var_unserializer.re"
1856
1857
1858
0
  return 0;
1859
23
}