Coverage Report

Created: 2026-06-02 06:37

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