Coverage Report

Created: 2026-06-02 06:39

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
14.7k
#define VAR_ENTRIES_MAX 1018     /* 1024 - offsetof(php_unserialize_data, entries) / sizeof(void*) */
25
141
#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
258
#define VAR_WAKEUP_FLAG 1
31
204
#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
8.07k
  ((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
819
PHPAPI php_unserialize_data_t php_var_unserialize_init(void) {
61
819
  php_unserialize_data_t d;
62
  /* fprintf(stderr, "UNSERIALIZE_INIT    == lock: %u, level: %u\n", BG(serialize_lock), BG(unserialize).level); */
63
819
  if (BG(serialize_lock) || !BG(unserialize).level) {
64
798
    d = emalloc(sizeof(struct php_unserialize_data));
65
798
    d->last = &d->entries;
66
798
    d->first_dtor = d->last_dtor = NULL;
67
798
    d->allowed_classes = NULL;
68
798
    d->ref_props = NULL;
69
798
    d->cur_depth = 0;
70
798
    d->max_depth = BG(unserialize_max_depth);
71
798
    d->entries.used_slots = 0;
72
798
    d->entries.next = NULL;
73
798
    if (!BG(serialize_lock)) {
74
798
      BG(unserialize).data = d;
75
798
      BG(unserialize).level = 1;
76
798
    }
77
798
  } else {
78
21
    d = BG(unserialize).data;
79
21
    ++BG(unserialize).level;
80
21
  }
81
819
  return d;
82
819
}
83
84
819
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
819
  if (BG(serialize_lock) || BG(unserialize).level == 1) {
87
798
    var_destroy(&d);
88
798
    efree(d);
89
798
  }
90
819
  if (!BG(serialize_lock) && !--BG(unserialize).level) {
91
798
    BG(unserialize).data = NULL;
92
798
  }
93
819
}
94
95
798
PHPAPI HashTable *php_var_unserialize_get_allowed_classes(php_unserialize_data_t d) {
96
798
  return d->allowed_classes;
97
798
}
98
798
PHPAPI void php_var_unserialize_set_allowed_classes(php_unserialize_data_t d, HashTable *classes) {
99
798
  d->allowed_classes = classes;
100
798
}
101
102
798
PHPAPI void php_var_unserialize_set_max_depth(php_unserialize_data_t d, zend_long max_depth) {
103
798
  d->max_depth = max_depth;
104
798
}
105
798
PHPAPI zend_long php_var_unserialize_get_max_depth(php_unserialize_data_t d) {
106
798
  return d->max_depth;
107
798
}
108
109
798
PHPAPI void php_var_unserialize_set_cur_depth(php_unserialize_data_t d, zend_long cur_depth) {
110
798
  d->cur_depth = cur_depth;
111
798
}
112
798
PHPAPI zend_long php_var_unserialize_get_cur_depth(php_unserialize_data_t d) {
113
798
  return d->cur_depth;
114
798
}
115
116
static inline void var_push(php_unserialize_data_t *var_hashx, zval *rval)
117
12.5k
{
118
12.5k
  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
12.5k
  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
12.5k
  var_hash->data[var_hash->used_slots++] = rval;
133
12.5k
}
134
135
PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval *rval)
136
21
{
137
21
  if (Z_REFCOUNTED_P(rval)) {
138
21
    zval *tmp_var = var_tmp_var(var_hashx);
139
21
    if (!tmp_var) {
140
0
      return;
141
0
    }
142
21
    ZVAL_COPY(tmp_var, rval);
143
21
  }
144
21
}
145
146
static zend_never_inline void var_push_dtor_value(php_unserialize_data_t *var_hashx, zval *rval)
147
78
{
148
78
  if (Z_REFCOUNTED_P(rval)) {
149
78
    zval *tmp_var = var_tmp_var(var_hashx);
150
78
    if (!tmp_var) {
151
0
      return;
152
0
    }
153
78
    ZVAL_COPY_VALUE(tmp_var, rval);
154
78
  }
155
78
}
156
157
static zend_always_inline zval *tmp_var(php_unserialize_data_t *var_hashx, zend_long num)
158
204
{
159
204
    var_dtor_entries *var_hash;
160
204
  zend_long used_slots;
161
162
204
    if (!var_hashx || !*var_hashx || num < 1) {
163
0
        return NULL;
164
0
    }
165
166
204
    var_hash = (*var_hashx)->last_dtor;
167
204
    if (!var_hash || var_hash->used_slots + num > VAR_DTOR_ENTRIES_MAX) {
168
63
        var_hash = emalloc(sizeof(var_dtor_entries));
169
63
        var_hash->used_slots = 0;
170
63
        var_hash->next = 0;
171
172
63
        if (!(*var_hashx)->first_dtor) {
173
63
            (*var_hashx)->first_dtor = var_hash;
174
63
        } else {
175
0
            (*var_hashx)->last_dtor->next = var_hash;
176
0
        }
177
178
63
        (*var_hashx)->last_dtor = var_hash;
179
63
    }
180
426
  for (used_slots = var_hash->used_slots; var_hash->used_slots < used_slots + num; var_hash->used_slots++) {
181
222
    ZVAL_UNDEF(&var_hash->data[var_hash->used_slots]);
182
222
    Z_EXTRA(var_hash->data[var_hash->used_slots]) = 0;
183
222
  }
184
204
    return &var_hash->data[used_slots];
185
204
}
186
187
PHPAPI zval *var_tmp_var(php_unserialize_data_t *var_hashx)
188
186
{
189
186
    return tmp_var(var_hashx, 1);
190
186
}
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.08k
{
213
1.08k
  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.08k
  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.08k
  if (!var_hash) return NULL;
224
225
1.08k
  if (id < 0 || id >= var_hash->used_slots) return NULL;
226
227
1.08k
  return var_hash->data[id];
228
1.08k
}
229
230
PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
231
798
{
232
798
  void *next;
233
798
  zend_long i;
234
798
  var_entries *var_hash = (*var_hashx)->entries.next;
235
798
  var_dtor_entries *var_dtor_hash = (*var_hashx)->first_dtor;
236
798
  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
798
  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
861
  while (var_dtor_hash) {
249
285
    for (i = 0; i < var_dtor_hash->used_slots; i++) {
250
222
      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
222
      if (Z_EXTRA_P(zv) == VAR_WAKEUP_FLAG) {
256
        /* Perform delayed __wakeup calls */
257
36
        if (!delayed_call_failed) {
258
36
          zval retval;
259
36
          zend_fcall_info fci;
260
36
          zend_fcall_info_cache fci_cache;
261
262
36
          ZEND_ASSERT(Z_TYPE_P(zv) == IS_OBJECT);
263
264
36
          fci.size = sizeof(fci);
265
36
          fci.object = Z_OBJ_P(zv);
266
36
          fci.retval = &retval;
267
36
          fci.param_count = 0;
268
36
          fci.params = NULL;
269
36
          fci.named_params = NULL;
270
36
          ZVAL_UNDEF(&fci.function_name);
271
272
36
          fci_cache.function_handler = zend_hash_find_ptr(
273
36
            &fci.object->ce->function_table, ZSTR_KNOWN(ZEND_STR_WAKEUP));
274
36
          fci_cache.object = fci.object;
275
36
          fci_cache.called_scope = fci.object->ce;
276
277
36
          BG(serialize_lock)++;
278
36
          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
36
          BG(serialize_lock)--;
283
284
36
          zval_ptr_dtor(&retval);
285
36
        } else {
286
0
          GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
287
0
        }
288
186
      } else if (Z_EXTRA_P(zv) == VAR_UNSERIALIZE_FLAG) {
289
        /* Perform delayed __unserialize calls */
290
18
        if (!delayed_call_failed) {
291
18
          zval param;
292
18
          ZVAL_COPY(&param, &var_dtor_hash->data[i + 1]);
293
294
18
          BG(serialize_lock)++;
295
18
          zend_call_known_instance_method_with_1_params(
296
18
            Z_OBJCE_P(zv)->__unserialize, Z_OBJ_P(zv), NULL, &param);
297
18
          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
18
          BG(serialize_lock)--;
302
18
          zval_ptr_dtor(&param);
303
18
        } else {
304
0
          GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
305
0
        }
306
18
      }
307
308
222
      i_zval_ptr_dtor(zv);
309
222
    }
310
63
    next = var_dtor_hash->next;
311
63
    efree_size(var_dtor_hash, sizeof(var_dtor_entries));
312
63
    var_dtor_hash = next;
313
63
  }
314
315
798
  if ((*var_hashx)->ref_props) {
316
75
    zend_hash_destroy((*var_hashx)->ref_props);
317
75
    FREE_HASHTABLE((*var_hashx)->ref_props);
318
75
  }
319
798
}
320
321
/* }}} */
322
323
static zend_string *unserialize_str(const unsigned char **p, size_t len, size_t maxlen)
324
0
{
325
0
  size_t i, j;
326
0
  zend_string *str = zend_string_safe_alloc(1, len, 0, 0);
327
0
  unsigned char *end = *(unsigned char **)p+maxlen;
328
329
0
  for (i = 0; i < len; i++) {
330
0
    if (*p >= end) {
331
0
      zend_string_efree(str);
332
0
      return NULL;
333
0
    }
334
0
    if (**p != '\\') {
335
0
      ZSTR_VAL(str)[i] = (char)**p;
336
0
    } else {
337
0
      unsigned char ch = 0;
338
339
0
      for (j = 0; j < 2; j++) {
340
0
        (*p)++;
341
0
        if (**p >= '0' && **p <= '9') {
342
0
          ch = (ch << 4) + (**p -'0');
343
0
        } else if (**p >= 'a' && **p <= 'f') {
344
0
          ch = (ch << 4) + (**p -'a'+10);
345
0
        } else if (**p >= 'A' && **p <= 'F') {
346
0
          ch = (ch << 4) + (**p -'A'+10);
347
0
        } else {
348
0
          zend_string_efree(str);
349
0
          return NULL;
350
0
        }
351
0
      }
352
0
      ZSTR_VAL(str)[i] = (char)ch;
353
0
    }
354
0
    (*p)++;
355
0
  }
356
0
  ZSTR_VAL(str)[i] = 0;
357
0
  ZSTR_LEN(str) = i;
358
0
  return str;
359
0
}
360
361
static inline int unserialize_allowed_class(
362
    zend_string *lcname, php_unserialize_data_t *var_hashx)
363
216
{
364
216
  HashTable *classes = (*var_hashx)->allowed_classes;
365
366
216
  if(classes == NULL) {
367
216
    return 1;
368
216
  }
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
277
#define YYFILL(n) do { } while (0)
377
26.3k
#define YYCTYPE unsigned char
378
352k
#define YYCURSOR cursor
379
81.9k
#define YYLIMIT limit
380
25.0k
#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
13.7k
{
390
13.7k
  zend_ulong result = 0;
391
13.7k
  zend_ulong neg = 0;
392
13.7k
  const unsigned char *start;
393
394
13.7k
  if (*p == '-') {
395
3
    neg = 1;
396
3
    p++;
397
13.6k
  } else if (UNEXPECTED(*p == '+')) {
398
0
    p++;
399
0
  }
400
401
20.5k
  while (UNEXPECTED(*p == '0')) {
402
6.84k
    p++;
403
6.84k
  }
404
405
13.7k
  start = p;
406
407
22.1k
  while (*p >= '0' && *p <= '9') {
408
8.49k
    result = result * 10 + ((zend_ulong)(*p) - '0');
409
8.49k
    p++;
410
8.49k
  }
411
412
13.7k
  if (q) {
413
357
    *q = p;
414
357
  }
415
416
  /* number too long or overflow */
417
13.7k
  if (UNEXPECTED(p - start > MAX_LENGTH_OF_LONG - 1)
418
13.6k
   || (SIZEOF_ZEND_LONG == 4
419
0
    && UNEXPECTED(p - start == MAX_LENGTH_OF_LONG - 1)
420
0
    && UNEXPECTED(*start > '2'))
421
13.6k
   || UNEXPECTED(result > ZEND_LONG_MAX + neg)) {
422
3
    php_error_docref(NULL, E_WARNING, "Numerical result out of range");
423
3
    return (!neg) ? ZEND_LONG_MAX : ZEND_LONG_MIN;
424
3
  }
425
426
13.6k
  return (zend_long) ((!neg) ? result : -result);
427
13.7k
}
428
429
static inline zend_long parse_iv(const unsigned char *p)
430
13.3k
{
431
13.3k
  return parse_iv2(p, NULL);
432
13.3k
}
433
434
/* no need to check for length - re2c already did */
435
static inline size_t parse_uiv(const unsigned char *p)
436
11.5k
{
437
11.5k
  unsigned char cursor;
438
11.5k
  size_t result = 0;
439
440
25.6k
  while (1) {
441
25.6k
    cursor = *p;
442
25.6k
    if (cursor >= '0' && cursor <= '9') {
443
14.0k
      result = result * 10 + (size_t)(cursor - (unsigned char)'0');
444
14.0k
    } else {
445
11.5k
      break;
446
11.5k
    }
447
14.0k
    p++;
448
14.0k
  }
449
11.5k
  return result;
450
11.5k
}
451
452
#define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash
453
11.5k
#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
2.14k
{
459
2.14k
  if (var_hash) {
460
2.14k
    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
2.14k
    (*var_hash)->cur_depth++;
469
2.14k
  }
470
471
14.3k
  while (elements-- > 0) {
472
12.3k
    zval key, *data;
473
12.3k
    zend_ulong idx;
474
475
12.3k
    ZVAL_UNDEF(&key);
476
477
12.3k
    if (!php_var_unserialize_internal(&key, p, max, NULL)) {
478
21
      zval_ptr_dtor(&key);
479
21
      goto failure;
480
21
    }
481
482
12.3k
    if (Z_TYPE(key) == IS_LONG) {
483
4.75k
      idx = Z_LVAL(key);
484
4.75k
numeric_key:
485
4.75k
      data = zend_hash_index_lookup(ht, idx);
486
4.75k
      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
7.55k
    } else if (Z_TYPE(key) == IS_STRING) {
491
7.55k
      if (UNEXPECTED(ZEND_HANDLE_NUMERIC(Z_STR(key), idx))) {
492
0
        zval_ptr_dtor_str(&key);
493
0
        goto numeric_key;
494
0
      }
495
7.55k
      data = zend_hash_lookup(ht, Z_STR(key));
496
7.55k
      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
7.55k
      zval_ptr_dtor_str(&key);
501
7.55k
    } else {
502
0
      zval_ptr_dtor(&key);
503
0
      goto failure;
504
0
    }
505
506
12.3k
    if (!php_var_unserialize_internal(data, p, max, var_hash)) {
507
51
      goto failure;
508
51
    }
509
510
12.2k
    if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
511
0
      (*p)--;
512
0
      goto failure;
513
0
    }
514
12.2k
  }
515
516
2.07k
  if (var_hash) {
517
2.07k
    (*var_hash)->cur_depth--;
518
2.07k
  }
519
2.07k
  return 1;
520
521
72
failure:
522
72
  if (var_hash) {
523
72
    (*var_hash)->cur_depth--;
524
72
  }
525
72
  return 0;
526
2.14k
}
527
528
static int is_property_visibility_changed(zend_class_entry *ce, zval *key)
529
99
{
530
99
  if (zend_hash_num_elements(&ce->properties_info) > 0) {
531
36
    zend_property_info *existing_propinfo = NULL;
532
36
    const char *unmangled_class = NULL;
533
36
    const char *unmangled_prop;
534
36
    size_t unmangled_prop_len;
535
536
36
    if (UNEXPECTED(zend_unmangle_property_name_ex(Z_STR_P(key), &unmangled_class, &unmangled_prop, &unmangled_prop_len) == FAILURE)) {
537
0
      zval_ptr_dtor_str(key);
538
0
      return -1;
539
0
    }
540
541
36
    if (unmangled_class == NULL) {
542
15
      existing_propinfo = zend_hash_find_ptr(&ce->properties_info, Z_STR_P(key));
543
21
    } else {
544
21
      if (!strcmp(unmangled_class, "*")
545
18
       || !strcasecmp(unmangled_class, ZSTR_VAL(ce->name))) {
546
18
        existing_propinfo = zend_hash_str_find_ptr(
547
18
          &ce->properties_info, unmangled_prop, unmangled_prop_len);
548
18
      }
549
21
    }
550
551
36
    if (existing_propinfo != NULL) {
552
6
      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
6
      } else {
557
6
        php_error_docref(NULL, E_WARNING,
558
6
          "Cannot unserialize value for virtual property %s::$%s",
559
6
          ZSTR_VAL(existing_propinfo->ce->name), Z_STRVAL_P(key));
560
6
        zval_ptr_dtor_str(key);
561
6
        return -1;
562
6
      }
563
6
    }
564
36
  }
565
93
  return 0;
566
99
}
567
568
569
static zend_always_inline int process_nested_object_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, zend_object *obj)
570
249
{
571
249
  if (var_hash) {
572
249
    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
249
    (*var_hash)->cur_depth++;
581
249
  }
582
583
645
  while (elements-- > 0) {
584
471
    zval key, *data;
585
471
    zend_property_info *info = NULL;
586
587
471
    ZVAL_UNDEF(&key);
588
589
471
    if (!php_var_unserialize_internal(&key, p, max, NULL)) {
590
21
      zval_ptr_dtor(&key);
591
21
      goto failure;
592
21
    }
593
594
450
    if (EXPECTED(Z_TYPE(key) == IS_STRING)) {
595
450
string_key:
596
450
      data = zend_hash_find(ht, Z_STR(key));
597
450
      if (data != NULL) {
598
351
        if (Z_TYPE_P(data) == IS_INDIRECT) {
599
351
declared_property:
600
          /* This is a property with a declaration */
601
351
          data = Z_INDIRECT_P(data);
602
351
          info = zend_get_typed_property_info_for_slot(obj, data);
603
351
          if (info) {
604
231
            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
231
            if ((*var_hash)->ref_props) {
610
              /* Remove old entry from ref_props table, if it exists. */
611
156
              zend_hash_index_del(
612
156
                (*var_hash)->ref_props, (uintptr_t) data);
613
156
            }
614
231
          }
615
          /* We may override default property value, but they are usually immutable */
616
351
          if (Z_REFCOUNTED_P(data)) {
617
78
            var_push_dtor_value(var_hash, data);
618
78
          }
619
351
          ZVAL_NULL(data);
620
351
        } else {
621
          /* Unusual override of dynamic property */
622
0
          int ret = is_property_visibility_changed(obj->ce, &key);
623
624
0
          if (ret > 0) {
625
0
            goto second_try;
626
0
          } else if (!ret) {
627
0
            var_push_dtor_value(var_hash, data);
628
0
            ZVAL_NULL(data);
629
0
          } else if (ret < 0) {
630
0
            goto failure;
631
0
          }
632
0
        }
633
351
      } else {
634
99
        int ret = is_property_visibility_changed(obj->ce, &key);
635
636
99
        if (EXPECTED(!ret)) {
637
93
          if (UNEXPECTED(obj->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) {
638
3
            zend_throw_error(NULL, "Cannot create dynamic property %s::$%s",
639
3
              ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key)));
640
3
            zval_ptr_dtor_str(&key);
641
3
            goto failure;
642
90
          } else if (!(obj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) {
643
24
            zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated",
644
24
              ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key)));
645
24
            if (EG(exception)) {
646
0
              zval_ptr_dtor_str(&key);
647
0
              goto failure;
648
0
            }
649
24
          }
650
651
90
          data = zend_hash_add_new(ht, Z_STR(key), &EG(uninitialized_zval));
652
90
        } else if (ret < 0) {
653
6
          goto failure;
654
6
        } 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
99
      }
665
441
      zval_ptr_dtor_str(&key);
666
441
    } else if (Z_TYPE(key) == IS_LONG) {
667
      /* object properties should include no integers */
668
33
      convert_to_string(&key);
669
33
      goto string_key;
670
33
    } else {
671
0
      zval_ptr_dtor(&key);
672
0
      goto failure;
673
0
    }
674
675
441
    if (!php_var_unserialize_internal(data, p, max, var_hash)) {
676
42
      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
42
      goto failure;
682
42
    }
683
684
399
    if (UNEXPECTED(info)) {
685
228
      if (!zend_verify_prop_assignable_by_ref(info, data, /* strict */ 1)) {
686
3
        zval_ptr_dtor(data);
687
3
        ZVAL_UNDEF(data);
688
3
        goto failure;
689
3
      }
690
691
225
      if (Z_ISREF_P(data)) {
692
0
        ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), info);
693
225
      } 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
225
        if (!(*var_hash)->ref_props) {
697
75
          (*var_hash)->ref_props = emalloc(sizeof(HashTable));
698
75
          zend_hash_init((*var_hash)->ref_props, 8, NULL, NULL, 0);
699
75
        }
700
225
        zend_hash_index_update_ptr(
701
225
          (*var_hash)->ref_props, (uintptr_t) data, info);
702
225
      }
703
225
    }
704
705
396
    if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
706
0
      (*p)--;
707
0
      goto failure;
708
0
    }
709
396
  }
710
711
174
  if (var_hash) {
712
174
    (*var_hash)->cur_depth--;
713
174
  }
714
174
  return 1;
715
716
75
failure:
717
75
  if (var_hash) {
718
75
    (*var_hash)->cur_depth--;
719
75
  }
720
75
  return 0;
721
249
}
722
723
static inline int finish_nested_data(UNSERIALIZE_PARAMETER)
724
7.92k
{
725
7.92k
  if (*p >= max || **p != '}') {
726
3
    return 0;
727
3
  }
728
729
7.91k
  (*p)++;
730
7.91k
  return 1;
731
7.92k
}
732
733
static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
734
30
{
735
30
  zend_long datalen;
736
737
30
  datalen = parse_iv2((*p) + 2, p);
738
739
30
  if (max - (*p) < 2) {
740
0
    return 0;
741
0
  }
742
743
30
  if ((*p)[0] != ':') {
744
3
    return 0;
745
3
  }
746
747
27
  if ((*p)[1] != '{') {
748
0
    (*p) += 1;
749
0
    return 0;
750
0
  }
751
752
27
  (*p) += 2;
753
754
27
  if (datalen < 0 || (max - (*p)) <= datalen) {
755
0
    zend_error(E_WARNING, "Insufficient data for unserializing - " ZEND_LONG_FMT " required, " ZEND_LONG_FMT " present", datalen, (zend_long)(max - (*p)));
756
0
    return 0;
757
0
  }
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
27
  if ((*p)[datalen] != '}') {
763
0
    (*p) += datalen;
764
0
    return 0;
765
0
  }
766
767
27
  if (ce->unserialize == NULL) {
768
3
    zend_error(E_WARNING, "Class %s has no unserializer", ZSTR_VAL(ce->name));
769
3
    object_init_ex(rval, ce);
770
24
  } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash) != SUCCESS) {
771
12
    return 0;
772
12
  }
773
774
15
  (*p) += datalen + 1; /* +1 for '}' */
775
15
  return 1;
776
27
}
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
318
{
783
318
  HashTable *ht;
784
318
  bool has_wakeup;
785
786
318
  if (has_unserialize) {
787
69
    zval ary, *tmp;
788
789
69
    if (elements >= HT_MAX_SIZE) {
790
0
      return 0;
791
0
    }
792
793
69
    array_init_size(&ary, elements);
794
    /* Avoid reallocation due to packed -> mixed conversion. */
795
69
    zend_hash_real_init_mixed(Z_ARRVAL(ary));
796
69
    if (!process_nested_array_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL(ary), elements)) {
797
51
      ZVAL_DEREF(rval);
798
51
      GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED);
799
51
      zval_ptr_dtor(&ary);
800
51
      return 0;
801
51
    }
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
18
    ZVAL_DEREF(rval);
806
18
    tmp = tmp_var(var_hash, 2);
807
18
    ZVAL_COPY(tmp, rval);
808
18
    Z_EXTRA_P(tmp) = VAR_UNSERIALIZE_FLAG;
809
18
    tmp++;
810
18
    ZVAL_COPY_VALUE(tmp, &ary);
811
812
18
    return finish_nested_data(UNSERIALIZE_PASSTHRU);
813
69
  }
814
815
249
  has_wakeup = Z_OBJCE_P(rval) != PHP_IC_ENTRY
816
219
    && zend_hash_exists(&Z_OBJCE_P(rval)->function_table, ZSTR_KNOWN(ZEND_STR_WAKEUP));
817
818
249
  ht = Z_OBJPROP_P(rval);
819
249
  if (elements >= (zend_long)(HT_MAX_SIZE - zend_hash_num_elements(ht))) {
820
0
    return 0;
821
0
  }
822
823
249
  zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, HT_IS_PACKED(ht));
824
249
  if (!process_nested_object_data(UNSERIALIZE_PASSTHRU, ht, elements, Z_OBJ_P(rval))) {
825
75
    if (has_wakeup) {
826
24
      ZVAL_DEREF(rval);
827
24
      GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED);
828
24
    }
829
75
    return 0;
830
75
  }
831
832
174
  ZVAL_DEREF(rval);
833
174
  if (has_wakeup) {
834
    /* Delay __wakeup call until end of serialization */
835
36
    zval *wakeup_var = var_tmp_var(var_hash);
836
36
    ZVAL_COPY(wakeup_var, rval);
837
36
    Z_EXTRA_P(wakeup_var) = VAR_WAKEUP_FLAG;
838
36
  }
839
840
174
  return finish_nested_data(UNSERIALIZE_PASSTHRU);
841
249
}
842
#ifdef PHP_WIN32
843
# pragma optimize("", on)
844
#endif
845
846
PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
847
849
{
848
849
  var_entries *orig_var_entries = (*var_hash)->last;
849
849
  zend_long orig_used_slots = orig_var_entries ? orig_var_entries->used_slots : 0;
850
849
  int result;
851
852
849
  result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU);
853
854
849
  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
207
    var_entries *e = orig_var_entries;
859
207
    zend_long s = orig_used_slots;
860
414
    while (e) {
861
597
      for (; s < e->used_slots; s++) {
862
390
        e->data[s] = NULL;
863
390
      }
864
865
207
      e = e->next;
866
207
      s = 0;
867
207
    }
868
207
  }
869
870
849
  return result;
871
849
}
872
873
static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
874
26.3k
{
875
26.3k
  const unsigned char *cursor, *limit, *marker, *start;
876
26.3k
  zval *rval_ref;
877
878
26.3k
  limit = max;
879
26.3k
  cursor = *p;
880
881
26.3k
  if (YYCURSOR >= YYLIMIT) {
882
0
    return 0;
883
0
  }
884
885
26.3k
  if (var_hash && (*p)[0] != 'R') {
886
12.5k
    var_push(var_hash, rval);
887
12.5k
  }
888
889
26.3k
  start = cursor;
890
891
892
26.3k
#line 893 "ext/standard/var_unserializer.c"
893
26.3k
{
894
26.3k
  YYCTYPE yych;
895
26.3k
  static const unsigned char yybm[] = {
896
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
897
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
898
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
899
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
900
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
901
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
902
26.3k
    128, 128, 128, 128, 128, 128, 128, 128, 
903
26.3k
    128, 128,   0,   0,   0,   0,   0,   0, 
904
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
905
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
906
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
907
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
908
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
909
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
910
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
911
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
912
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
913
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
914
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
915
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
916
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
917
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
918
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
919
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
920
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
921
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
922
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
923
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
924
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
925
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
926
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
927
26.3k
      0,   0,   0,   0,   0,   0,   0,   0, 
928
26.3k
  };
929
26.3k
  if ((YYLIMIT - YYCURSOR) < 7) YYFILL(7);
930
26.3k
  yych = *YYCURSOR;
931
26.3k
  switch (yych) {
932
36
  case 'C':
933
408
  case 'O': goto yy4;
934
60
  case 'E': goto yy5;
935
1.37k
  case 'N': goto yy6;
936
1.05k
  case 'R': goto yy7;
937
3
  case 'S': goto yy8;
938
7.75k
  case 'a': goto yy9;
939
0
  case 'b': goto yy10;
940
0
  case 'd': goto yy11;
941
5.61k
  case 'i': goto yy12;
942
36
  case 'r': goto yy13;
943
10.0k
  case 's': goto yy14;
944
0
  case '}': goto yy15;
945
3
  default:  goto yy2;
946
26.3k
  }
947
3
yy2:
948
3
  ++YYCURSOR;
949
102
yy3:
950
102
#line 1435 "ext/standard/var_unserializer.re"
951
102
  { return 0; }
952
0
#line 953 "ext/standard/var_unserializer.c"
953
408
yy4:
954
408
  yych = *(YYMARKER = ++YYCURSOR);
955
408
  if (yych == ':') goto yy17;
956
6
  goto yy3;
957
60
yy5:
958
60
  yych = *(YYMARKER = ++YYCURSOR);
959
60
  if (yych == ':') goto yy19;
960
3
  goto yy3;
961
1.37k
yy6:
962
1.37k
  yych = *++YYCURSOR;
963
1.37k
  if (yych == ';') goto yy20;
964
3
  goto yy3;
965
1.05k
yy7:
966
1.05k
  yych = *(YYMARKER = ++YYCURSOR);
967
1.05k
  if (yych == ':') goto yy22;
968
0
  goto yy3;
969
3
yy8:
970
3
  yych = *(YYMARKER = ++YYCURSOR);
971
3
  if (yych == ':') goto yy23;
972
3
  goto yy3;
973
7.75k
yy9:
974
7.75k
  yych = *(YYMARKER = ++YYCURSOR);
975
7.75k
  if (yych == ':') goto yy24;
976
3
  goto yy3;
977
3
yy10:
978
0
  yych = *(YYMARKER = ++YYCURSOR);
979
0
  if (yych == ':') goto yy25;
980
0
  goto yy3;
981
0
yy11:
982
0
  yych = *(YYMARKER = ++YYCURSOR);
983
0
  if (yych == ':') goto yy26;
984
0
  goto yy3;
985
5.61k
yy12:
986
5.61k
  yych = *(YYMARKER = ++YYCURSOR);
987
5.61k
  if (yych == ':') goto yy27;
988
3
  goto yy3;
989
36
yy13:
990
36
  yych = *(YYMARKER = ++YYCURSOR);
991
36
  if (yych == ':') goto yy28;
992
3
  goto yy3;
993
10.0k
yy14:
994
10.0k
  yych = *(YYMARKER = ++YYCURSOR);
995
10.0k
  if (yych == ':') goto yy29;
996
3
  goto yy3;
997
3
yy15:
998
0
  ++YYCURSOR;
999
0
#line 1429 "ext/standard/var_unserializer.re"
1000
0
  {
1001
  /* this is the case where we have less data than planned */
1002
0
  php_error_docref(NULL, E_WARNING, "Unexpected end of serialized data");
1003
0
  return 0; /* not sure if it should be 0 or 1 here? */
1004
10.0k
}
1005
0
#line 1006 "ext/standard/var_unserializer.c"
1006
402
yy17:
1007
402
  yych = *++YYCURSOR;
1008
402
  if (yybm[0+yych] & 128) {
1009
399
    goto yy30;
1010
399
  }
1011
72
yy18:
1012
72
  YYCURSOR = YYMARKER;
1013
72
  goto yy3;
1014
57
yy19:
1015
57
  yych = *++YYCURSOR;
1016
57
  if (yych <= '/') goto yy18;
1017
57
  if (yych <= '9') goto yy32;
1018
0
  goto yy18;
1019
1.37k
yy20:
1020
1.37k
  ++YYCURSOR;
1021
1.37k
#line 953 "ext/standard/var_unserializer.re"
1022
1.37k
  {
1023
1.37k
  *p = YYCURSOR;
1024
1.37k
  ZVAL_NULL(rval);
1025
1.37k
  return 1;
1026
57
}
1027
0
#line 1028 "ext/standard/var_unserializer.c"
1028
1.05k
yy22:
1029
1.05k
  yych = *++YYCURSOR;
1030
1.05k
  if (yych <= '/') goto yy18;
1031
1.05k
  if (yych <= '9') goto yy34;
1032
0
  goto yy18;
1033
0
yy23:
1034
0
  yych = *++YYCURSOR;
1035
0
  if (yych <= '/') goto yy18;
1036
0
  if (yych <= '9') goto yy36;
1037
0
  goto yy18;
1038
7.75k
yy24:
1039
7.75k
  yych = *++YYCURSOR;
1040
7.75k
  if (yych <= '/') goto yy18;
1041
7.75k
  if (yych <= '9') goto yy38;
1042
0
  goto yy18;
1043
0
yy25:
1044
0
  yych = *++YYCURSOR;
1045
0
  if (yych <= '/') goto yy18;
1046
0
  if (yych <= '0') goto yy40;
1047
0
  if (yych <= '1') goto yy41;
1048
0
  goto yy18;
1049
0
yy26:
1050
0
  yych = *++YYCURSOR;
1051
0
  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
0
  } else {
1061
0
    if (yych <= 'I') {
1062
0
      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
0
  }
1070
5.61k
yy27:
1071
5.61k
  yych = *++YYCURSOR;
1072
5.61k
  if (yych <= ',') {
1073
3
    if (yych == '+') goto yy49;
1074
3
    goto yy18;
1075
5.60k
  } else {
1076
5.60k
    if (yych <= '-') goto yy49;
1077
5.60k
    if (yych <= '/') goto yy18;
1078
5.60k
    if (yych <= '9') goto yy50;
1079
3
    goto yy18;
1080
5.60k
  }
1081
33
yy28:
1082
33
  yych = *++YYCURSOR;
1083
33
  if (yych <= '/') goto yy18;
1084
33
  if (yych <= '9') goto yy52;
1085
3
  goto yy18;
1086
10.0k
yy29:
1087
10.0k
  yych = *++YYCURSOR;
1088
10.0k
  if (yych <= '/') goto yy18;
1089
10.0k
  if (yych <= '9') goto yy54;
1090
3
  goto yy18;
1091
495
yy30:
1092
495
  ++YYCURSOR;
1093
495
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1094
495
  yych = *YYCURSOR;
1095
495
  if (yybm[0+yych] & 128) {
1096
96
    goto yy30;
1097
96
  }
1098
399
  if (yych <= '/') goto yy18;
1099
396
  if (yych <= ':') goto yy56;
1100
3
  goto yy18;
1101
57
yy32:
1102
57
  ++YYCURSOR;
1103
57
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1104
57
  yych = *YYCURSOR;
1105
57
  if (yych <= '/') goto yy18;
1106
54
  if (yych <= '9') goto yy32;
1107
54
  if (yych <= ':') goto yy57;
1108
0
  goto yy18;
1109
2.34k
yy34:
1110
2.34k
  ++YYCURSOR;
1111
2.34k
  if (YYLIMIT <= YYCURSOR) YYFILL(1);
1112
2.34k
  yych = *YYCURSOR;
1113
2.34k
  if (yych <= '/') goto yy18;
1114
2.34k
  if (yych <= '9') goto yy34;
1115
1.05k
  if (yych == ';') goto yy58;
1116
0
  goto yy18;
1117
0
yy36:
1118
0
  ++YYCURSOR;
1119
0
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1120
0
  yych = *YYCURSOR;
1121
0
  if (yych <= '/') goto yy18;
1122
0
  if (yych <= '9') goto yy36;
1123
0
  if (yych <= ':') goto yy60;
1124
0
  goto yy18;
1125
8.40k
yy38:
1126
8.40k
  ++YYCURSOR;
1127
8.40k
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1128
8.40k
  yych = *YYCURSOR;
1129
8.40k
  if (yych <= '/') goto yy18;
1130
8.40k
  if (yych <= '9') goto yy38;
1131
7.75k
  if (yych <= ':') goto yy61;
1132
3
  goto yy18;
1133
3
yy40:
1134
0
  yych = *++YYCURSOR;
1135
0
  if (yych == ';') goto yy62;
1136
0
  goto yy18;
1137
0
yy41:
1138
0
  yych = *++YYCURSOR;
1139
0
  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
0
yy45:
1162
0
  ++YYCURSOR;
1163
0
  if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
1164
0
  yych = *YYCURSOR;
1165
0
  if (yych <= ':') {
1166
0
    if (yych <= '.') {
1167
0
      if (yych <= '-') goto yy18;
1168
0
      goto yy66;
1169
0
    } else {
1170
0
      if (yych <= '/') goto yy18;
1171
0
      if (yych <= '9') goto yy45;
1172
0
      goto yy18;
1173
0
    }
1174
0
  } 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
0
yy49:
1193
0
  yych = *++YYCURSOR;
1194
0
  if (yych <= '/') goto yy18;
1195
0
  if (yych >= ':') goto yy18;
1196
6.63k
yy50:
1197
6.63k
  ++YYCURSOR;
1198
6.63k
  if (YYLIMIT <= YYCURSOR) YYFILL(1);
1199
6.63k
  yych = *YYCURSOR;
1200
6.63k
  if (yych <= '/') goto yy18;
1201
6.63k
  if (yych <= '9') goto yy50;
1202
5.60k
  if (yych == ';') goto yy73;
1203
6
  goto yy18;
1204
30
yy52:
1205
30
  ++YYCURSOR;
1206
30
  if (YYLIMIT <= YYCURSOR) YYFILL(1);
1207
30
  yych = *YYCURSOR;
1208
30
  if (yych <= '/') goto yy18;
1209
30
  if (yych <= '9') goto yy52;
1210
30
  if (yych == ';') goto yy75;
1211
3
  goto yy18;
1212
11.1k
yy54:
1213
11.1k
  ++YYCURSOR;
1214
11.1k
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1215
11.1k
  yych = *YYCURSOR;
1216
11.1k
  if (yych <= '/') goto yy18;
1217
11.1k
  if (yych <= '9') goto yy54;
1218
10.0k
  if (yych <= ':') goto yy77;
1219
3
  goto yy18;
1220
393
yy56:
1221
393
  yych = *++YYCURSOR;
1222
393
  if (yych == '"') goto yy78;
1223
6
  goto yy18;
1224
54
yy57:
1225
54
  yych = *++YYCURSOR;
1226
54
  if (yych == '"') goto yy80;
1227
3
  goto yy18;
1228
1.05k
yy58:
1229
1.05k
  ++YYCURSOR;
1230
1.05k
#line 897 "ext/standard/var_unserializer.re"
1231
1.05k
  {
1232
1.05k
  zend_long id;
1233
1234
1.05k
  *p = YYCURSOR;
1235
1.05k
  if (!var_hash) return 0;
1236
1237
1.05k
  id = parse_uiv(start + 2) - 1;
1238
1.05k
  if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) {
1239
0
    return 0;
1240
0
  }
1241
1242
1.05k
  if (rval_ref == rval || (Z_ISREF_P(rval_ref) && Z_REFVAL_P(rval_ref) == rval)) {
1243
0
    return 0;
1244
0
  }
1245
1246
1.05k
  if (!Z_ISREF_P(rval_ref)) {
1247
691
    zend_property_info *info = NULL;
1248
691
    if ((*var_hash)->ref_props) {
1249
0
      info = zend_hash_index_find_ptr((*var_hash)->ref_props, (uintptr_t) rval_ref);
1250
0
    }
1251
691
    ZVAL_NEW_REF(rval_ref, rval_ref);
1252
691
    if (info) {
1253
0
      ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(rval_ref), info);
1254
0
    }
1255
691
  }
1256
1257
1.05k
  ZVAL_COPY(rval, rval_ref);
1258
1259
1.05k
  return 1;
1260
1.05k
}
1261
0
#line 1262 "ext/standard/var_unserializer.c"
1262
0
yy60:
1263
0
  yych = *++YYCURSOR;
1264
0
  if (yych == '"') goto yy82;
1265
0
  goto yy18;
1266
7.75k
yy61:
1267
7.75k
  yych = *++YYCURSOR;
1268
7.75k
  if (yych == '{') goto yy84;
1269
3
  goto yy18;
1270
3
yy62:
1271
0
  ++YYCURSOR;
1272
0
#line 959 "ext/standard/var_unserializer.re"
1273
0
  {
1274
0
  *p = YYCURSOR;
1275
0
  ZVAL_FALSE(rval);
1276
0
  return 1;
1277
7.75k
}
1278
0
#line 1279 "ext/standard/var_unserializer.c"
1279
0
yy64:
1280
0
  ++YYCURSOR;
1281
0
#line 965 "ext/standard/var_unserializer.re"
1282
0
  {
1283
0
  *p = YYCURSOR;
1284
0
  ZVAL_TRUE(rval);
1285
0
  return 1;
1286
7.75k
}
1287
0
#line 1288 "ext/standard/var_unserializer.c"
1288
0
yy66:
1289
0
  ++YYCURSOR;
1290
0
  if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
1291
0
  yych = *YYCURSOR;
1292
0
  if (yych <= ';') {
1293
0
    if (yych <= '/') goto yy18;
1294
0
    if (yych <= '9') goto yy66;
1295
0
    if (yych <= ':') goto yy18;
1296
0
  } else {
1297
0
    if (yych <= 'E') {
1298
0
      if (yych <= 'D') goto yy18;
1299
0
      goto yy70;
1300
0
    } else {
1301
0
      if (yych == 'e') goto yy70;
1302
0
      goto yy18;
1303
0
    }
1304
0
  }
1305
0
yy68:
1306
0
  ++YYCURSOR;
1307
0
#line 1013 "ext/standard/var_unserializer.re"
1308
0
  {
1309
#if SIZEOF_ZEND_LONG == 4
1310
use_double:
1311
#endif
1312
0
  *p = YYCURSOR;
1313
0
  ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL));
1314
0
  return 1;
1315
0
}
1316
0
#line 1317 "ext/standard/var_unserializer.c"
1317
0
yy70:
1318
0
  yych = *++YYCURSOR;
1319
0
  if (yych <= ',') {
1320
0
    if (yych == '+') goto yy86;
1321
0
    goto yy18;
1322
0
  } 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
5.59k
yy73:
1337
5.59k
  ++YYCURSOR;
1338
5.59k
#line 971 "ext/standard/var_unserializer.re"
1339
5.59k
  {
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
5.59k
  *p = YYCURSOR;
1361
5.59k
  ZVAL_LONG(rval, parse_iv(start + 2));
1362
5.59k
  return 1;
1363
0
}
1364
0
#line 1365 "ext/standard/var_unserializer.c"
1365
27
yy75:
1366
27
  ++YYCURSOR;
1367
27
#line 928 "ext/standard/var_unserializer.re"
1368
27
  {
1369
27
  zend_long id;
1370
1371
27
  *p = YYCURSOR;
1372
27
  if (!var_hash) return 0;
1373
1374
27
  id = parse_uiv(start + 2) - 1;
1375
27
  if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) {
1376
0
    return 0;
1377
0
  }
1378
1379
27
  if (rval_ref == rval) {
1380
0
    return 0;
1381
0
  }
1382
1383
27
  ZVAL_DEREF(rval_ref);
1384
27
  if (Z_TYPE_P(rval_ref) != IS_OBJECT) {
1385
0
    return 0;
1386
0
  }
1387
1388
27
  ZVAL_COPY(rval, rval_ref);
1389
1390
27
  return 1;
1391
27
}
1392
0
#line 1393 "ext/standard/var_unserializer.c"
1393
10.0k
yy77:
1394
10.0k
  yych = *++YYCURSOR;
1395
10.0k
  if (yych == '"') goto yy90;
1396
9
  goto yy18;
1397
387
yy78:
1398
387
  ++YYCURSOR;
1399
387
#line 1129 "ext/standard/var_unserializer.re"
1400
387
  {
1401
387
  size_t len, maxlen;
1402
387
  zend_long elements;
1403
387
  char *str;
1404
387
  zend_string *class_name;
1405
387
  zend_class_entry *ce;
1406
387
  bool incomplete_class = 0;
1407
387
  bool custom_object = 0;
1408
387
  bool has_unserialize = 0;
1409
1410
387
  zval user_func;
1411
387
  zval retval;
1412
387
  zval args[1];
1413
1414
387
    if (!var_hash) return 0;
1415
387
  if (*start == 'C') {
1416
36
    custom_object = 1;
1417
36
  }
1418
1419
387
  len = parse_uiv(start + 2);
1420
387
  maxlen = max - YYCURSOR;
1421
387
  if (maxlen < len || len == 0) {
1422
6
    *p = start + 2;
1423
6
    return 0;
1424
6
  }
1425
1426
381
  str = (char*)YYCURSOR;
1427
1428
381
  YYCURSOR += len;
1429
1430
381
  if (*(YYCURSOR) != '"') {
1431
3
    *p = YYCURSOR;
1432
3
    return 0;
1433
3
  }
1434
378
  if (*(YYCURSOR+1) != ':') {
1435
3
    *p = YYCURSOR+1;
1436
3
    return 0;
1437
3
  }
1438
1439
375
  if (len == 0) {
1440
    /* empty class names are not allowed */
1441
0
    return 0;
1442
0
  }
1443
1444
375
  if (str[0] == '\000') {
1445
    /* runtime definition keys are not allowed */
1446
3
    return 0;
1447
3
  }
1448
1449
372
  if (str[0] == '\\') {
1450
    /* class name can't start from namespace separator */
1451
0
    return 0;
1452
0
  }
1453
1454
372
  class_name = zend_string_init_interned(str, len, 0);
1455
1456
372
  do {
1457
372
    zend_string *lc_name;
1458
1459
372
    if (!(*var_hash)->allowed_classes && ZSTR_HAS_CE_CACHE(class_name)) {
1460
336
      ce = ZSTR_GET_CE_CACHE(class_name);
1461
336
      if (ce) {
1462
156
        break;
1463
156
      }
1464
336
    }
1465
1466
216
    lc_name = zend_string_tolower(class_name);
1467
216
    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
216
    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
216
    ce = zend_hash_find_ptr(EG(class_table), lc_name);
1487
216
    if (ce
1488
171
     && (ce->ce_flags & ZEND_ACC_LINKED)
1489
171
     && !(ce->ce_flags & ZEND_ACC_ANON_CLASS)) {
1490
171
      zend_string_release_ex(lc_name, 0);
1491
171
      break;
1492
171
    }
1493
1494
45
    if (!ZSTR_HAS_CE_CACHE(class_name) && !zend_is_valid_class_name(class_name)) {
1495
3
      zend_string_release_ex(lc_name, 0);
1496
3
      zend_string_release_ex(class_name, 0);
1497
3
      return 0;
1498
3
    }
1499
1500
    /* Try to find class directly */
1501
42
    BG(serialize_lock)++;
1502
42
    ce = zend_lookup_class_ex(class_name, lc_name, 0);
1503
42
    BG(serialize_lock)--;
1504
42
    zend_string_release_ex(lc_name, 0);
1505
42
    if (EG(exception)) {
1506
0
      zend_string_release_ex(class_name, 0);
1507
0
      return 0;
1508
0
    }
1509
1510
42
    if (ce) {
1511
0
      break;
1512
0
    }
1513
1514
    /* Check for unserialize callback */
1515
42
    if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
1516
42
      incomplete_class = 1;
1517
42
      ce = PHP_IC_ENTRY;
1518
42
      break;
1519
42
    }
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
369
  *p = YYCURSOR;
1549
1550
369
  if (ce->ce_flags & ZEND_ACC_NOT_SERIALIZABLE) {
1551
12
    zend_throw_exception_ex(NULL, 0, "Unserialization of '%s' is not allowed",
1552
12
      ZSTR_VAL(ce->name));
1553
12
    zend_string_release_ex(class_name, 0);
1554
12
    return 0;
1555
12
  }
1556
1557
357
  if (custom_object) {
1558
30
    int ret;
1559
1560
30
    ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
1561
1562
30
    if (ret && incomplete_class) {
1563
3
      php_store_class_name(rval, class_name);
1564
3
    }
1565
30
    zend_string_release_ex(class_name, 0);
1566
30
    return ret;
1567
30
  }
1568
1569
327
  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
327
  elements = parse_iv2(*p + 2, p);
1576
327
  if (elements < 0 || IS_FAKE_ELEM_COUNT(elements, max - YYCURSOR)) {
1577
3
    zend_string_release_ex(class_name, 0);
1578
3
    return 0;
1579
3
  }
1580
1581
324
  YYCURSOR = *p;
1582
1583
324
  if (*(YYCURSOR) != ':') {
1584
3
    zend_string_release_ex(class_name, 0);
1585
3
    return 0;
1586
3
  }
1587
321
  if (*(YYCURSOR+1) != '{') {
1588
3
    *p = YYCURSOR+1;
1589
3
    zend_string_release_ex(class_name, 0);
1590
3
    return 0;
1591
3
  }
1592
1593
318
  *p += 2;
1594
1595
318
  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
318
  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
318
  if (object_init_ex(rval, ce) == FAILURE) {
1608
0
    zend_string_release_ex(class_name, 0);
1609
0
    return 0;
1610
0
  }
1611
1612
318
  if (incomplete_class) {
1613
30
    php_store_class_name(rval, class_name);
1614
30
  }
1615
318
  zend_string_release_ex(class_name, 0);
1616
1617
318
  return object_common(UNSERIALIZE_PASSTHRU, elements, has_unserialize);
1618
318
}
1619
0
#line 1620 "ext/standard/var_unserializer.c"
1620
51
yy80:
1621
51
  ++YYCURSOR;
1622
51
#line 1349 "ext/standard/var_unserializer.re"
1623
51
  {
1624
51
  if (!var_hash) return 0;
1625
1626
51
  size_t len = parse_uiv(start + 2);
1627
51
  size_t maxlen = max - YYCURSOR;
1628
51
  if (maxlen < len || len == 0) {
1629
3
    *p = start + 2;
1630
3
    return 0;
1631
3
  }
1632
1633
48
  char *str = (char *) YYCURSOR;
1634
48
  YYCURSOR += len;
1635
1636
48
  if (*(YYCURSOR) != '"') {
1637
3
    *p = YYCURSOR;
1638
3
    return 0;
1639
3
  }
1640
45
  if (*(YYCURSOR+1) != ';') {
1641
3
    *p = YYCURSOR+1;
1642
3
    return 0;
1643
3
  }
1644
1645
42
  char *colon_ptr = memchr(str, ':', len);
1646
42
  if (colon_ptr == NULL) {
1647
3
    php_error_docref(NULL, E_WARNING, "Invalid enum name '%.*s' (missing colon)", (int) len, str);
1648
3
    return 0;
1649
3
  }
1650
39
  size_t colon_pos = colon_ptr - str;
1651
1652
39
  zend_string *enum_name = zend_string_init(str, colon_pos, 0);
1653
39
  zend_string *case_name = zend_string_init(&str[colon_pos + 1], len - colon_pos - 1, 0);
1654
1655
39
  if (!zend_is_valid_class_name(enum_name)) {
1656
0
    goto fail;
1657
0
  }
1658
1659
39
  zend_class_entry *ce = zend_lookup_class(enum_name);
1660
39
  if (!ce) {
1661
3
    php_error_docref(NULL, E_WARNING, "Class '%s' not found", ZSTR_VAL(enum_name));
1662
3
    goto fail;
1663
3
  }
1664
36
  if (!(ce->ce_flags & ZEND_ACC_ENUM)) {
1665
3
    php_error_docref(NULL, E_WARNING, "Class '%s' is not an enum", ZSTR_VAL(enum_name));
1666
3
    goto fail;
1667
3
  }
1668
1669
33
  YYCURSOR += 2;
1670
33
  *p = YYCURSOR;
1671
1672
33
  zend_class_constant *c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), case_name);
1673
33
  if (!c) {
1674
3
    php_error_docref(NULL, E_WARNING, "Undefined constant %s::%s", ZSTR_VAL(enum_name), ZSTR_VAL(case_name));
1675
3
    goto fail;
1676
3
  }
1677
1678
30
  if (!(ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE)) {
1679
3
    php_error_docref(NULL, E_WARNING, "%s::%s is not an enum case", ZSTR_VAL(enum_name), ZSTR_VAL(case_name));
1680
3
    goto fail;
1681
3
  }
1682
1683
27
  zend_string_release_ex(enum_name, 0);
1684
27
  zend_string_release_ex(case_name, 0);
1685
1686
27
  zval *value = &c->value;
1687
27
  if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
1688
9
    if (zval_update_constant_ex(value, c->ce) == FAILURE) {
1689
0
      return 0;
1690
0
    }
1691
9
  }
1692
27
  ZEND_ASSERT(Z_TYPE_P(value) == IS_OBJECT);
1693
27
  ZVAL_COPY(rval, value);
1694
1695
27
  return 1;
1696
1697
12
fail:
1698
12
  zend_string_release_ex(enum_name, 0);
1699
12
  zend_string_release_ex(case_name, 0);
1700
12
  return 0;
1701
27
}
1702
0
#line 1703 "ext/standard/var_unserializer.c"
1703
0
yy82:
1704
0
  ++YYCURSOR;
1705
0
#line 1059 "ext/standard/var_unserializer.re"
1706
0
  {
1707
0
  size_t len, maxlen;
1708
0
  zend_string *str;
1709
1710
0
  len = parse_uiv(start + 2);
1711
0
  maxlen = max - YYCURSOR;
1712
0
  if (maxlen < len) {
1713
0
    *p = start + 2;
1714
0
    return 0;
1715
0
  }
1716
1717
0
  if ((str = unserialize_str(&YYCURSOR, len, maxlen)) == NULL) {
1718
0
    return 0;
1719
0
  }
1720
1721
0
  if (*(YYCURSOR) != '"') {
1722
0
    zend_string_efree(str);
1723
0
    *p = YYCURSOR;
1724
0
    return 0;
1725
0
  }
1726
1727
0
  if (*(YYCURSOR + 1) != ';') {
1728
0
    efree(str);
1729
0
    *p = YYCURSOR + 1;
1730
0
    return 0;
1731
0
  }
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
0
}
1742
0
#line 1743 "ext/standard/var_unserializer.c"
1743
7.74k
yy84:
1744
7.74k
  ++YYCURSOR;
1745
7.74k
#line 1096 "ext/standard/var_unserializer.re"
1746
7.74k
  {
1747
7.74k
  zend_long elements = parse_iv(start + 2);
1748
  /* use iv() not uiv() in order to check data range */
1749
7.74k
  *p = YYCURSOR;
1750
7.74k
    if (!var_hash) return 0;
1751
1752
7.74k
  if (elements < 0 || elements >= HT_MAX_SIZE || IS_FAKE_ELEM_COUNT(elements, max - YYCURSOR)) {
1753
0
    return 0;
1754
0
  }
1755
1756
7.74k
  if (elements) {
1757
2.07k
    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
2.07k
    zend_hash_real_init_mixed(Z_ARRVAL_P(rval));
1761
5.67k
  } else {
1762
5.67k
    ZVAL_EMPTY_ARRAY(rval);
1763
5.67k
    return finish_nested_data(UNSERIALIZE_PASSTHRU);
1764
5.67k
  }
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
7.74k
  HT_ALLOW_COW_VIOLATION(Z_ARRVAL_P(rval));
1771
1772
2.07k
  if (!process_nested_array_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements)) {
1773
21
    return 0;
1774
21
  }
1775
1776
2.05k
  return finish_nested_data(UNSERIALIZE_PASSTHRU);
1777
2.07k
}
1778
0
#line 1779 "ext/standard/var_unserializer.c"
1779
0
yy86:
1780
0
  yych = *++YYCURSOR;
1781
0
  if (yych <= '/') goto yy18;
1782
0
  if (yych >= ':') goto yy18;
1783
0
yy87:
1784
0
  ++YYCURSOR;
1785
0
  if (YYLIMIT <= YYCURSOR) YYFILL(1);
1786
0
  yych = *YYCURSOR;
1787
0
  if (yych <= '/') goto yy18;
1788
0
  if (yych <= '9') goto yy87;
1789
0
  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
10.0k
yy90:
1796
10.0k
  ++YYCURSOR;
1797
10.0k
#line 1022 "ext/standard/var_unserializer.re"
1798
10.0k
  {
1799
10.0k
  size_t len, maxlen;
1800
10.0k
  char *str;
1801
1802
10.0k
  len = parse_uiv(start + 2);
1803
10.0k
  maxlen = max - YYCURSOR;
1804
10.0k
  if (maxlen < len) {
1805
3
    *p = start + 2;
1806
3
    return 0;
1807
3
  }
1808
1809
10.0k
  str = (char*)YYCURSOR;
1810
1811
10.0k
  YYCURSOR += len;
1812
1813
10.0k
  if (*(YYCURSOR) != '"') {
1814
6
    *p = YYCURSOR;
1815
6
    return 0;
1816
6
  }
1817
1818
10.0k
  if (*(YYCURSOR + 1) != ';') {
1819
3
    *p = YYCURSOR + 1;
1820
3
    return 0;
1821
3
  }
1822
1823
10.0k
  YYCURSOR += 2;
1824
10.0k
  *p = YYCURSOR;
1825
1826
10.0k
  if (!var_hash) {
1827
    /* Array or object key unserialization */
1828
7.96k
    ZVAL_STR(rval, zend_string_init_existing_interned(str, len, 0));
1829
7.96k
  } else {
1830
2.06k
    ZVAL_STRINGL_FAST(rval, str, len);
1831
2.06k
  }
1832
10.0k
  return 1;
1833
10.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
10.0k
}
1853
10.0k
#line 1854 "ext/standard/var_unserializer.c"
1854
10.0k
}
1855
0
#line 1437 "ext/standard/var_unserializer.re"
1856
1857
1858
0
  return 0;
1859
10.0k
}