Updates to Tomato RAF including NGINX && PHP
[tomato.git] / release / src / router / php / ext / standard / var_unserializer.re
blob4d99cbfd78944c8ed77f51647ae7ef50d86084b0
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   +----------------------------------------------------------------------+
19 /* $Id$ */
21 #include "php.h"
22 #include "ext/standard/php_var.h"
23 #include "php_incomplete_class.h"
25 /* {{{ reference-handling for unserializer: var_* */
26 #define VAR_ENTRIES_MAX 1024
28 typedef struct {
29         zval *data[VAR_ENTRIES_MAX];
30         long used_slots;
31         void *next;
32 } var_entries;
34 static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval)
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
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;
46                 if (!(*var_hashx)->first) {
47                         (*var_hashx)->first = var_hash;
48                 } else {
49                         ((var_entries *) (*var_hashx)->last)->next = var_hash;
50                 }
52                 (*var_hashx)->last = var_hash;
53         }
55         var_hash->data[var_hash->used_slots++] = *rval;
58 PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
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
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;
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                 }
76                 (*var_hashx)->last_dtor = var_hash;
77         }
79         Z_ADDREF_PP(rval);
80         var_hash->data[var_hash->used_slots++] = *rval;
83 PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **nzval)
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         }
102 static int var_access(php_unserialize_data_t *var_hashx, long id, zval ***store)
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         }
114         if (!var_hash) return !SUCCESS;
116         if (id < 0 || id >= var_hash->used_slots) return !SUCCESS;
118         *store = &var_hash->data[id];
120         return SUCCESS;
123 PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
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         }
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         }
150 /* }}} */
152 static char *unserialize_str(const unsigned char **p, size_t *len, size_t maxlen)
154         size_t i, j;
155         char *str = safe_emalloc(*len, 1, 1);
156         unsigned char *end = *(unsigned char **)p+maxlen;
158         if (end < *p) {
159                 efree(str);
160                 return NULL;
161         }
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;
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;
195 #define YYFILL(n) do { } while (0)
196 #define YYCTYPE unsigned char
197 #define YYCURSOR cursor
198 #define YYLIMIT limit
199 #define YYMARKER marker
202 /*!re2c
203 uiv = [+]? [0-9]+;
204 iv = [+-]? [0-9]+;
205 nv = [+-]? ([0-9]* "." [0-9]+|[0-9]+ "." [0-9]*);
206 nvexp = (iv | nv) [eE] [+-]? iv;
207 any = [\000-\377];
208 object = [OC];
213 static inline long parse_iv2(const unsigned char *p, const unsigned char **q)
215         char cursor;
216         long result = 0;
217         int neg = 0;
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;
241 static inline long parse_iv(const unsigned char *p)
243         return parse_iv2(p, NULL);
246 /* no need to check for length - re2c already did */
247 static inline size_t parse_uiv(const unsigned char *p)
249         unsigned char cursor;
250         size_t result = 0;
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;
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
271 static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long elements, int objprops)
273         while (elements-- > 0) {
274                 zval *key, *data, **old_data;
276                 ALLOC_INIT_ZVAL(key);
278                 if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) {
279                         zval_dtor(key);
280                         FREE_ZVAL(key);
281                         return 0;
282                 }
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                 }
290                 ALLOC_INIT_ZVAL(data);
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                 }
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);
325                 if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
326                         (*p)--;
327                         return 0;
328                 }
329         }
331         return 1;
334 static inline int finish_nested_data(UNSERIALIZE_PARAMETER)
336         if (*((*p)++) == '}')
337                 return 1;
339 #if SOMETHING_NEW_MIGHT_LEAD_TO_CRASH_ENABLE_IF_YOU_ARE_BRAVE
340         zval_ptr_dtor(rval);
341 #endif
342         return 0;
345 static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
347         long datalen;
349         datalen = parse_iv2((*p) + 2, p);
351         (*p) += 2;
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         }
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         }
365         (*p) += datalen;
367         return finish_nested_data(UNSERIALIZE_PASSTHRU);
370 static inline long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
372         long elements;
373         
374         elements = parse_iv2((*p) + 2, p);
376         (*p) += 2;
377         
378         object_init_ex(*rval, ce);
379         return elements;
382 #ifdef PHP_WIN32
383 # pragma optimize("", off)
384 #endif
385 static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
387         zval *retval_ptr = NULL;
388         zval fname;
390         if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) {
391                 return 0;
392         }
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         }
403         if (retval_ptr) {
404                 zval_ptr_dtor(&retval_ptr);
405         }
407         if (EG(exception)) {
408                 return 0;
409         }
411         return finish_nested_data(UNSERIALIZE_PASSTHRU);
414 #ifdef PHP_WIN32
415 # pragma optimize("", on)
416 #endif
418 PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
420         const unsigned char *cursor, *limit, *marker, *start;
421         zval **rval_ref;
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         }
434         start = cursor;
436         
437         
438 /*!re2c
440 "R:" iv ";"             {
441         long id;
443         *p = YYCURSOR;
444         if (!var_hash) return 0;
446         id = parse_iv(start + 2) - 1;
447         if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) {
448                 return 0;
449         }
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;
461 "r:" iv ";"             {
462         long id;
464         *p = YYCURSOR;
465         if (!var_hash) return 0;
467         id = parse_iv(start + 2) - 1;
468         if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) {
469                 return 0;
470         }
472         if (*rval == *rval_ref) return 0;
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;
484 "N;"    {
485         *p = YYCURSOR;
486         INIT_PZVAL(*rval);
487         ZVAL_NULL(*rval);
488         return 1;
491 "b:" [01] ";"   {
492         *p = YYCURSOR;
493         INIT_PZVAL(*rval);
494         ZVAL_BOOL(*rval, parse_iv(start + 2));
495         return 1;
498 "i:" iv ";"     {
499 #if SIZEOF_LONG == 4
500         int digits = YYCURSOR - start - 3;
502         if (start[2] == '-' || start[2] == '+') {
503                 digits--;
504         }
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);
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;
525 "d:" ("NAN" | "-"? "INF") ";"   {
526         *p = YYCURSOR;
527         INIT_PZVAL(*rval);
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         }
537         return 1;
540 "d:" (iv | nv | nvexp) ";"      {
541 #if SIZEOF_LONG == 4
542 use_double:
543 #endif
544         *p = YYCURSOR;
545         INIT_PZVAL(*rval);
546         ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
547         return 1;
550 "s:" uiv ":" ["]        {
551         size_t len, maxlen;
552         char *str;
554         len = parse_uiv(start + 2);
555         maxlen = max - YYCURSOR;
556         if (maxlen < len) {
557                 *p = start + 2;
558                 return 0;
559         }
561         str = (char*)YYCURSOR;
563         YYCURSOR += len;
565         if (*(YYCURSOR) != '"') {
566                 *p = YYCURSOR;
567                 return 0;
568         }
570         YYCURSOR += 2;
571         *p = YYCURSOR;
573         INIT_PZVAL(*rval);
574         ZVAL_STRINGL(*rval, str, len, 1);
575         return 1;
578 "S:" uiv ":" ["]        {
579         size_t len, maxlen;
580         char *str;
582         len = parse_uiv(start + 2);
583         maxlen = max - YYCURSOR;
584         if (maxlen < len) {
585                 *p = start + 2;
586                 return 0;
587         }
589         if ((str = unserialize_str(&YYCURSOR, &len, maxlen)) == NULL) {
590                 return 0;
591         }
593         if (*(YYCURSOR) != '"') {
594                 efree(str);
595                 *p = YYCURSOR;
596                 return 0;
597         }
599         YYCURSOR += 2;
600         *p = YYCURSOR;
602         INIT_PZVAL(*rval);
603         ZVAL_STRINGL(*rval, str, len, 0);
604         return 1;
607 "a:" uiv ":" "{" {
608         long elements = parse_iv(start + 2);
609         /* use iv() not uiv() in order to check data range */
610         *p = YYCURSOR;
612         if (elements < 0) {
613                 return 0;
614         }
616         INIT_PZVAL(*rval);
618         array_init_size(*rval, elements);
620         if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements, 0)) {
621                 return 0;
622         }
624         return finish_nested_data(UNSERIALIZE_PASSTHRU);
627 "o:" iv ":" ["] {
629         INIT_PZVAL(*rval);
630         
631         return object_common2(UNSERIALIZE_PASSTHRU,
632                         object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
635 object ":" 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;
643         int custom_object = 0;
645         zval *user_func;
646         zval *retval_ptr;
647         zval **args[1];
648         zval *arg_func_name;
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         }
662         class_name = (char*)YYCURSOR;
664         YYCURSOR += len;
666         if (*(YYCURSOR) != '"') {
667                 *p = YYCURSOR;
668                 return 0;
669         }
670         if (*(YYCURSOR+1) != ':') {
671                 *p = YYCURSOR+1;
672                 return 0;
673         }
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         }
682         class_name = estrndup(class_name, len);
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;
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                 }
752                 zval_ptr_dtor(&user_func);
753                 zval_ptr_dtor(&arg_func_name);
754                 break;
755         } while (1);
757         *p = YYCURSOR;
759         if (custom_object) {
760                 int ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
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);
771         if (incomplete_class) {
772                 php_store_class_name(*rval, class_name, len2);
773         }
774         efree(class_name);
776         return object_common2(UNSERIALIZE_PASSTHRU, elements);
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? */
785 any     { return 0; }
789         return 0;