Coverage Report

Created: 2025-11-16 06:23

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