Coverage Report

Created: 2026-01-18 06:49

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