Coverage Report

Created: 2025-12-31 07:28

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