Coverage Report

Created: 2025-06-13 06:43

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