Coverage Report

Created: 2026-06-02 06:40

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