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