1/*
2  +----------------------------------------------------------------------+
3  | PHP Version 5                                                        |
4  +----------------------------------------------------------------------+
5  | Copyright (c) 1997-2013 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  | http://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/* $Id$ */
20
21#include "php.h"
22#include "ext/standard/php_var.h"
23#include "php_incomplete_class.h"
24
25/* {{{ reference-handling for unserializer: var_* */
26#define VAR_ENTRIES_MAX 1024
27
28typedef struct {
29    zval *data[VAR_ENTRIES_MAX];
30    long used_slots;
31    void *next;
32} var_entries;
33
34static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval)
35{
36    var_entries *var_hash = (*var_hashx)->last;
37#if 0
38    fprintf(stderr, "var_push(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval));
39#endif
40
41    if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) {
42        var_hash = emalloc(sizeof(var_entries));
43        var_hash->used_slots = 0;
44        var_hash->next = 0;
45
46        if (!(*var_hashx)->first) {
47            (*var_hashx)->first = var_hash;
48        } else {
49            ((var_entries *) (*var_hashx)->last)->next = var_hash;
50        }
51
52        (*var_hashx)->last = var_hash;
53    }
54
55    var_hash->data[var_hash->used_slots++] = *rval;
56}
57
58PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
59{
60    var_entries *var_hash = (*var_hashx)->last_dtor;
61#if 0
62    fprintf(stderr, "var_push_dtor(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval));
63#endif
64
65    if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) {
66        var_hash = emalloc(sizeof(var_entries));
67        var_hash->used_slots = 0;
68        var_hash->next = 0;
69
70        if (!(*var_hashx)->first_dtor) {
71            (*var_hashx)->first_dtor = var_hash;
72        } else {
73            ((var_entries *) (*var_hashx)->last_dtor)->next = var_hash;
74        }
75
76        (*var_hashx)->last_dtor = var_hash;
77    }
78
79    Z_ADDREF_PP(rval);
80    var_hash->data[var_hash->used_slots++] = *rval;
81}
82
83PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **nzval)
84{
85    long i;
86    var_entries *var_hash = (*var_hashx)->first;
87#if 0
88    fprintf(stderr, "var_replace(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(nzval));
89#endif
90
91    while (var_hash) {
92        for (i = 0; i < var_hash->used_slots; i++) {
93            if (var_hash->data[i] == ozval) {
94                var_hash->data[i] = *nzval;
95                /* do not break here */
96            }
97        }
98        var_hash = var_hash->next;
99    }
100}
101
102static int var_access(php_unserialize_data_t *var_hashx, long id, zval ***store)
103{
104    var_entries *var_hash = (*var_hashx)->first;
105#if 0
106    fprintf(stderr, "var_access(%ld): %ld\n", var_hash?var_hash->used_slots:-1L, id);
107#endif
108
109    while (id >= VAR_ENTRIES_MAX && var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) {
110        var_hash = var_hash->next;
111        id -= VAR_ENTRIES_MAX;
112    }
113
114    if (!var_hash) return !SUCCESS;
115
116    if (id < 0 || id >= var_hash->used_slots) return !SUCCESS;
117
118    *store = &var_hash->data[id];
119
120    return SUCCESS;
121}
122
123PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
124{
125    void *next;
126    long i;
127    var_entries *var_hash = (*var_hashx)->first;
128#if 0
129    fprintf(stderr, "var_destroy(%ld)\n", var_hash?var_hash->used_slots:-1L);
130#endif
131
132    while (var_hash) {
133        next = var_hash->next;
134        efree(var_hash);
135        var_hash = next;
136    }
137
138    var_hash = (*var_hashx)->first_dtor;
139
140    while (var_hash) {
141        for (i = 0; i < var_hash->used_slots; i++) {
142            zval_ptr_dtor(&var_hash->data[i]);
143        }
144        next = var_hash->next;
145        efree(var_hash);
146        var_hash = next;
147    }
148}
149
150/* }}} */
151
152static char *unserialize_str(const unsigned char **p, size_t *len, size_t maxlen)
153{
154    size_t i, j;
155    char *str = safe_emalloc(*len, 1, 1);
156    unsigned char *end = *(unsigned char **)p+maxlen;
157
158    if (end < *p) {
159        efree(str);
160        return NULL;
161    }
162
163    for (i = 0; i < *len; i++) {
164        if (*p >= end) {
165            efree(str);
166            return NULL;
167        }
168        if (**p != '\\') {
169            str[i] = (char)**p;
170        } else {
171            unsigned char ch = 0;
172
173            for (j = 0; j < 2; j++) {
174                (*p)++;
175                if (**p >= '0' && **p <= '9') {
176                    ch = (ch << 4) + (**p -'0');
177                } else if (**p >= 'a' && **p <= 'f') {
178                    ch = (ch << 4) + (**p -'a'+10);
179                } else if (**p >= 'A' && **p <= 'F') {
180                    ch = (ch << 4) + (**p -'A'+10);
181                } else {
182                    efree(str);
183                    return NULL;
184                }
185            }
186            str[i] = (char)ch;
187        }
188        (*p)++;
189    }
190    str[i] = 0;
191    *len = i;
192    return str;
193}
194
195#define YYFILL(n) do { } while (0)
196#define YYCTYPE unsigned char
197#define YYCURSOR cursor
198#define YYLIMIT limit
199#define YYMARKER marker
200
201
202/*!re2c
203uiv = [+]? [0-9]+;
204iv = [+-]? [0-9]+;
205nv = [+-]? ([0-9]* "." [0-9]+|[0-9]+ "." [0-9]*);
206nvexp = (iv | nv) [eE] [+-]? iv;
207any = [\000-\377];
208object = [OC];
209*/
210
211
212
213static inline long parse_iv2(const unsigned char *p, const unsigned char **q)
214{
215    char cursor;
216    long result = 0;
217    int neg = 0;
218
219    switch (*p) {
220        case '-':
221            neg++;
222            /* fall-through */
223        case '+':
224            p++;
225    }
226
227    while (1) {
228        cursor = (char)*p;
229        if (cursor >= '0' && cursor <= '9') {
230            result = result * 10 + (size_t)(cursor - (unsigned char)'0');
231        } else {
232            break;
233        }
234        p++;
235    }
236    if (q) *q = p;
237    if (neg) return -result;
238    return result;
239}
240
241static inline long parse_iv(const unsigned char *p)
242{
243    return parse_iv2(p, NULL);
244}
245
246/* no need to check for length - re2c already did */
247static inline size_t parse_uiv(const unsigned char *p)
248{
249    unsigned char cursor;
250    size_t result = 0;
251
252    if (*p == '+') {
253        p++;
254    }
255
256    while (1) {
257        cursor = *p;
258        if (cursor >= '0' && cursor <= '9') {
259            result = result * 10 + (size_t)(cursor - (unsigned char)'0');
260        } else {
261            break;
262        }
263        p++;
264    }
265    return result;
266}
267
268#define UNSERIALIZE_PARAMETER zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC
269#define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC
270
271static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long elements, int objprops)
272{
273    while (elements-- > 0) {
274        zval *key, *data, **old_data;
275
276        ALLOC_INIT_ZVAL(key);
277
278        if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) {
279            zval_dtor(key);
280            FREE_ZVAL(key);
281            return 0;
282        }
283
284        if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) {
285            zval_dtor(key);
286            FREE_ZVAL(key);
287            return 0;
288        }
289
290        ALLOC_INIT_ZVAL(data);
291
292        if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) {
293            zval_dtor(key);
294            FREE_ZVAL(key);
295            zval_dtor(data);
296            FREE_ZVAL(data);
297            return 0;
298        }
299
300        if (!objprops) {
301            switch (Z_TYPE_P(key)) {
302            case IS_LONG:
303                if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)==SUCCESS) {
304                    var_push_dtor(var_hash, old_data);
305                }
306                zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL);
307                break;
308            case IS_STRING:
309                if (zend_symtable_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
310                    var_push_dtor(var_hash, old_data);
311                }
312                zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL);
313                break;
314            }
315        } else {
316            /* object properties should include no integers */
317            convert_to_string(key);
318            zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data,
319                    sizeof data, NULL);
320        }
321
322        zval_dtor(key);
323        FREE_ZVAL(key);
324
325        if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
326            (*p)--;
327            return 0;
328        }
329    }
330
331    return 1;
332}
333
334static inline int finish_nested_data(UNSERIALIZE_PARAMETER)
335{
336    if (*((*p)++) == '}')
337        return 1;
338
339#if SOMETHING_NEW_MIGHT_LEAD_TO_CRASH_ENABLE_IF_YOU_ARE_BRAVE
340    zval_ptr_dtor(rval);
341#endif
342    return 0;
343}
344
345static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
346{
347    long datalen;
348
349    datalen = parse_iv2((*p) + 2, p);
350
351    (*p) += 2;
352
353    if (datalen < 0 || (*p) + datalen >= max) {
354        zend_error(E_WARNING, "Insufficient data for unserializing - %ld required, %ld present", datalen, (long)(max - (*p)));
355        return 0;
356    }
357
358    if (ce->unserialize == NULL) {
359        zend_error(E_WARNING, "Class %s has no unserializer", ce->name);
360        object_init_ex(*rval, ce);
361    } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) != SUCCESS) {
362        return 0;
363    }
364
365    (*p) += datalen;
366
367    return finish_nested_data(UNSERIALIZE_PASSTHRU);
368}
369
370static inline long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
371{
372    long elements;
373
374    elements = parse_iv2((*p) + 2, p);
375
376    (*p) += 2;
377
378    object_init_ex(*rval, ce);
379    return elements;
380}
381
382#ifdef PHP_WIN32
383# pragma optimize("", off)
384#endif
385static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
386{
387    zval *retval_ptr = NULL;
388    zval fname;
389
390    if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) {
391        return 0;
392    }
393
394    if (Z_OBJCE_PP(rval) != PHP_IC_ENTRY &&
395        zend_hash_exists(&Z_OBJCE_PP(rval)->function_table, "__wakeup", sizeof("__wakeup"))) {
396        INIT_PZVAL(&fname);
397        ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1, 0);
398        BG(serialize_lock)++;
399        call_user_function_ex(CG(function_table), rval, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC);
400        BG(serialize_lock)--;
401    }
402
403    if (retval_ptr) {
404        zval_ptr_dtor(&retval_ptr);
405    }
406
407    if (EG(exception)) {
408        return 0;
409    }
410
411    return finish_nested_data(UNSERIALIZE_PASSTHRU);
412
413}
414#ifdef PHP_WIN32
415# pragma optimize("", on)
416#endif
417
418PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
419{
420    const unsigned char *cursor, *limit, *marker, *start;
421    zval **rval_ref;
422
423    limit = max;
424    cursor = *p;
425
426    if (YYCURSOR >= YYLIMIT) {
427        return 0;
428    }
429
430    if (var_hash && cursor[0] != 'R') {
431        var_push(var_hash, rval);
432    }
433
434    start = cursor;
435
436
437
438/*!re2c
439
440"R:" iv ";"     {
441    long id;
442
443    *p = YYCURSOR;
444    if (!var_hash) return 0;
445
446    id = parse_iv(start + 2) - 1;
447    if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) {
448        return 0;
449    }
450
451    if (*rval != NULL) {
452        zval_ptr_dtor(rval);
453    }
454    *rval = *rval_ref;
455    Z_ADDREF_PP(rval);
456    Z_SET_ISREF_PP(rval);
457
458    return 1;
459}
460
461"r:" iv ";"     {
462    long id;
463
464    *p = YYCURSOR;
465    if (!var_hash) return 0;
466
467    id = parse_iv(start + 2) - 1;
468    if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) {
469        return 0;
470    }
471
472    if (*rval == *rval_ref) return 0;
473
474    if (*rval != NULL) {
475        zval_ptr_dtor(rval);
476    }
477    *rval = *rval_ref;
478    Z_ADDREF_PP(rval);
479    Z_UNSET_ISREF_PP(rval);
480
481    return 1;
482}
483
484"N;"    {
485    *p = YYCURSOR;
486    INIT_PZVAL(*rval);
487    ZVAL_NULL(*rval);
488    return 1;
489}
490
491"b:" [01] ";"   {
492    *p = YYCURSOR;
493    INIT_PZVAL(*rval);
494    ZVAL_BOOL(*rval, parse_iv(start + 2));
495    return 1;
496}
497
498"i:" iv ";" {
499#if SIZEOF_LONG == 4
500    int digits = YYCURSOR - start - 3;
501
502    if (start[2] == '-' || start[2] == '+') {
503        digits--;
504    }
505
506    /* Use double for large long values that were serialized on a 64-bit system */
507    if (digits >= MAX_LENGTH_OF_LONG - 1) {
508        if (digits == MAX_LENGTH_OF_LONG - 1) {
509            int cmp = strncmp(YYCURSOR - MAX_LENGTH_OF_LONG, long_min_digits, MAX_LENGTH_OF_LONG - 1);
510
511            if (!(cmp < 0 || (cmp == 0 && start[2] == '-'))) {
512                goto use_double;
513            }
514        } else {
515            goto use_double;
516        }
517    }
518#endif
519    *p = YYCURSOR;
520    INIT_PZVAL(*rval);
521    ZVAL_LONG(*rval, parse_iv(start + 2));
522    return 1;
523}
524
525"d:" ("NAN" | "-"? "INF") ";"   {
526    *p = YYCURSOR;
527    INIT_PZVAL(*rval);
528
529    if (!strncmp(start + 2, "NAN", 3)) {
530        ZVAL_DOUBLE(*rval, php_get_nan());
531    } else if (!strncmp(start + 2, "INF", 3)) {
532        ZVAL_DOUBLE(*rval, php_get_inf());
533    } else if (!strncmp(start + 2, "-INF", 4)) {
534        ZVAL_DOUBLE(*rval, -php_get_inf());
535    }
536
537    return 1;
538}
539
540"d:" (iv | nv | nvexp) ";"  {
541#if SIZEOF_LONG == 4
542use_double:
543#endif
544    *p = YYCURSOR;
545    INIT_PZVAL(*rval);
546    ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
547    return 1;
548}
549
550"s:" uiv ":" ["]    {
551    size_t len, maxlen;
552    char *str;
553
554    len = parse_uiv(start + 2);
555    maxlen = max - YYCURSOR;
556    if (maxlen < len) {
557        *p = start + 2;
558        return 0;
559    }
560
561    str = (char*)YYCURSOR;
562
563    YYCURSOR += len;
564
565    if (*(YYCURSOR) != '"') {
566        *p = YYCURSOR;
567        return 0;
568    }
569
570    YYCURSOR += 2;
571    *p = YYCURSOR;
572
573    INIT_PZVAL(*rval);
574    ZVAL_STRINGL(*rval, str, len, 1);
575    return 1;
576}
577
578"S:" uiv ":" ["]    {
579    size_t len, maxlen;
580    char *str;
581
582    len = parse_uiv(start + 2);
583    maxlen = max - YYCURSOR;
584    if (maxlen < len) {
585        *p = start + 2;
586        return 0;
587    }
588
589    if ((str = unserialize_str(&YYCURSOR, &len, maxlen)) == NULL) {
590        return 0;
591    }
592
593    if (*(YYCURSOR) != '"') {
594        efree(str);
595        *p = YYCURSOR;
596        return 0;
597    }
598
599    YYCURSOR += 2;
600    *p = YYCURSOR;
601
602    INIT_PZVAL(*rval);
603    ZVAL_STRINGL(*rval, str, len, 0);
604    return 1;
605}
606
607"a:" uiv ":" "{" {
608    long elements = parse_iv(start + 2);
609    /* use iv() not uiv() in order to check data range */
610    *p = YYCURSOR;
611
612    if (elements < 0) {
613        return 0;
614    }
615
616    INIT_PZVAL(*rval);
617
618    array_init_size(*rval, elements);
619
620    if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements, 0)) {
621        return 0;
622    }
623
624    return finish_nested_data(UNSERIALIZE_PASSTHRU);
625}
626
627"o:" iv ":" ["] {
628
629    INIT_PZVAL(*rval);
630
631    return object_common2(UNSERIALIZE_PASSTHRU,
632            object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
633}
634
635object ":" uiv ":" ["]  {
636    size_t len, len2, len3, maxlen;
637    long elements;
638    char *class_name;
639    zend_class_entry *ce;
640    zend_class_entry **pce;
641    int incomplete_class = 0;
642
643    int custom_object = 0;
644
645    zval *user_func;
646    zval *retval_ptr;
647    zval **args[1];
648    zval *arg_func_name;
649
650    if (*start == 'C') {
651        custom_object = 1;
652    }
653
654    INIT_PZVAL(*rval);
655    len2 = len = parse_uiv(start + 2);
656    maxlen = max - YYCURSOR;
657    if (maxlen < len || len == 0) {
658        *p = start + 2;
659        return 0;
660    }
661
662    class_name = (char*)YYCURSOR;
663
664    YYCURSOR += len;
665
666    if (*(YYCURSOR) != '"') {
667        *p = YYCURSOR;
668        return 0;
669    }
670    if (*(YYCURSOR+1) != ':') {
671        *p = YYCURSOR+1;
672        return 0;
673    }
674
675    len3 = strspn(class_name, "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377\\");
676    if (len3 != len)
677    {
678        *p = YYCURSOR + len3 - len;
679        return 0;
680    }
681
682    class_name = estrndup(class_name, len);
683
684    do {
685        /* Try to find class directly */
686        BG(serialize_lock) = 1;
687        if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
688            BG(serialize_lock) = 0;
689            if (EG(exception)) {
690                efree(class_name);
691                return 0;
692            }
693            ce = *pce;
694            break;
695        }
696        BG(serialize_lock) = 0;
697
698        if (EG(exception)) {
699            efree(class_name);
700            return 0;
701        }
702
703        /* Check for unserialize callback */
704        if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
705            incomplete_class = 1;
706            ce = PHP_IC_ENTRY;
707            break;
708        }
709
710        /* Call unserialize callback */
711        MAKE_STD_ZVAL(user_func);
712        ZVAL_STRING(user_func, PG(unserialize_callback_func), 1);
713        args[0] = &arg_func_name;
714        MAKE_STD_ZVAL(arg_func_name);
715        ZVAL_STRING(arg_func_name, class_name, 1);
716        BG(serialize_lock) = 1;
717        if (call_user_function_ex(CG(function_table), NULL, user_func, &retval_ptr, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) {
718            BG(serialize_lock) = 0;
719            if (EG(exception)) {
720                efree(class_name);
721                zval_ptr_dtor(&user_func);
722                zval_ptr_dtor(&arg_func_name);
723                return 0;
724            }
725            php_error_docref(NULL TSRMLS_CC, E_WARNING, "defined (%s) but not found", user_func->value.str.val);
726            incomplete_class = 1;
727            ce = PHP_IC_ENTRY;
728            zval_ptr_dtor(&user_func);
729            zval_ptr_dtor(&arg_func_name);
730            break;
731        }
732        BG(serialize_lock) = 0;
733        if (retval_ptr) {
734            zval_ptr_dtor(&retval_ptr);
735        }
736        if (EG(exception)) {
737            efree(class_name);
738            zval_ptr_dtor(&user_func);
739            zval_ptr_dtor(&arg_func_name);
740            return 0;
741        }
742
743        /* The callback function may have defined the class */
744        if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
745            ce = *pce;
746        } else {
747            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Function %s() hasn't defined the class it was called for", user_func->value.str.val);
748            incomplete_class = 1;
749            ce = PHP_IC_ENTRY;
750        }
751
752        zval_ptr_dtor(&user_func);
753        zval_ptr_dtor(&arg_func_name);
754        break;
755    } while (1);
756
757    *p = YYCURSOR;
758
759    if (custom_object) {
760        int ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
761
762        if (ret && incomplete_class) {
763            php_store_class_name(*rval, class_name, len2);
764        }
765        efree(class_name);
766        return ret;
767    }
768
769    elements = object_common1(UNSERIALIZE_PASSTHRU, ce);
770
771    if (incomplete_class) {
772        php_store_class_name(*rval, class_name, len2);
773    }
774    efree(class_name);
775
776    return object_common2(UNSERIALIZE_PASSTHRU, elements);
777}
778
779"}" {
780    /* this is the case where we have less data than planned */
781    php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data");
782    return 0; /* not sure if it should be 0 or 1 here? */
783}
784
785any { return 0; }
786
787*/
788
789    return 0;
790}
791