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
11.6k
#define VAR_ENTRIES_MAX 1018     /* 1024 - offsetof(php_unserialize_data, entries) / sizeof(void*) */
27
128
#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
206
#define VAR_WAKEUP_FLAG 1
33
138
#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
5.46k
  ((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
432
PHPAPI php_unserialize_data_t php_var_unserialize_init(void) {
63
432
  php_unserialize_data_t d;
64
  /* fprintf(stderr, "UNSERIALIZE_INIT    == lock: %u, level: %u\n", BG(serialize_lock), BG(unserialize).level); */
65
432
  if (BG(serialize_lock) || !BG(unserialize).level) {
66
416
    d = emalloc(sizeof(struct php_unserialize_data));
67
416
    d->last = &d->entries;
68
416
    d->first_dtor = d->last_dtor = NULL;
69
416
    d->allowed_classes = NULL;
70
416
    d->ref_props = NULL;
71
416
    d->cur_depth = 0;
72
416
    d->max_depth = BG(unserialize_max_depth);
73
416
    d->entries.used_slots = 0;
74
416
    d->entries.next = NULL;
75
416
    if (!BG(serialize_lock)) {
76
416
      BG(unserialize).data = d;
77
416
      BG(unserialize).level = 1;
78
416
    }
79
416
  } else {
80
16
    d = BG(unserialize).data;
81
16
    ++BG(unserialize).level;
82
16
  }
83
432
  return d;
84
432
}
85
86
432
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
432
  if (BG(serialize_lock) || BG(unserialize).level == 1) {
89
416
    var_destroy(&d);
90
416
    efree(d);
91
416
  }
92
432
  if (!BG(serialize_lock) && !--BG(unserialize).level) {
93
416
    BG(unserialize).data = NULL;
94
416
  }
95
432
}
96
97
416
PHPAPI HashTable *php_var_unserialize_get_allowed_classes(php_unserialize_data_t d) {
98
416
  return d->allowed_classes;
99
416
}
100
416
PHPAPI void php_var_unserialize_set_allowed_classes(php_unserialize_data_t d, HashTable *classes) {
101
416
  d->allowed_classes = classes;
102
416
}
103
104
416
PHPAPI void php_var_unserialize_set_max_depth(php_unserialize_data_t d, zend_long max_depth) {
105
416
  d->max_depth = max_depth;
106
416
}
107
416
PHPAPI zend_long php_var_unserialize_get_max_depth(php_unserialize_data_t d) {
108
416
  return d->max_depth;
109
416
}
110
111
416
PHPAPI void php_var_unserialize_set_cur_depth(php_unserialize_data_t d, zend_long cur_depth) {
112
416
  d->cur_depth = cur_depth;
113
416
}
114
416
PHPAPI zend_long php_var_unserialize_get_cur_depth(php_unserialize_data_t d) {
115
416
  return d->cur_depth;
116
416
}
117
118
static inline void var_push(php_unserialize_data_t *var_hashx, zval *rval)
119
9.87k
{
120
9.87k
  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
9.87k
  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
9.87k
  var_hash->data[var_hash->used_slots++] = rval;
135
9.87k
}
136
137
PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval *rval)
138
16
{
139
16
  if (Z_REFCOUNTED_P(rval)) {
140
16
    zval *tmp_var = var_tmp_var(var_hashx);
141
16
    if (!tmp_var) {
142
0
      return;
143
0
    }
144
16
    ZVAL_COPY(tmp_var, rval);
145
16
  }
146
16
}
147
148
static zend_never_inline void var_push_dtor_value(php_unserialize_data_t *var_hashx, zval *rval)
149
74
{
150
74
  if (Z_REFCOUNTED_P(rval)) {
151
72
    zval *tmp_var = var_tmp_var(var_hashx);
152
72
    if (!tmp_var) {
153
0
      return;
154
0
    }
155
72
    ZVAL_COPY_VALUE(tmp_var, rval);
156
72
  }
157
74
}
158
159
static zend_always_inline zval *tmp_var(php_unserialize_data_t *var_hashx, zend_long num)
160
166
{
161
166
    var_dtor_entries *var_hash;
162
166
  zend_long used_slots;
163
164
166
    if (!var_hashx || !*var_hashx || num < 1) {
165
0
        return NULL;
166
0
    }
167
168
166
    var_hash = (*var_hashx)->last_dtor;
169
166
    if (!var_hash || var_hash->used_slots + num > VAR_DTOR_ENTRIES_MAX) {
170
38
        var_hash = emalloc(sizeof(var_dtor_entries));
171
38
        var_hash->used_slots = 0;
172
38
        var_hash->next = 0;
173
174
38
        if (!(*var_hashx)->first_dtor) {
175
38
            (*var_hashx)->first_dtor = var_hash;
176
38
        } else {
177
0
            (*var_hashx)->last_dtor->next = var_hash;
178
0
        }
179
180
38
        (*var_hashx)->last_dtor = var_hash;
181
38
    }
182
336
  for (used_slots = var_hash->used_slots; var_hash->used_slots < used_slots + num; var_hash->used_slots++) {
183
170
    ZVAL_UNDEF(&var_hash->data[var_hash->used_slots]);
184
170
    Z_EXTRA(var_hash->data[var_hash->used_slots]) = 0;
185
170
  }
186
166
    return &var_hash->data[used_slots];
187
166
}
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
889
{
215
889
  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
889
  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
889
  if (!var_hash) return NULL;
226
227
889
  if (id < 0 || id >= var_hash->used_slots) return NULL;
228
229
889
  return var_hash->data[id];
230
889
}
231
232
PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
233
416
{
234
416
  void *next;
235
416
  zend_long i;
236
416
  var_entries *var_hash = (*var_hashx)->entries.next;
237
416
  var_dtor_entries *var_dtor_hash = (*var_hashx)->first_dtor;
238
416
  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
416
  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
454
  while (var_dtor_hash) {
251
208
    for (i = 0; i < var_dtor_hash->used_slots; i++) {
252
170
      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
170
      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
134
      } else if (Z_EXTRA_P(zv) == VAR_UNSERIALIZE_FLAG) {
291
        /* Perform delayed __unserialize calls */
292
4
        if (!delayed_call_failed) {
293
4
          zval param;
294
4
          ZVAL_COPY(&param, &var_dtor_hash->data[i + 1]);
295
296
4
          BG(serialize_lock)++;
297
4
          zend_call_known_instance_method_with_1_params(
298
4
            Z_OBJCE_P(zv)->__unserialize, Z_OBJ_P(zv), NULL, &param);
299
4
          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
4
          BG(serialize_lock)--;
304
4
          zval_ptr_dtor(&param);
305
4
        } else {
306
0
          GC_ADD_FLAGS(Z_OBJ_P(zv), IS_OBJ_DESTRUCTOR_CALLED);
307
0
        }
308
4
      }
309
310
170
      i_zval_ptr_dtor(zv);
311
170
    }
312
38
    next = var_dtor_hash->next;
313
38
    efree_size(var_dtor_hash, sizeof(var_dtor_entries));
314
38
    var_dtor_hash = next;
315
38
  }
316
317
416
  if ((*var_hashx)->ref_props) {
318
46
    zend_hash_destroy((*var_hashx)->ref_props);
319
46
    FREE_HASHTABLE((*var_hashx)->ref_props);
320
46
  }
321
416
}
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
127
{
366
127
  HashTable *classes = (*var_hashx)->allowed_classes;
367
368
127
  if(classes == NULL) {
369
127
    return 1;
370
127
  }
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
190
#define YYFILL(n) do { } while (0)
379
21.0k
#define YYCTYPE unsigned char
380
303k
#define YYCURSOR cursor
381
75.2k
#define YYLIMIT limit
382
20.8k
#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
12.5k
{
392
12.5k
  zend_ulong result = 0;
393
12.5k
  zend_ulong neg = 0;
394
12.5k
  const unsigned char *start;
395
396
12.5k
  if (*p == '-') {
397
199
    neg = 1;
398
199
    p++;
399
12.3k
  } else if (UNEXPECTED(*p == '+')) {
400
0
    p++;
401
0
  }
402
403
18.6k
  while (UNEXPECTED(*p == '0')) {
404
6.05k
    p++;
405
6.05k
  }
406
407
12.5k
  start = p;
408
409
25.8k
  while (*p >= '0' && *p <= '9') {
410
13.2k
    result = result * 10 + ((zend_ulong)(*p) - '0');
411
13.2k
    p++;
412
13.2k
  }
413
414
12.5k
  if (q) {
415
235
    *q = p;
416
235
  }
417
418
  /* number too long or overflow */
419
12.5k
  if (UNEXPECTED(p - start > MAX_LENGTH_OF_LONG - 1)
420
12.5k
   || (SIZEOF_ZEND_LONG == 4
421
0
    && UNEXPECTED(p - start == MAX_LENGTH_OF_LONG - 1)
422
0
    && UNEXPECTED(*start > '2'))
423
12.5k
   || UNEXPECTED(result > ZEND_LONG_MAX + neg)) {
424
0
    php_error_docref(NULL, E_WARNING, "Numerical result out of range");
425
0
    return (!neg) ? ZEND_LONG_MAX : ZEND_LONG_MIN;
426
0
  }
427
428
12.5k
  return (zend_long) ((!neg) ? result : -result);
429
12.5k
}
430
431
static inline zend_long parse_iv(const unsigned char *p)
432
12.3k
{
433
12.3k
  return parse_iv2(p, NULL);
434
12.3k
}
435
436
/* no need to check for length - re2c already did */
437
static inline size_t parse_uiv(const unsigned char *p)
438
8.20k
{
439
8.20k
  unsigned char cursor;
440
8.20k
  size_t result = 0;
441
442
18.2k
  while (1) {
443
18.2k
    cursor = *p;
444
18.2k
    if (cursor >= '0' && cursor <= '9') {
445
10.0k
      result = result * 10 + (size_t)(cursor - (unsigned char)'0');
446
10.0k
    } else {
447
8.20k
      break;
448
8.20k
    }
449
10.0k
    p++;
450
10.0k
  }
451
8.20k
  return result;
452
8.20k
}
453
454
#define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash
455
7.22k
#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
957
{
461
957
  if (var_hash) {
462
957
    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
957
    (*var_hash)->cur_depth++;
471
957
  }
472
473
10.8k
  while (elements-- > 0) {
474
9.87k
    zval key, *data;
475
9.87k
    zend_ulong idx;
476
477
9.87k
    ZVAL_UNDEF(&key);
478
479
9.87k
    if (!php_var_unserialize_internal(&key, p, max, NULL)) {
480
6
      zval_ptr_dtor(&key);
481
6
      goto failure;
482
6
    }
483
484
9.87k
    if (Z_TYPE(key) == IS_LONG) {
485
3.94k
      idx = Z_LVAL(key);
486
3.94k
numeric_key:
487
3.94k
      data = zend_hash_index_lookup(ht, idx);
488
3.94k
      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
5.92k
    } else if (Z_TYPE(key) == IS_STRING) {
493
5.92k
      if (UNEXPECTED(ZEND_HANDLE_NUMERIC(Z_STR(key), idx))) {
494
0
        zval_ptr_dtor_str(&key);
495
0
        goto numeric_key;
496
0
      }
497
5.92k
      data = zend_hash_lookup(ht, Z_STR(key));
498
5.92k
      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
5.92k
      zval_ptr_dtor_str(&key);
503
5.92k
    } else {
504
0
      zval_ptr_dtor(&key);
505
0
      goto failure;
506
0
    }
507
508
9.87k
    if (!php_var_unserialize_internal(data, p, max, var_hash)) {
509
14
      goto failure;
510
14
    }
511
512
9.85k
    if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
513
0
      (*p)--;
514
0
      goto failure;
515
0
    }
516
9.85k
  }
517
518
937
  if (var_hash) {
519
937
    (*var_hash)->cur_depth--;
520
937
  }
521
937
  return 1;
522
523
20
failure:
524
20
  if (var_hash) {
525
20
    (*var_hash)->cur_depth--;
526
20
  }
527
20
  return 0;
528
957
}
529
530
static int is_property_visibility_changed(zend_class_entry *ce, zval *key)
531
93
{
532
93
  if (zend_hash_num_elements(&ce->properties_info) > 0) {
533
20
    zend_property_info *existing_propinfo = NULL;
534
20
    const char *unmangled_class = NULL;
535
20
    const char *unmangled_prop;
536
20
    size_t unmangled_prop_len;
537
538
20
    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
20
    if (unmangled_class == NULL) {
544
20
      existing_propinfo = zend_hash_find_ptr(&ce->properties_info, Z_STR_P(key));
545
20
    } else {
546
0
      if (!strcmp(unmangled_class, "*")
547
0
       || !strcasecmp(unmangled_class, ZSTR_VAL(ce->name))) {
548
0
        existing_propinfo = zend_hash_str_find_ptr(
549
0
          &ce->properties_info, unmangled_prop, unmangled_prop_len);
550
0
      }
551
0
    }
552
553
20
    if (existing_propinfo != NULL) {
554
2
      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
2
      } else {
559
2
        php_error_docref(NULL, E_WARNING,
560
2
          "Cannot unserialize value for virtual property %s::$%s",
561
2
          ZSTR_VAL(existing_propinfo->ce->name), Z_STRVAL_P(key));
562
2
        zval_ptr_dtor_str(key);
563
2
        return -1;
564
2
      }
565
2
    }
566
20
  }
567
91
  return 0;
568
93
}
569
570
571
static zend_always_inline int process_nested_object_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, zend_object *obj)
572
189
{
573
189
  if (var_hash) {
574
189
    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
189
    (*var_hash)->cur_depth++;
583
189
  }
584
585
550
  while (elements-- > 0) {
586
401
    zval key, *data;
587
401
    zend_property_info *info = NULL;
588
589
401
    ZVAL_UNDEF(&key);
590
591
401
    if (!php_var_unserialize_internal(&key, p, max, NULL)) {
592
4
      zval_ptr_dtor(&key);
593
4
      goto failure;
594
4
    }
595
596
397
    if (EXPECTED(Z_TYPE(key) == IS_STRING)) {
597
397
string_key:
598
397
      data = zend_hash_find(ht, Z_STR(key));
599
397
      if (data != NULL) {
600
306
        if (Z_TYPE_P(data) == IS_INDIRECT) {
601
304
declared_property:
602
          /* This is a property with a declaration */
603
304
          data = Z_INDIRECT_P(data);
604
304
          info = zend_get_typed_property_info_for_slot(obj, data);
605
304
          if (info) {
606
208
            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
208
            if ((*var_hash)->ref_props) {
612
              /* Remove old entry from ref_props table, if it exists. */
613
162
              zend_hash_index_del(
614
162
                (*var_hash)->ref_props, (uintptr_t) data);
615
162
            }
616
208
          }
617
          /* We may override default property value, but they are usually immutable */
618
304
          if (Z_REFCOUNTED_P(data)) {
619
72
            var_push_dtor_value(var_hash, data);
620
72
          }
621
304
          ZVAL_NULL(data);
622
304
        } else {
623
          /* Unusual override of dynamic property */
624
2
          int ret = is_property_visibility_changed(obj->ce, &key);
625
626
2
          if (ret > 0) {
627
0
            goto second_try;
628
2
          } else if (!ret) {
629
2
            var_push_dtor_value(var_hash, data);
630
2
            ZVAL_NULL(data);
631
2
          } else if (ret < 0) {
632
0
            goto failure;
633
0
          }
634
2
        }
635
306
      } else {
636
91
        int ret = is_property_visibility_changed(obj->ce, &key);
637
638
91
        if (EXPECTED(!ret)) {
639
89
          if (UNEXPECTED(obj->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) {
640
2
            zend_throw_error(NULL, "Cannot create dynamic property %s::$%s",
641
2
              ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key)));
642
2
            zval_ptr_dtor_str(&key);
643
2
            goto failure;
644
87
          } else if (!(obj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) {
645
12
            zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated",
646
12
              ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key)));
647
12
            if (EG(exception)) {
648
0
              zval_ptr_dtor_str(&key);
649
0
              goto failure;
650
0
            }
651
12
          }
652
653
87
          data = zend_hash_add_new(ht, Z_STR(key), &EG(uninitialized_zval));
654
87
        } else if (ret < 0) {
655
2
          goto failure;
656
2
        } 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
91
      }
667
393
      zval_ptr_dtor_str(&key);
668
393
    } else if (Z_TYPE(key) == IS_LONG) {
669
      /* object properties should include no integers */
670
30
      convert_to_string(&key);
671
30
      goto string_key;
672
30
    } else {
673
0
      zval_ptr_dtor(&key);
674
0
      goto failure;
675
0
    }
676
677
393
    if (!php_var_unserialize_internal(data, p, max, var_hash)) {
678
30
      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
30
      goto failure;
684
30
    }
685
686
363
    if (UNEXPECTED(info)) {
687
208
      if (!zend_verify_prop_assignable_by_ref(info, data, /* strict */ 1)) {
688
2
        zval_ptr_dtor(data);
689
2
        ZVAL_UNDEF(data);
690
2
        goto failure;
691
2
      }
692
693
206
      if (Z_ISREF_P(data)) {
694
0
        ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(data), info);
695
206
      } 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
206
        if (!(*var_hash)->ref_props) {
699
46
          (*var_hash)->ref_props = emalloc(sizeof(HashTable));
700
46
          zend_hash_init((*var_hash)->ref_props, 8, NULL, NULL, 0);
701
46
        }
702
206
        zend_hash_index_update_ptr(
703
206
          (*var_hash)->ref_props, (uintptr_t) data, info);
704
206
      }
705
206
    }
706
707
361
    if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
708
0
      (*p)--;
709
0
      goto failure;
710
0
    }
711
361
  }
712
713
149
  if (var_hash) {
714
149
    (*var_hash)->cur_depth--;
715
149
  }
716
149
  return 1;
717
718
40
failure:
719
40
  if (var_hash) {
720
40
    (*var_hash)->cur_depth--;
721
40
  }
722
40
  return 0;
723
189
}
724
725
static inline int finish_nested_data(UNSERIALIZE_PARAMETER)
726
5.39k
{
727
5.39k
  if (*p >= max || **p != '}') {
728
2
    return 0;
729
2
  }
730
731
5.39k
  (*p)++;
732
5.39k
  return 1;
733
5.39k
}
734
735
static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
736
26
{
737
26
  zend_long datalen;
738
739
26
  datalen = parse_iv2((*p) + 2, p);
740
741
26
  if (max - (*p) < 2) {
742
0
    return 0;
743
0
  }
744
745
26
  if ((*p)[0] != ':') {
746
2
    return 0;
747
2
  }
748
749
24
  if ((*p)[1] != '{') {
750
2
    (*p) += 1;
751
2
    return 0;
752
2
  }
753
754
22
  (*p) += 2;
755
756
22
  if (datalen < 0 || (max - (*p)) <= datalen) {
757
2
    zend_error(E_WARNING, "Insufficient data for unserializing - " ZEND_LONG_FMT " required, " ZEND_LONG_FMT " present", datalen, (zend_long)(max - (*p)));
758
2
    return 0;
759
2
  }
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
20
  if ((*p)[datalen] != '}') {
765
0
    (*p) += datalen;
766
0
    return 0;
767
0
  }
768
769
20
  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
20
  } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash) != SUCCESS) {
773
10
    return 0;
774
10
  }
775
776
10
  (*p) += datalen + 1; /* +1 for '}' */
777
10
  return 1;
778
20
}
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
203
{
785
203
  HashTable *ht;
786
203
  bool has_wakeup;
787
788
203
  if (has_unserialize) {
789
14
    zval ary, *tmp;
790
791
14
    if (elements >= HT_MAX_SIZE) {
792
0
      return 0;
793
0
    }
794
795
14
    array_init_size(&ary, elements);
796
    /* Avoid reallocation due to packed -> mixed conversion. */
797
14
    zend_hash_real_init_mixed(Z_ARRVAL(ary));
798
14
    if (!process_nested_array_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL(ary), elements)) {
799
10
      ZVAL_DEREF(rval);
800
10
      GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED);
801
10
      zval_ptr_dtor(&ary);
802
10
      return 0;
803
10
    }
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
4
    ZVAL_DEREF(rval);
808
4
    tmp = tmp_var(var_hash, 2);
809
4
    ZVAL_COPY(tmp, rval);
810
4
    Z_EXTRA_P(tmp) = VAR_UNSERIALIZE_FLAG;
811
4
    tmp++;
812
4
    ZVAL_COPY_VALUE(tmp, &ary);
813
814
4
    return finish_nested_data(UNSERIALIZE_PASSTHRU);
815
14
  }
816
817
189
  has_wakeup = Z_OBJCE_P(rval) != PHP_IC_ENTRY
818
173
    && zend_hash_exists(&Z_OBJCE_P(rval)->function_table, ZSTR_KNOWN(ZEND_STR_WAKEUP));
819
820
189
  ht = Z_OBJPROP_P(rval);
821
189
  if (elements >= (zend_long)(HT_MAX_SIZE - zend_hash_num_elements(ht))) {
822
0
    return 0;
823
0
  }
824
825
189
  zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, HT_IS_PACKED(ht));
826
189
  if (!process_nested_object_data(UNSERIALIZE_PASSTHRU, ht, elements, Z_OBJ_P(rval))) {
827
40
    if (has_wakeup) {
828
8
      ZVAL_DEREF(rval);
829
8
      GC_ADD_FLAGS(Z_OBJ_P(rval), IS_OBJ_DESTRUCTOR_CALLED);
830
8
    }
831
40
    return 0;
832
40
  }
833
834
149
  ZVAL_DEREF(rval);
835
149
  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
149
  return finish_nested_data(UNSERIALIZE_PASSTHRU);
843
189
}
844
#ifdef PHP_WIN32
845
# pragma optimize("", on)
846
#endif
847
848
PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
849
454
{
850
454
  var_entries *orig_var_entries = (*var_hash)->last;
851
454
  zend_long orig_used_slots = orig_var_entries ? orig_var_entries->used_slots : 0;
852
454
  int result;
853
854
454
  result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU);
855
856
454
  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
124
    var_entries *e = orig_var_entries;
861
124
    zend_long s = orig_used_slots;
862
248
    while (e) {
863
340
      for (; s < e->used_slots; s++) {
864
216
        e->data[s] = NULL;
865
216
      }
866
867
124
      e = e->next;
868
124
      s = 0;
869
124
    }
870
124
  }
871
872
454
  return result;
873
454
}
874
875
static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER)
876
21.0k
{
877
21.0k
  const unsigned char *cursor, *limit, *marker, *start;
878
21.0k
  zval *rval_ref;
879
880
21.0k
  limit = max;
881
21.0k
  cursor = *p;
882
883
21.0k
  if (YYCURSOR >= YYLIMIT) {
884
0
    return 0;
885
0
  }
886
887
21.0k
  if (var_hash && (*p)[0] != 'R') {
888
9.87k
    var_push(var_hash, rval);
889
9.87k
  }
890
891
21.0k
  start = cursor;
892
893
894
21.0k
#line 895 "ext/standard/var_unserializer.c"
895
21.0k
{
896
21.0k
  YYCTYPE yych;
897
21.0k
  static const unsigned char yybm[] = {
898
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
899
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
900
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
901
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
902
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
903
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
904
21.0k
    128, 128, 128, 128, 128, 128, 128, 128, 
905
21.0k
    128, 128,   0,   0,   0,   0,   0,   0, 
906
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
907
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
908
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
909
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
910
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
911
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
912
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
913
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
914
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
915
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
916
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
917
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
918
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
919
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
920
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
921
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
922
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
923
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
924
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
925
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
926
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
927
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
928
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
929
21.0k
      0,   0,   0,   0,   0,   0,   0,   0, 
930
21.0k
  };
931
21.0k
  if ((YYLIMIT - YYCURSOR) < 7) YYFILL(7);
932
21.0k
  yych = *YYCURSOR;
933
21.0k
  switch (yych) {
934
34
  case 'C':
935
263
  case 'O': goto yy4;
936
54
  case 'E': goto yy5;
937
203
  case 'N': goto yy6;
938
846
  case 'R': goto yy7;
939
0
  case 'S': goto yy8;
940
5.26k
  case 'a': goto yy9;
941
0
  case 'b': goto yy10;
942
212
  case 'd': goto yy11;
943
7.07k
  case 'i': goto yy12;
944
49
  case 'r': goto yy13;
945
7.02k
  case 's': goto yy14;
946
0
  case '}': goto yy15;
947
4
  default:  goto yy2;
948
21.0k
  }
949
4
yy2:
950
4
  ++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
263
yy4:
956
263
  yych = *(YYMARKER = ++YYCURSOR);
957
263
  if (yych == ':') goto yy17;
958
2
  goto yy3;
959
54
yy5:
960
54
  yych = *(YYMARKER = ++YYCURSOR);
961
54
  if (yych == ':') goto yy19;
962
2
  goto yy3;
963
203
yy6:
964
203
  yych = *++YYCURSOR;
965
203
  if (yych == ';') goto yy20;
966
0
  goto yy3;
967
846
yy7:
968
846
  yych = *(YYMARKER = ++YYCURSOR);
969
846
  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
5.26k
yy9:
976
5.26k
  yych = *(YYMARKER = ++YYCURSOR);
977
5.26k
  if (yych == ':') goto yy24;
978
2
  goto yy3;
979
2
yy10:
980
0
  yych = *(YYMARKER = ++YYCURSOR);
981
0
  if (yych == ':') goto yy25;
982
0
  goto yy3;
983
212
yy11:
984
212
  yych = *(YYMARKER = ++YYCURSOR);
985
212
  if (yych == ':') goto yy26;
986
0
  goto yy3;
987
7.07k
yy12:
988
7.07k
  yych = *(YYMARKER = ++YYCURSOR);
989
7.07k
  if (yych == ':') goto yy27;
990
2
  goto yy3;
991
49
yy13:
992
49
  yych = *(YYMARKER = ++YYCURSOR);
993
49
  if (yych == ':') goto yy28;
994
2
  goto yy3;
995
7.02k
yy14:
996
7.02k
  yych = *(YYMARKER = ++YYCURSOR);
997
7.02k
  if (yych == ':') goto yy29;
998
2
  goto yy3;
999
2
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
7.02k
}
1007
0
#line 1008 "ext/standard/var_unserializer.c"
1008
261
yy17:
1009
261
  yych = *++YYCURSOR;
1010
261
  if (yybm[0+yych] & 128) {
1011
259
    goto yy30;
1012
259
  }
1013
38
yy18:
1014
38
  YYCURSOR = YYMARKER;
1015
38
  goto yy3;
1016
52
yy19:
1017
52
  yych = *++YYCURSOR;
1018
52
  if (yych <= '/') goto yy18;
1019
48
  if (yych <= '9') goto yy32;
1020
2
  goto yy18;
1021
203
yy20:
1022
203
  ++YYCURSOR;
1023
203
#line 955 "ext/standard/var_unserializer.re"
1024
203
  {
1025
203
  *p = YYCURSOR;
1026
203
  ZVAL_NULL(rval);
1027
203
  return 1;
1028
48
}
1029
0
#line 1030 "ext/standard/var_unserializer.c"
1030
846
yy22:
1031
846
  yych = *++YYCURSOR;
1032
846
  if (yych <= '/') goto yy18;
1033
846
  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
5.26k
yy24:
1041
5.26k
  yych = *++YYCURSOR;
1042
5.26k
  if (yych <= '/') goto yy18;
1043
5.25k
  if (yych <= '9') goto yy38;
1044
2
  goto yy18;
1045
2
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
212
yy26:
1052
212
  yych = *++YYCURSOR;
1053
212
  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
212
  } else {
1063
212
    if (yych <= 'I') {
1064
212
      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
212
  }
1072
7.07k
yy27:
1073
7.07k
  yych = *++YYCURSOR;
1074
7.07k
  if (yych <= ',') {
1075
0
    if (yych == '+') goto yy49;
1076
0
    goto yy18;
1077
7.07k
  } else {
1078
7.07k
    if (yych <= '-') goto yy49;
1079
6.87k
    if (yych <= '/') goto yy18;
1080
6.87k
    if (yych <= '9') goto yy50;
1081
2
    goto yy18;
1082
6.87k
  }
1083
47
yy28:
1084
47
  yych = *++YYCURSOR;
1085
47
  if (yych <= '/') goto yy18;
1086
47
  if (yych <= '9') goto yy52;
1087
0
  goto yy18;
1088
7.02k
yy29:
1089
7.02k
  yych = *++YYCURSOR;
1090
7.02k
  if (yych <= '/') goto yy18;
1091
7.02k
  if (yych <= '9') goto yy54;
1092
0
  goto yy18;
1093
325
yy30:
1094
325
  ++YYCURSOR;
1095
325
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1096
325
  yych = *YYCURSOR;
1097
325
  if (yybm[0+yych] & 128) {
1098
66
    goto yy30;
1099
66
  }
1100
259
  if (yych <= '/') goto yy18;
1101
257
  if (yych <= ':') goto yy56;
1102
2
  goto yy18;
1103
48
yy32:
1104
48
  ++YYCURSOR;
1105
48
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1106
48
  yych = *YYCURSOR;
1107
48
  if (yych <= '/') goto yy18;
1108
46
  if (yych <= '9') goto yy32;
1109
44
  if (yych <= ':') goto yy57;
1110
0
  goto yy18;
1111
1.78k
yy34:
1112
1.78k
  ++YYCURSOR;
1113
1.78k
  if (YYLIMIT <= YYCURSOR) YYFILL(1);
1114
1.78k
  yych = *YYCURSOR;
1115
1.78k
  if (yych <= '/') goto yy18;
1116
1.78k
  if (yych <= '9') goto yy34;
1117
846
  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
5.98k
yy38:
1128
5.98k
  ++YYCURSOR;
1129
5.98k
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1130
5.98k
  yych = *YYCURSOR;
1131
5.98k
  if (yych <= '/') goto yy18;
1132
5.98k
  if (yych <= '9') goto yy38;
1133
5.25k
  if (yych <= ':') goto yy61;
1134
2
  goto yy18;
1135
2
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
212
yy45:
1164
212
  ++YYCURSOR;
1165
212
  if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
1166
212
  yych = *YYCURSOR;
1167
212
  if (yych <= ':') {
1168
212
    if (yych <= '.') {
1169
212
      if (yych <= '-') goto yy18;
1170
212
      goto yy66;
1171
212
    } else {
1172
0
      if (yych <= '/') goto yy18;
1173
0
      if (yych <= '9') goto yy45;
1174
0
      goto yy18;
1175
0
    }
1176
212
  } 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
199
yy49:
1195
199
  yych = *++YYCURSOR;
1196
199
  if (yych <= '/') goto yy18;
1197
199
  if (yych >= ':') goto yy18;
1198
13.1k
yy50:
1199
13.1k
  ++YYCURSOR;
1200
13.1k
  if (YYLIMIT <= YYCURSOR) YYFILL(1);
1201
13.1k
  yych = *YYCURSOR;
1202
13.1k
  if (yych <= '/') goto yy18;
1203
13.1k
  if (yych <= '9') goto yy50;
1204
7.07k
  if (yych == ';') goto yy73;
1205
2
  goto yy18;
1206
49
yy52:
1207
49
  ++YYCURSOR;
1208
49
  if (YYLIMIT <= YYCURSOR) YYFILL(1);
1209
49
  yych = *YYCURSOR;
1210
49
  if (yych <= '/') goto yy18;
1211
49
  if (yych <= '9') goto yy52;
1212
47
  if (yych == ';') goto yy75;
1213
2
  goto yy18;
1214
7.86k
yy54:
1215
7.86k
  ++YYCURSOR;
1216
7.86k
  if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
1217
7.86k
  yych = *YYCURSOR;
1218
7.86k
  if (yych <= '/') goto yy18;
1219
7.86k
  if (yych <= '9') goto yy54;
1220
7.02k
  if (yych <= ':') goto yy77;
1221
2
  goto yy18;
1222
255
yy56:
1223
255
  yych = *++YYCURSOR;
1224
255
  if (yych == '"') goto yy78;
1225
4
  goto yy18;
1226
44
yy57:
1227
44
  yych = *++YYCURSOR;
1228
44
  if (yych == '"') goto yy80;
1229
2
  goto yy18;
1230
846
yy58:
1231
846
  ++YYCURSOR;
1232
846
#line 899 "ext/standard/var_unserializer.re"
1233
846
  {
1234
846
  zend_long id;
1235
1236
846
  *p = YYCURSOR;
1237
846
  if (!var_hash) return 0;
1238
1239
846
  id = parse_uiv(start + 2) - 1;
1240
846
  if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) {
1241
0
    return 0;
1242
0
  }
1243
1244
846
  if (rval_ref == rval || (Z_ISREF_P(rval_ref) && Z_REFVAL_P(rval_ref) == rval)) {
1245
0
    return 0;
1246
0
  }
1247
1248
846
  if (!Z_ISREF_P(rval_ref)) {
1249
578
    zend_property_info *info = NULL;
1250
578
    if ((*var_hash)->ref_props) {
1251
0
      info = zend_hash_index_find_ptr((*var_hash)->ref_props, (uintptr_t) rval_ref);
1252
0
    }
1253
578
    ZVAL_NEW_REF(rval_ref, rval_ref);
1254
578
    if (info) {
1255
0
      ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(rval_ref), info);
1256
0
    }
1257
578
  }
1258
1259
846
  ZVAL_COPY(rval, rval_ref);
1260
1261
846
  return 1;
1262
846
}
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
5.25k
yy61:
1269
5.25k
  yych = *++YYCURSOR;
1270
5.25k
  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
5.25k
}
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
5.25k
}
1289
0
#line 1290 "ext/standard/var_unserializer.c"
1290
3.39k
yy66:
1291
3.39k
  ++YYCURSOR;
1292
3.39k
  if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3);
1293
3.39k
  yych = *YYCURSOR;
1294
3.39k
  if (yych <= ';') {
1295
3.18k
    if (yych <= '/') goto yy18;
1296
3.18k
    if (yych <= '9') goto yy66;
1297
0
    if (yych <= ':') goto yy18;
1298
212
  } else {
1299
212
    if (yych <= 'E') {
1300
212
      if (yych <= 'D') goto yy18;
1301
212
      goto yy70;
1302
212
    } else {
1303
0
      if (yych == 'e') goto yy70;
1304
0
      goto yy18;
1305
0
    }
1306
212
  }
1307
212
yy68:
1308
212
  ++YYCURSOR;
1309
212
#line 1015 "ext/standard/var_unserializer.re"
1310
212
  {
1311
#if SIZEOF_ZEND_LONG == 4
1312
use_double:
1313
#endif
1314
212
  *p = YYCURSOR;
1315
212
  ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL));
1316
212
  return 1;
1317
3.39k
}
1318
0
#line 1319 "ext/standard/var_unserializer.c"
1319
212
yy70:
1320
212
  yych = *++YYCURSOR;
1321
212
  if (yych <= ',') {
1322
212
    if (yych == '+') goto yy86;
1323
0
    goto yy18;
1324
212
  } 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
7.07k
yy73:
1339
7.07k
  ++YYCURSOR;
1340
7.07k
#line 973 "ext/standard/var_unserializer.re"
1341
7.07k
  {
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
7.07k
  *p = YYCURSOR;
1363
7.07k
  ZVAL_LONG(rval, parse_iv(start + 2));
1364
7.07k
  return 1;
1365
0
}
1366
0
#line 1367 "ext/standard/var_unserializer.c"
1367
45
yy75:
1368
45
  ++YYCURSOR;
1369
45
#line 930 "ext/standard/var_unserializer.re"
1370
45
  {
1371
45
  zend_long id;
1372
1373
45
  *p = YYCURSOR;
1374
45
  if (!var_hash) return 0;
1375
1376
45
  id = parse_uiv(start + 2) - 1;
1377
45
  if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) {
1378
2
    return 0;
1379
2
  }
1380
1381
43
  if (rval_ref == rval) {
1382
0
    return 0;
1383
0
  }
1384
1385
43
  ZVAL_DEREF(rval_ref);
1386
43
  if (Z_TYPE_P(rval_ref) != IS_OBJECT) {
1387
0
    return 0;
1388
0
  }
1389
1390
43
  ZVAL_COPY(rval, rval_ref);
1391
1392
43
  return 1;
1393
43
}
1394
0
#line 1395 "ext/standard/var_unserializer.c"
1395
7.02k
yy77:
1396
7.02k
  yych = *++YYCURSOR;
1397
7.02k
  if (yych == '"') goto yy90;
1398
2
  goto yy18;
1399
251
yy78:
1400
251
  ++YYCURSOR;
1401
251
#line 1131 "ext/standard/var_unserializer.re"
1402
251
  {
1403
251
  size_t len, maxlen;
1404
251
  zend_long elements;
1405
251
  char *str;
1406
251
  zend_string *class_name;
1407
251
  zend_class_entry *ce;
1408
251
  bool incomplete_class = 0;
1409
251
  bool custom_object = 0;
1410
251
  bool has_unserialize = 0;
1411
1412
251
  zval user_func;
1413
251
  zval retval;
1414
251
  zval args[1];
1415
1416
251
    if (!var_hash) return 0;
1417
251
  if (*start == 'C') {
1418
30
    custom_object = 1;
1419
30
  }
1420
1421
251
  len = parse_uiv(start + 2);
1422
251
  maxlen = max - YYCURSOR;
1423
251
  if (maxlen < len || len == 0) {
1424
2
    *p = start + 2;
1425
2
    return 0;
1426
2
  }
1427
1428
249
  str = (char*)YYCURSOR;
1429
1430
249
  YYCURSOR += len;
1431
1432
249
  if (*(YYCURSOR) != '"') {
1433
2
    *p = YYCURSOR;
1434
2
    return 0;
1435
2
  }
1436
247
  if (*(YYCURSOR+1) != ':') {
1437
2
    *p = YYCURSOR+1;
1438
2
    return 0;
1439
2
  }
1440
1441
245
  if (len == 0) {
1442
    /* empty class names are not allowed */
1443
0
    return 0;
1444
0
  }
1445
1446
245
  if (str[0] == '\000') {
1447
    /* runtime definition keys are not allowed */
1448
2
    return 0;
1449
2
  }
1450
1451
243
  if (str[0] == '\\') {
1452
    /* class name can't start from namespace separator */
1453
0
    return 0;
1454
0
  }
1455
1456
243
  class_name = zend_string_init_interned(str, len, 0);
1457
1458
243
  do {
1459
243
    zend_string *lc_name;
1460
1461
243
    if (!(*var_hash)->allowed_classes && ZSTR_HAS_CE_CACHE(class_name)) {
1462
225
      ce = ZSTR_GET_CE_CACHE(class_name);
1463
225
      if (ce) {
1464
116
        break;
1465
116
      }
1466
225
    }
1467
1468
127
    lc_name = zend_string_tolower(class_name);
1469
127
    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
127
    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
127
    ce = zend_hash_find_ptr(EG(class_table), lc_name);
1489
127
    if (ce
1490
107
     && (ce->ce_flags & ZEND_ACC_LINKED)
1491
107
     && !(ce->ce_flags & ZEND_ACC_ANON_CLASS)) {
1492
107
      zend_string_release_ex(lc_name, 0);
1493
107
      break;
1494
107
    }
1495
1496
20
    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
20
    BG(serialize_lock)++;
1504
20
    ce = zend_lookup_class_ex(class_name, lc_name, 0);
1505
20
    BG(serialize_lock)--;
1506
20
    zend_string_release_ex(lc_name, 0);
1507
20
    if (EG(exception)) {
1508
0
      zend_string_release_ex(class_name, 0);
1509
0
      return 0;
1510
0
    }
1511
1512
20
    if (ce) {
1513
0
      break;
1514
0
    }
1515
1516
    /* Check for unserialize callback */
1517
20
    if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
1518
20
      incomplete_class = 1;
1519
20
      ce = PHP_IC_ENTRY;
1520
20
      break;
1521
20
    }
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
243
  *p = YYCURSOR;
1551
1552
243
  if (ce->ce_flags & ZEND_ACC_NOT_SERIALIZABLE) {
1553
8
    zend_throw_exception_ex(NULL, 0, "Unserialization of '%s' is not allowed",
1554
8
      ZSTR_VAL(ce->name));
1555
8
    zend_string_release_ex(class_name, 0);
1556
8
    return 0;
1557
8
  }
1558
1559
235
  if (custom_object) {
1560
26
    int ret;
1561
1562
26
    ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
1563
1564
26
    if (ret && incomplete_class) {
1565
0
      php_store_class_name(rval, class_name);
1566
0
    }
1567
26
    zend_string_release_ex(class_name, 0);
1568
26
    return ret;
1569
26
  }
1570
1571
209
  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
209
  elements = parse_iv2(*p + 2, p);
1578
209
  if (elements < 0 || IS_FAKE_ELEM_COUNT(elements, max - YYCURSOR)) {
1579
2
    zend_string_release_ex(class_name, 0);
1580
2
    return 0;
1581
2
  }
1582
1583
207
  YYCURSOR = *p;
1584
1585
207
  if (*(YYCURSOR) != ':') {
1586
2
    zend_string_release_ex(class_name, 0);
1587
2
    return 0;
1588
2
  }
1589
205
  if (*(YYCURSOR+1) != '{') {
1590
2
    *p = YYCURSOR+1;
1591
2
    zend_string_release_ex(class_name, 0);
1592
2
    return 0;
1593
2
  }
1594
1595
203
  *p += 2;
1596
1597
203
  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
203
  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
203
  if (object_init_ex(rval, ce) == FAILURE) {
1610
0
    zend_string_release_ex(class_name, 0);
1611
0
    return 0;
1612
0
  }
1613
1614
203
  if (incomplete_class) {
1615
16
    php_store_class_name(rval, class_name);
1616
16
  }
1617
203
  zend_string_release_ex(class_name, 0);
1618
1619
203
  return object_common(UNSERIALIZE_PASSTHRU, elements, has_unserialize);
1620
203
}
1621
0
#line 1622 "ext/standard/var_unserializer.c"
1622
42
yy80:
1623
42
  ++YYCURSOR;
1624
42
#line 1351 "ext/standard/var_unserializer.re"
1625
42
  {
1626
42
  if (!var_hash) return 0;
1627
1628
42
  size_t len = parse_uiv(start + 2);
1629
42
  size_t maxlen = max - YYCURSOR;
1630
42
  if (maxlen < len || len == 0) {
1631
0
    *p = start + 2;
1632
0
    return 0;
1633
0
  }
1634
1635
42
  char *str = (char *) YYCURSOR;
1636
42
  YYCURSOR += len;
1637
1638
42
  if (*(YYCURSOR) != '"') {
1639
4
    *p = YYCURSOR;
1640
4
    return 0;
1641
4
  }
1642
38
  if (*(YYCURSOR+1) != ';') {
1643
0
    *p = YYCURSOR+1;
1644
0
    return 0;
1645
0
  }
1646
1647
38
  char *colon_ptr = memchr(str, ':', len);
1648
38
  if (colon_ptr == NULL) {
1649
4
    php_error_docref(NULL, E_WARNING, "Invalid enum name '%.*s' (missing colon)", (int) len, str);
1650
4
    return 0;
1651
4
  }
1652
34
  size_t colon_pos = colon_ptr - str;
1653
1654
34
  zend_string *enum_name = zend_string_init(str, colon_pos, 0);
1655
34
  zend_string *case_name = zend_string_init(&str[colon_pos + 1], len - colon_pos - 1, 0);
1656
1657
34
  if (!zend_is_valid_class_name(enum_name)) {
1658
2
    goto fail;
1659
2
  }
1660
1661
32
  zend_class_entry *ce = zend_lookup_class(enum_name);
1662
32
  if (!ce) {
1663
2
    php_error_docref(NULL, E_WARNING, "Class '%s' not found", ZSTR_VAL(enum_name));
1664
2
    goto fail;
1665
2
  }
1666
30
  if (!(ce->ce_flags & ZEND_ACC_ENUM)) {
1667
2
    php_error_docref(NULL, E_WARNING, "Class '%s' is not an enum", ZSTR_VAL(enum_name));
1668
2
    goto fail;
1669
2
  }
1670
1671
28
  YYCURSOR += 2;
1672
28
  *p = YYCURSOR;
1673
1674
28
  zend_class_constant *c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), case_name);
1675
28
  if (!c) {
1676
2
    php_error_docref(NULL, E_WARNING, "Undefined constant %s::%s", ZSTR_VAL(enum_name), ZSTR_VAL(case_name));
1677
2
    goto fail;
1678
2
  }
1679
1680
26
  if (!(ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE)) {
1681
2
    php_error_docref(NULL, E_WARNING, "%s::%s is not an enum case", ZSTR_VAL(enum_name), ZSTR_VAL(case_name));
1682
2
    goto fail;
1683
2
  }
1684
1685
24
  zend_string_release_ex(enum_name, 0);
1686
24
  zend_string_release_ex(case_name, 0);
1687
1688
24
  zval *value = &c->value;
1689
24
  if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
1690
12
    if (zval_update_constant_ex(value, c->ce) == FAILURE) {
1691
0
      return 0;
1692
0
    }
1693
12
  }
1694
24
  ZEND_ASSERT(Z_TYPE_P(value) == IS_OBJECT);
1695
24
  ZVAL_COPY(rval, value);
1696
1697
24
  return 1;
1698
1699
10
fail:
1700
10
  zend_string_release_ex(enum_name, 0);
1701
10
  zend_string_release_ex(case_name, 0);
1702
10
  return 0;
1703
24
}
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
5.25k
yy84:
1746
5.25k
  ++YYCURSOR;
1747
5.25k
#line 1098 "ext/standard/var_unserializer.re"
1748
5.25k
  {
1749
5.25k
  zend_long elements = parse_iv(start + 2);
1750
  /* use iv() not uiv() in order to check data range */
1751
5.25k
  *p = YYCURSOR;
1752
5.25k
    if (!var_hash) return 0;
1753
1754
5.25k
  if (elements < 0 || elements >= HT_MAX_SIZE || IS_FAKE_ELEM_COUNT(elements, max - YYCURSOR)) {
1755
2
    return 0;
1756
2
  }
1757
1758
5.25k
  if (elements) {
1759
943
    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
943
    zend_hash_real_init_mixed(Z_ARRVAL_P(rval));
1763
4.30k
  } else {
1764
4.30k
    ZVAL_EMPTY_ARRAY(rval);
1765
4.30k
    return finish_nested_data(UNSERIALIZE_PASSTHRU);
1766
4.30k
  }
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
5.25k
  HT_ALLOW_COW_VIOLATION(Z_ARRVAL_P(rval));
1773
1774
943
  if (!process_nested_array_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements)) {
1775
10
    return 0;
1776
10
  }
1777
1778
933
  return finish_nested_data(UNSERIALIZE_PASSTHRU);
1779
943
}
1780
0
#line 1781 "ext/standard/var_unserializer.c"
1781
212
yy86:
1782
212
  yych = *++YYCURSOR;
1783
212
  if (yych <= '/') goto yy18;
1784
212
  if (yych >= ':') goto yy18;
1785
424
yy87:
1786
424
  ++YYCURSOR;
1787
424
  if (YYLIMIT <= YYCURSOR) YYFILL(1);
1788
424
  yych = *YYCURSOR;
1789
424
  if (yych <= '/') goto yy18;
1790
424
  if (yych <= '9') goto yy87;
1791
212
  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
7.02k
yy90:
1798
7.02k
  ++YYCURSOR;
1799
7.02k
#line 1024 "ext/standard/var_unserializer.re"
1800
7.02k
  {
1801
7.02k
  size_t len, maxlen;
1802
7.02k
  char *str;
1803
1804
7.02k
  len = parse_uiv(start + 2);
1805
7.02k
  maxlen = max - YYCURSOR;
1806
7.02k
  if (maxlen < len) {
1807
0
    *p = start + 2;
1808
0
    return 0;
1809
0
  }
1810
1811
7.02k
  str = (char*)YYCURSOR;
1812
1813
7.02k
  YYCURSOR += len;
1814
1815
7.02k
  if (*(YYCURSOR) != '"') {
1816
2
    *p = YYCURSOR;
1817
2
    return 0;
1818
2
  }
1819
1820
7.02k
  if (*(YYCURSOR + 1) != ';') {
1821
0
    *p = YYCURSOR + 1;
1822
0
    return 0;
1823
0
  }
1824
1825
7.02k
  YYCURSOR += 2;
1826
7.02k
  *p = YYCURSOR;
1827
1828
7.02k
  if (!var_hash) {
1829
    /* Array or object key unserialization */
1830
6.29k
    ZVAL_STR(rval, zend_string_init_existing_interned(str, len, 0));
1831
6.29k
  } else {
1832
728
    ZVAL_STRINGL_FAST(rval, str, len);
1833
728
  }
1834
7.02k
  return 1;
1835
7.02k
}
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
7.02k
}
1855
7.02k
#line 1856 "ext/standard/var_unserializer.c"
1856
7.02k
}
1857
0
#line 1439 "ext/standard/var_unserializer.re"
1858
1859
1860
0
  return 0;
1861
7.02k
}