Coverage Report

Created: 2026-04-01 06:49

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