Coverage Report

Created: 2026-06-02 06:36

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