Coverage Report

Created: 2026-06-02 06:40

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