Coverage Report

Created: 2025-12-14 06:06

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