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