Coverage Report

Created: 2026-07-25 06:39

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