Coverage Report

Created: 2025-12-14 06:06

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