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