Coverage Report

Created: 2026-06-13 07:01

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