Coverage Report

Created: 2025-09-27 06:26

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