Coverage Report

Created: 2026-01-18 06:47

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