Coverage Report

Created: 2025-07-23 06:33

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