Coverage Report

Created: 2026-02-09 07:07

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