Coverage Report

Created: 2026-09-14 06:25

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