Coverage Report

Created: 2025-12-14 06:09

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