Coverage Report

Created: 2026-02-14 06:52

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