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