Coverage Report

Created: 2025-12-14 06:10

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