Coverage Report

Created: 2026-01-18 06:49

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