root/ext/standard/var_unserializer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. var_push
  2. var_push_dtor
  3. var_push_dtor_no_addref
  4. var_replace
  5. var_access
  6. var_destroy
  7. unserialize_str
  8. parse_iv2
  9. parse_iv
  10. parse_uiv
  11. process_nested_data
  12. finish_nested_data
  13. object_custom
  14. object_common1
  15. object_common2
  16. php_var_unserialize

   1 /* Generated by re2c 0.13.7.5 */
   2 /*
   3   +----------------------------------------------------------------------+
   4   | PHP Version 5                                                        |
   5   +----------------------------------------------------------------------+
   6   | Copyright (c) 1997-2016 The PHP Group                                |
   7   +----------------------------------------------------------------------+
   8   | This source file is subject to version 3.01 of the PHP license,      |
   9   | that is bundled with this package in the file LICENSE, and is        |
  10   | available through the world-wide-web at the following url:           |
  11   | http://www.php.net/license/3_01.txt                                  |
  12   | If you did not receive a copy of the PHP license and are unable to   |
  13   | obtain it through the world-wide-web, please send a note to          |
  14   | license@php.net so we can mail you a copy immediately.               |
  15   +----------------------------------------------------------------------+
  16   | Author: Sascha Schumann <sascha@schumann.cx>                         |
  17   +----------------------------------------------------------------------+
  18 */
  19 
  20 /* $Id$ */
  21 
  22 #include "php.h"
  23 #include "ext/standard/php_var.h"
  24 #include "php_incomplete_class.h"
  25 
  26 /* {{{ reference-handling for unserializer: var_* */
  27 #define VAR_ENTRIES_MAX 1024
  28 #define VAR_ENTRIES_DBG 0
  29 
  30 typedef struct {
  31         zval *data[VAR_ENTRIES_MAX];
  32         long used_slots;
  33         void *next;
  34 } var_entries;
  35 
  36 static 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 
  60 PHPAPI 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 
  91 PHPAPI 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 
 121 PHPAPI 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 
 140 static 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 
 161 PHPAPI 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 
 193 static 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 
 244 
 245 
 246 
 247 static inline long parse_iv2(const unsigned char *p, const unsigned char **q)
 248 {
 249         char cursor;
 250         long result = 0;
 251         int neg = 0;
 252 
 253         switch (*p) {
 254                 case '-':
 255                         neg++;
 256                         /* fall-through */
 257                 case '+':
 258                         p++;
 259         }
 260 
 261         while (1) {
 262                 cursor = (char)*p;
 263                 if (cursor >= '0' && cursor <= '9') {
 264                         result = result * 10 + (size_t)(cursor - (unsigned char)'0');
 265                 } else {
 266                         break;
 267                 }
 268                 p++;
 269         }
 270         if (q) *q = p;
 271         if (neg) return -result;
 272         return result;
 273 }
 274 
 275 static inline long parse_iv(const unsigned char *p)
 276 {
 277         return parse_iv2(p, NULL);
 278 }
 279 
 280 /* no need to check for length - re2c already did */
 281 static inline size_t parse_uiv(const unsigned char *p)
 282 {
 283         unsigned char cursor;
 284         size_t result = 0;
 285 
 286         if (*p == '+') {
 287                 p++;
 288         }
 289 
 290         while (1) {
 291                 cursor = *p;
 292                 if (cursor >= '0' && cursor <= '9') {
 293                         result = result * 10 + (size_t)(cursor - (unsigned char)'0');
 294                 } else {
 295                         break;
 296                 }
 297                 p++;
 298         }
 299         return result;
 300 }
 301 
 302 #define UNSERIALIZE_PARAMETER zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC
 303 #define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC
 304 
 305 static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long elements, int objprops)
 306 {
 307         while (elements-- > 0) {
 308                 zval *key, *data, **old_data;
 309 
 310                 ALLOC_INIT_ZVAL(key);
 311 
 312                 if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) {
 313             var_push_dtor_no_addref(var_hash, &key);
 314                         return 0;
 315                 }
 316 
 317                 if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) {
 318             var_push_dtor_no_addref(var_hash, &key);
 319                         return 0;
 320                 }
 321 
 322                 ALLOC_INIT_ZVAL(data);
 323 
 324                 if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) {
 325             var_push_dtor_no_addref(var_hash, &key);
 326             var_push_dtor_no_addref(var_hash, &data);
 327                         return 0;
 328                 }
 329 
 330                 if (!objprops) {
 331                         switch (Z_TYPE_P(key)) {
 332                         case IS_LONG:
 333                                 if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)==SUCCESS) {
 334                                         var_push_dtor(var_hash, old_data);
 335                                 }
 336                                 zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL);
 337                                 break;
 338                         case IS_STRING:
 339                                 if (zend_symtable_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
 340                                         var_push_dtor(var_hash, old_data);
 341                                 }
 342                                 zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL);
 343                                 break;
 344                         }
 345                 } else {
 346                         /* object properties should include no integers */
 347                         convert_to_string(key);
 348                         if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
 349                                 var_push_dtor(var_hash, old_data);
 350                         }
 351                         zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data,
 352                                         sizeof data, NULL);
 353                 }
 354                 var_push_dtor(var_hash, &data);
 355         var_push_dtor_no_addref(var_hash, &key);
 356 
 357                 if (elements && *(*p-1) != ';' && *(*p-1) != '}') {
 358                         (*p)--;
 359                         return 0;
 360                 }
 361         }
 362 
 363         return 1;
 364 }
 365 
 366 static inline int finish_nested_data(UNSERIALIZE_PARAMETER)
 367 {
 368         if (*((*p)++) == '}')
 369                 return 1;
 370 
 371 #if SOMETHING_NEW_MIGHT_LEAD_TO_CRASH_ENABLE_IF_YOU_ARE_BRAVE
 372         zval_ptr_dtor(rval);
 373 #endif
 374         return 0;
 375 }
 376 
 377 static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
 378 {
 379         long datalen;
 380 
 381         datalen = parse_iv2((*p) + 2, p);
 382 
 383         (*p) += 2;
 384 
 385         if (datalen < 0 || (max - (*p)) <= datalen) {
 386                 zend_error(E_WARNING, "Insufficient data for unserializing - %ld required, %ld present", datalen, (long)(max - (*p)));
 387                 return 0;
 388         }
 389 
 390         if (ce->unserialize == NULL) {
 391                 zend_error(E_WARNING, "Class %s has no unserializer", ce->name);
 392                 object_init_ex(*rval, ce);
 393         } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) != SUCCESS) {
 394                 return 0;
 395         }
 396 
 397         (*p) += datalen;
 398 
 399         return finish_nested_data(UNSERIALIZE_PASSTHRU);
 400 }
 401 
 402 static inline long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
 403 {
 404         long elements;
 405 
 406         elements = parse_iv2((*p) + 2, p);
 407 
 408         (*p) += 2;
 409         
 410         if (ce->serialize == NULL) {
 411                 object_init_ex(*rval, ce);
 412         } else {
 413                 /* If this class implements Serializable, it should not land here but in object_custom(). The passed string
 414                 obviously doesn't descend from the regular serializer. */
 415                 zend_error(E_WARNING, "Erroneous data format for unserializing '%s'", ce->name);
 416                 return 0;
 417         }
 418 
 419         return elements;
 420 }
 421 
 422 #ifdef PHP_WIN32
 423 # pragma optimize("", off)
 424 #endif
 425 static inline int object_common2(UNSERIALIZE_PARAMETER, long elements)
 426 {
 427         zval *retval_ptr = NULL;
 428         zval fname;
 429 
 430         if (Z_TYPE_PP(rval) != IS_OBJECT) {
 431                 return 0;
 432         }
 433 
 434         if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) {
 435                 return 0;
 436         }
 437 
 438         if (Z_OBJCE_PP(rval) != PHP_IC_ENTRY &&
 439                 zend_hash_exists(&Z_OBJCE_PP(rval)->function_table, "__wakeup", sizeof("__wakeup"))) {
 440                 INIT_PZVAL(&fname);
 441                 ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1, 0);
 442                 BG(serialize_lock)++;
 443                 call_user_function_ex(CG(function_table), rval, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC);
 444                 BG(serialize_lock)--;
 445         }
 446 
 447         if (retval_ptr) {
 448                 zval_ptr_dtor(&retval_ptr);
 449         }
 450 
 451         if (EG(exception)) {
 452                 return 0;
 453         }
 454 
 455         return finish_nested_data(UNSERIALIZE_PASSTHRU);
 456 
 457 }
 458 #ifdef PHP_WIN32
 459 # pragma optimize("", on)
 460 #endif
 461 
 462 PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
 463 {
 464         const unsigned char *cursor, *limit, *marker, *start;
 465         zval **rval_ref;
 466 
 467         limit = max;
 468         cursor = *p;
 469 
 470         if (YYCURSOR >= YYLIMIT) {
 471                 return 0;
 472         }
 473 
 474         if (var_hash && cursor[0] != 'R') {
 475                 var_push(var_hash, rval);
 476         }
 477 
 478         start = cursor;
 479 
 480 
 481 
 482 
 483 {
 484         YYCTYPE yych;
 485         static const unsigned char yybm[] = {
 486                   0,   0,   0,   0,   0,   0,   0,   0, 
 487                   0,   0,   0,   0,   0,   0,   0,   0, 
 488                   0,   0,   0,   0,   0,   0,   0,   0, 
 489                   0,   0,   0,   0,   0,   0,   0,   0, 
 490                   0,   0,   0,   0,   0,   0,   0,   0, 
 491                   0,   0,   0,   0,   0,   0,   0,   0, 
 492                 128, 128, 128, 128, 128, 128, 128, 128, 
 493                 128, 128,   0,   0,   0,   0,   0,   0, 
 494                   0,   0,   0,   0,   0,   0,   0,   0, 
 495                   0,   0,   0,   0,   0,   0,   0,   0, 
 496                   0,   0,   0,   0,   0,   0,   0,   0, 
 497                   0,   0,   0,   0,   0,   0,   0,   0, 
 498                   0,   0,   0,   0,   0,   0,   0,   0, 
 499                   0,   0,   0,   0,   0,   0,   0,   0, 
 500                   0,   0,   0,   0,   0,   0,   0,   0, 
 501                   0,   0,   0,   0,   0,   0,   0,   0, 
 502                   0,   0,   0,   0,   0,   0,   0,   0, 
 503                   0,   0,   0,   0,   0,   0,   0,   0, 
 504                   0,   0,   0,   0,   0,   0,   0,   0, 
 505                   0,   0,   0,   0,   0,   0,   0,   0, 
 506                   0,   0,   0,   0,   0,   0,   0,   0, 
 507                   0,   0,   0,   0,   0,   0,   0,   0, 
 508                   0,   0,   0,   0,   0,   0,   0,   0, 
 509                   0,   0,   0,   0,   0,   0,   0,   0, 
 510                   0,   0,   0,   0,   0,   0,   0,   0, 
 511                   0,   0,   0,   0,   0,   0,   0,   0, 
 512                   0,   0,   0,   0,   0,   0,   0,   0, 
 513                   0,   0,   0,   0,   0,   0,   0,   0, 
 514                   0,   0,   0,   0,   0,   0,   0,   0, 
 515                   0,   0,   0,   0,   0,   0,   0,   0, 
 516                   0,   0,   0,   0,   0,   0,   0,   0, 
 517                   0,   0,   0,   0,   0,   0,   0,   0, 
 518         };
 519 
 520         if ((YYLIMIT - YYCURSOR) < 7) YYFILL(7);
 521         yych = *YYCURSOR;
 522         switch (yych) {
 523         case 'C':
 524         case 'O':       goto yy13;
 525         case 'N':       goto yy5;
 526         case 'R':       goto yy2;
 527         case 'S':       goto yy10;
 528         case 'a':       goto yy11;
 529         case 'b':       goto yy6;
 530         case 'd':       goto yy8;
 531         case 'i':       goto yy7;
 532         case 'o':       goto yy12;
 533         case 'r':       goto yy4;
 534         case 's':       goto yy9;
 535         case '}':       goto yy14;
 536         default:        goto yy16;
 537         }
 538 yy2:
 539         yych = *(YYMARKER = ++YYCURSOR);
 540         if (yych == ':') goto yy95;
 541 yy3:
 542         { return 0; }
 543 yy4:
 544         yych = *(YYMARKER = ++YYCURSOR);
 545         if (yych == ':') goto yy89;
 546         goto yy3;
 547 yy5:
 548         yych = *++YYCURSOR;
 549         if (yych == ';') goto yy87;
 550         goto yy3;
 551 yy6:
 552         yych = *(YYMARKER = ++YYCURSOR);
 553         if (yych == ':') goto yy83;
 554         goto yy3;
 555 yy7:
 556         yych = *(YYMARKER = ++YYCURSOR);
 557         if (yych == ':') goto yy77;
 558         goto yy3;
 559 yy8:
 560         yych = *(YYMARKER = ++YYCURSOR);
 561         if (yych == ':') goto yy53;
 562         goto yy3;
 563 yy9:
 564         yych = *(YYMARKER = ++YYCURSOR);
 565         if (yych == ':') goto yy46;
 566         goto yy3;
 567 yy10:
 568         yych = *(YYMARKER = ++YYCURSOR);
 569         if (yych == ':') goto yy39;
 570         goto yy3;
 571 yy11:
 572         yych = *(YYMARKER = ++YYCURSOR);
 573         if (yych == ':') goto yy32;
 574         goto yy3;
 575 yy12:
 576         yych = *(YYMARKER = ++YYCURSOR);
 577         if (yych == ':') goto yy25;
 578         goto yy3;
 579 yy13:
 580         yych = *(YYMARKER = ++YYCURSOR);
 581         if (yych == ':') goto yy17;
 582         goto yy3;
 583 yy14:
 584         ++YYCURSOR;
 585         {
 586         /* this is the case where we have less data than planned */
 587         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data");
 588         return 0; /* not sure if it should be 0 or 1 here? */
 589 }
 590 yy16:
 591         yych = *++YYCURSOR;
 592         goto yy3;
 593 yy17:
 594         yych = *++YYCURSOR;
 595         if (yybm[0+yych] & 128) {
 596                 goto yy20;
 597         }
 598         if (yych == '+') goto yy19;
 599 yy18:
 600         YYCURSOR = YYMARKER;
 601         goto yy3;
 602 yy19:
 603         yych = *++YYCURSOR;
 604         if (yybm[0+yych] & 128) {
 605                 goto yy20;
 606         }
 607         goto yy18;
 608 yy20:
 609         ++YYCURSOR;
 610         if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
 611         yych = *YYCURSOR;
 612         if (yybm[0+yych] & 128) {
 613                 goto yy20;
 614         }
 615         if (yych <= '/') goto yy18;
 616         if (yych >= ';') goto yy18;
 617         yych = *++YYCURSOR;
 618         if (yych != '"') goto yy18;
 619         ++YYCURSOR;
 620         {
 621         size_t len, len2, len3, maxlen;
 622         long elements;
 623         char *class_name;
 624         zend_class_entry *ce;
 625         zend_class_entry **pce;
 626         int incomplete_class = 0;
 627 
 628         int custom_object = 0;
 629 
 630         zval *user_func;
 631         zval *retval_ptr;
 632         zval **args[1];
 633         zval *arg_func_name;
 634 
 635     if (!var_hash) return 0;
 636         if (*start == 'C') {
 637                 custom_object = 1;
 638         }
 639 
 640         INIT_PZVAL(*rval);
 641         len2 = len = parse_uiv(start + 2);
 642         maxlen = max - YYCURSOR;
 643         if (maxlen < len || len == 0) {
 644                 *p = start + 2;
 645                 return 0;
 646         }
 647 
 648         class_name = (char*)YYCURSOR;
 649 
 650         YYCURSOR += len;
 651 
 652         if (*(YYCURSOR) != '"') {
 653                 *p = YYCURSOR;
 654                 return 0;
 655         }
 656         if (*(YYCURSOR+1) != ':') {
 657                 *p = YYCURSOR+1;
 658                 return 0;
 659         }
 660 
 661         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\\");
 662         if (len3 != len)
 663         {
 664                 *p = YYCURSOR + len3 - len;
 665                 return 0;
 666         }
 667 
 668         class_name = estrndup(class_name, len);
 669 
 670         do {
 671                 /* Try to find class directly */
 672                 BG(serialize_lock)++;
 673                 if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
 674                         BG(serialize_lock)--;
 675                         if (EG(exception)) {
 676                                 efree(class_name);
 677                                 return 0;
 678                         }
 679                         ce = *pce;
 680                         break;
 681                 }
 682                 BG(serialize_lock)--;
 683 
 684                 if (EG(exception)) {
 685                         efree(class_name);
 686                         return 0;
 687                 }
 688 
 689                 /* Check for unserialize callback */
 690                 if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
 691                         incomplete_class = 1;
 692                         ce = PHP_IC_ENTRY;
 693                         break;
 694                 }
 695 
 696                 /* Call unserialize callback */
 697                 MAKE_STD_ZVAL(user_func);
 698                 ZVAL_STRING(user_func, PG(unserialize_callback_func), 1);
 699                 args[0] = &arg_func_name;
 700                 MAKE_STD_ZVAL(arg_func_name);
 701                 ZVAL_STRING(arg_func_name, class_name, 1);
 702                 BG(serialize_lock)++;
 703                 if (call_user_function_ex(CG(function_table), NULL, user_func, &retval_ptr, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) {
 704                         BG(serialize_lock)--;
 705                         if (EG(exception)) {
 706                                 efree(class_name);
 707                                 zval_ptr_dtor(&user_func);
 708                                 zval_ptr_dtor(&arg_func_name);
 709                                 return 0;
 710                         }
 711                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "defined (%s) but not found", user_func->value.str.val);
 712                         incomplete_class = 1;
 713                         ce = PHP_IC_ENTRY;
 714                         zval_ptr_dtor(&user_func);
 715                         zval_ptr_dtor(&arg_func_name);
 716                         break;
 717                 }
 718                 BG(serialize_lock)--;
 719                 if (retval_ptr) {
 720                         zval_ptr_dtor(&retval_ptr);
 721                 }
 722                 if (EG(exception)) {
 723                         efree(class_name);
 724                         zval_ptr_dtor(&user_func);
 725                         zval_ptr_dtor(&arg_func_name);
 726                         return 0;
 727                 }
 728 
 729                 /* The callback function may have defined the class */
 730                 if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
 731                         ce = *pce;
 732                 } else {
 733                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Function %s() hasn't defined the class it was called for", user_func->value.str.val);
 734                         incomplete_class = 1;
 735                         ce = PHP_IC_ENTRY;
 736                 }
 737 
 738                 zval_ptr_dtor(&user_func);
 739                 zval_ptr_dtor(&arg_func_name);
 740                 break;
 741         } while (1);
 742 
 743         *p = YYCURSOR;
 744 
 745         if (custom_object) {
 746                 int ret;
 747 
 748                 ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
 749 
 750                 if (ret && incomplete_class) {
 751                         php_store_class_name(*rval, class_name, len2);
 752                 }
 753                 efree(class_name);
 754                 return ret;
 755         }
 756 
 757         elements = object_common1(UNSERIALIZE_PASSTHRU, ce);
 758 
 759         if (incomplete_class) {
 760                 php_store_class_name(*rval, class_name, len2);
 761         }
 762         efree(class_name);
 763 
 764         return object_common2(UNSERIALIZE_PASSTHRU, elements);
 765 }
 766 yy25:
 767         yych = *++YYCURSOR;
 768         if (yych <= ',') {
 769                 if (yych != '+') goto yy18;
 770         } else {
 771                 if (yych <= '-') goto yy26;
 772                 if (yych <= '/') goto yy18;
 773                 if (yych <= '9') goto yy27;
 774                 goto yy18;
 775         }
 776 yy26:
 777         yych = *++YYCURSOR;
 778         if (yych <= '/') goto yy18;
 779         if (yych >= ':') goto yy18;
 780 yy27:
 781         ++YYCURSOR;
 782         if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
 783         yych = *YYCURSOR;
 784         if (yych <= '/') goto yy18;
 785         if (yych <= '9') goto yy27;
 786         if (yych >= ';') goto yy18;
 787         yych = *++YYCURSOR;
 788         if (yych != '"') goto yy18;
 789         ++YYCURSOR;
 790         {
 791     if (!var_hash) return 0;
 792 
 793         INIT_PZVAL(*rval);
 794 
 795         return object_common2(UNSERIALIZE_PASSTHRU,
 796                         object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
 797 }
 798 yy32:
 799         yych = *++YYCURSOR;
 800         if (yych == '+') goto yy33;
 801         if (yych <= '/') goto yy18;
 802         if (yych <= '9') goto yy34;
 803         goto yy18;
 804 yy33:
 805         yych = *++YYCURSOR;
 806         if (yych <= '/') goto yy18;
 807         if (yych >= ':') goto yy18;
 808 yy34:
 809         ++YYCURSOR;
 810         if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
 811         yych = *YYCURSOR;
 812         if (yych <= '/') goto yy18;
 813         if (yych <= '9') goto yy34;
 814         if (yych >= ';') goto yy18;
 815         yych = *++YYCURSOR;
 816         if (yych != '{') goto yy18;
 817         ++YYCURSOR;
 818         {
 819         long elements = parse_iv(start + 2);
 820         /* use iv() not uiv() in order to check data range */
 821         *p = YYCURSOR;
 822     if (!var_hash) return 0;
 823 
 824         if (elements < 0) {
 825                 return 0;
 826         }
 827 
 828         INIT_PZVAL(*rval);
 829 
 830         array_init_size(*rval, elements);
 831 
 832         if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements, 0)) {
 833                 return 0;
 834         }
 835 
 836         return finish_nested_data(UNSERIALIZE_PASSTHRU);
 837 }
 838 yy39:
 839         yych = *++YYCURSOR;
 840         if (yych == '+') goto yy40;
 841         if (yych <= '/') goto yy18;
 842         if (yych <= '9') goto yy41;
 843         goto yy18;
 844 yy40:
 845         yych = *++YYCURSOR;
 846         if (yych <= '/') goto yy18;
 847         if (yych >= ':') goto yy18;
 848 yy41:
 849         ++YYCURSOR;
 850         if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
 851         yych = *YYCURSOR;
 852         if (yych <= '/') goto yy18;
 853         if (yych <= '9') goto yy41;
 854         if (yych >= ';') goto yy18;
 855         yych = *++YYCURSOR;
 856         if (yych != '"') goto yy18;
 857         ++YYCURSOR;
 858         {
 859         size_t len, maxlen;
 860         char *str;
 861 
 862         len = parse_uiv(start + 2);
 863         maxlen = max - YYCURSOR;
 864         if (maxlen < len) {
 865                 *p = start + 2;
 866                 return 0;
 867         }
 868 
 869         if ((str = unserialize_str(&YYCURSOR, &len, maxlen)) == NULL) {
 870                 return 0;
 871         }
 872 
 873         if (*(YYCURSOR) != '"') {
 874                 efree(str);
 875                 *p = YYCURSOR;
 876                 return 0;
 877         }
 878 
 879         YYCURSOR += 2;
 880         *p = YYCURSOR;
 881 
 882         INIT_PZVAL(*rval);
 883         ZVAL_STRINGL(*rval, str, len, 0);
 884         return 1;
 885 }
 886 yy46:
 887         yych = *++YYCURSOR;
 888         if (yych == '+') goto yy47;
 889         if (yych <= '/') goto yy18;
 890         if (yych <= '9') goto yy48;
 891         goto yy18;
 892 yy47:
 893         yych = *++YYCURSOR;
 894         if (yych <= '/') goto yy18;
 895         if (yych >= ':') goto yy18;
 896 yy48:
 897         ++YYCURSOR;
 898         if ((YYLIMIT - YYCURSOR) < 2) YYFILL(2);
 899         yych = *YYCURSOR;
 900         if (yych <= '/') goto yy18;
 901         if (yych <= '9') goto yy48;
 902         if (yych >= ';') goto yy18;
 903         yych = *++YYCURSOR;
 904         if (yych != '"') goto yy18;
 905         ++YYCURSOR;
 906         {
 907         size_t len, maxlen;
 908         char *str;
 909 
 910         len = parse_uiv(start + 2);
 911         maxlen = max - YYCURSOR;
 912         if (maxlen < len) {
 913                 *p = start + 2;
 914                 return 0;
 915         }
 916 
 917         str = (char*)YYCURSOR;
 918 
 919         YYCURSOR += len;
 920 
 921         if (*(YYCURSOR) != '"') {
 922                 *p = YYCURSOR;
 923                 return 0;
 924         }
 925 
 926         YYCURSOR += 2;
 927         *p = YYCURSOR;
 928 
 929         INIT_PZVAL(*rval);
 930         ZVAL_STRINGL(*rval, str, len, 1);
 931         return 1;
 932 }
 933 yy53:
 934         yych = *++YYCURSOR;
 935         if (yych <= '/') {
 936                 if (yych <= ',') {
 937                         if (yych == '+') goto yy57;
 938                         goto yy18;
 939                 } else {
 940                         if (yych <= '-') goto yy55;
 941                         if (yych <= '.') goto yy60;
 942                         goto yy18;
 943                 }
 944         } else {
 945                 if (yych <= 'I') {
 946                         if (yych <= '9') goto yy58;
 947                         if (yych <= 'H') goto yy18;
 948                         goto yy56;
 949                 } else {
 950                         if (yych != 'N') goto yy18;
 951                 }
 952         }
 953         yych = *++YYCURSOR;
 954         if (yych == 'A') goto yy76;
 955         goto yy18;
 956 yy55:
 957         yych = *++YYCURSOR;
 958         if (yych <= '/') {
 959                 if (yych == '.') goto yy60;
 960                 goto yy18;
 961         } else {
 962                 if (yych <= '9') goto yy58;
 963                 if (yych != 'I') goto yy18;
 964         }
 965 yy56:
 966         yych = *++YYCURSOR;
 967         if (yych == 'N') goto yy72;
 968         goto yy18;
 969 yy57:
 970         yych = *++YYCURSOR;
 971         if (yych == '.') goto yy60;
 972         if (yych <= '/') goto yy18;
 973         if (yych >= ':') goto yy18;
 974 yy58:
 975         ++YYCURSOR;
 976         if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
 977         yych = *YYCURSOR;
 978         if (yych <= ':') {
 979                 if (yych <= '.') {
 980                         if (yych <= '-') goto yy18;
 981                         goto yy70;
 982                 } else {
 983                         if (yych <= '/') goto yy18;
 984                         if (yych <= '9') goto yy58;
 985                         goto yy18;
 986                 }
 987         } else {
 988                 if (yych <= 'E') {
 989                         if (yych <= ';') goto yy63;
 990                         if (yych <= 'D') goto yy18;
 991                         goto yy65;
 992                 } else {
 993                         if (yych == 'e') goto yy65;
 994                         goto yy18;
 995                 }
 996         }
 997 yy60:
 998         yych = *++YYCURSOR;
 999         if (yych <= '/') goto yy18;
1000         if (yych >= ':') goto yy18;
1001 yy61:
1002         ++YYCURSOR;
1003         if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
1004         yych = *YYCURSOR;
1005         if (yych <= ';') {
1006                 if (yych <= '/') goto yy18;
1007                 if (yych <= '9') goto yy61;
1008                 if (yych <= ':') goto yy18;
1009         } else {
1010                 if (yych <= 'E') {
1011                         if (yych <= 'D') goto yy18;
1012                         goto yy65;
1013                 } else {
1014                         if (yych == 'e') goto yy65;
1015                         goto yy18;
1016                 }
1017         }
1018 yy63:
1019         ++YYCURSOR;
1020         {
1021 #if SIZEOF_LONG == 4
1022 use_double:
1023 #endif
1024         *p = YYCURSOR;
1025         INIT_PZVAL(*rval);
1026         ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
1027         return 1;
1028 }
1029 yy65:
1030         yych = *++YYCURSOR;
1031         if (yych <= ',') {
1032                 if (yych != '+') goto yy18;
1033         } else {
1034                 if (yych <= '-') goto yy66;
1035                 if (yych <= '/') goto yy18;
1036                 if (yych <= '9') goto yy67;
1037                 goto yy18;
1038         }
1039 yy66:
1040         yych = *++YYCURSOR;
1041         if (yych <= ',') {
1042                 if (yych == '+') goto yy69;
1043                 goto yy18;
1044         } else {
1045                 if (yych <= '-') goto yy69;
1046                 if (yych <= '/') goto yy18;
1047                 if (yych >= ':') goto yy18;
1048         }
1049 yy67:
1050         ++YYCURSOR;
1051         if (YYLIMIT <= YYCURSOR) YYFILL(1);
1052         yych = *YYCURSOR;
1053         if (yych <= '/') goto yy18;
1054         if (yych <= '9') goto yy67;
1055         if (yych == ';') goto yy63;
1056         goto yy18;
1057 yy69:
1058         yych = *++YYCURSOR;
1059         if (yych <= '/') goto yy18;
1060         if (yych <= '9') goto yy67;
1061         goto yy18;
1062 yy70:
1063         ++YYCURSOR;
1064         if ((YYLIMIT - YYCURSOR) < 4) YYFILL(4);
1065         yych = *YYCURSOR;
1066         if (yych <= ';') {
1067                 if (yych <= '/') goto yy18;
1068                 if (yych <= '9') goto yy70;
1069                 if (yych <= ':') goto yy18;
1070                 goto yy63;
1071         } else {
1072                 if (yych <= 'E') {
1073                         if (yych <= 'D') goto yy18;
1074                         goto yy65;
1075                 } else {
1076                         if (yych == 'e') goto yy65;
1077                         goto yy18;
1078                 }
1079         }
1080 yy72:
1081         yych = *++YYCURSOR;
1082         if (yych != 'F') goto yy18;
1083 yy73:
1084         yych = *++YYCURSOR;
1085         if (yych != ';') goto yy18;
1086         ++YYCURSOR;
1087         {
1088         *p = YYCURSOR;
1089         INIT_PZVAL(*rval);
1090 
1091         if (!strncmp(start + 2, "NAN", 3)) {
1092                 ZVAL_DOUBLE(*rval, php_get_nan());
1093         } else if (!strncmp(start + 2, "INF", 3)) {
1094                 ZVAL_DOUBLE(*rval, php_get_inf());
1095         } else if (!strncmp(start + 2, "-INF", 4)) {
1096                 ZVAL_DOUBLE(*rval, -php_get_inf());
1097         }
1098 
1099         return 1;
1100 }
1101 yy76:
1102         yych = *++YYCURSOR;
1103         if (yych == 'N') goto yy73;
1104         goto yy18;
1105 yy77:
1106         yych = *++YYCURSOR;
1107         if (yych <= ',') {
1108                 if (yych != '+') goto yy18;
1109         } else {
1110                 if (yych <= '-') goto yy78;
1111                 if (yych <= '/') goto yy18;
1112                 if (yych <= '9') goto yy79;
1113                 goto yy18;
1114         }
1115 yy78:
1116         yych = *++YYCURSOR;
1117         if (yych <= '/') goto yy18;
1118         if (yych >= ':') goto yy18;
1119 yy79:
1120         ++YYCURSOR;
1121         if (YYLIMIT <= YYCURSOR) YYFILL(1);
1122         yych = *YYCURSOR;
1123         if (yych <= '/') goto yy18;
1124         if (yych <= '9') goto yy79;
1125         if (yych != ';') goto yy18;
1126         ++YYCURSOR;
1127         {
1128 #if SIZEOF_LONG == 4
1129         int digits = YYCURSOR - start - 3;
1130 
1131         if (start[2] == '-' || start[2] == '+') {
1132                 digits--;
1133         }
1134 
1135         /* Use double for large long values that were serialized on a 64-bit system */
1136         if (digits >= MAX_LENGTH_OF_LONG - 1) {
1137                 if (digits == MAX_LENGTH_OF_LONG - 1) {
1138                         int cmp = strncmp(YYCURSOR - MAX_LENGTH_OF_LONG, long_min_digits, MAX_LENGTH_OF_LONG - 1);
1139 
1140                         if (!(cmp < 0 || (cmp == 0 && start[2] == '-'))) {
1141                                 goto use_double;
1142                         }
1143                 } else {
1144                         goto use_double;
1145                 }
1146         }
1147 #endif
1148         *p = YYCURSOR;
1149         INIT_PZVAL(*rval);
1150         ZVAL_LONG(*rval, parse_iv(start + 2));
1151         return 1;
1152 }
1153 yy83:
1154         yych = *++YYCURSOR;
1155         if (yych <= '/') goto yy18;
1156         if (yych >= '2') goto yy18;
1157         yych = *++YYCURSOR;
1158         if (yych != ';') goto yy18;
1159         ++YYCURSOR;
1160         {
1161         *p = YYCURSOR;
1162         INIT_PZVAL(*rval);
1163         ZVAL_BOOL(*rval, parse_iv(start + 2));
1164         return 1;
1165 }
1166 yy87:
1167         ++YYCURSOR;
1168         {
1169         *p = YYCURSOR;
1170         INIT_PZVAL(*rval);
1171         ZVAL_NULL(*rval);
1172         return 1;
1173 }
1174 yy89:
1175         yych = *++YYCURSOR;
1176         if (yych <= ',') {
1177                 if (yych != '+') goto yy18;
1178         } else {
1179                 if (yych <= '-') goto yy90;
1180                 if (yych <= '/') goto yy18;
1181                 if (yych <= '9') goto yy91;
1182                 goto yy18;
1183         }
1184 yy90:
1185         yych = *++YYCURSOR;
1186         if (yych <= '/') goto yy18;
1187         if (yych >= ':') goto yy18;
1188 yy91:
1189         ++YYCURSOR;
1190         if (YYLIMIT <= YYCURSOR) YYFILL(1);
1191         yych = *YYCURSOR;
1192         if (yych <= '/') goto yy18;
1193         if (yych <= '9') goto yy91;
1194         if (yych != ';') goto yy18;
1195         ++YYCURSOR;
1196         {
1197         long id;
1198 
1199         *p = YYCURSOR;
1200         if (!var_hash) return 0;
1201 
1202         id = parse_iv(start + 2) - 1;
1203         if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) {
1204                 return 0;
1205         }
1206 
1207         if (*rval == *rval_ref) return 0;
1208 
1209         if (*rval != NULL) {
1210                 var_push_dtor_no_addref(var_hash, rval);
1211         }
1212         *rval = *rval_ref;
1213         Z_ADDREF_PP(rval);
1214         Z_UNSET_ISREF_PP(rval);
1215 
1216         return 1;
1217 }
1218 yy95:
1219         yych = *++YYCURSOR;
1220         if (yych <= ',') {
1221                 if (yych != '+') goto yy18;
1222         } else {
1223                 if (yych <= '-') goto yy96;
1224                 if (yych <= '/') goto yy18;
1225                 if (yych <= '9') goto yy97;
1226                 goto yy18;
1227         }
1228 yy96:
1229         yych = *++YYCURSOR;
1230         if (yych <= '/') goto yy18;
1231         if (yych >= ':') goto yy18;
1232 yy97:
1233         ++YYCURSOR;
1234         if (YYLIMIT <= YYCURSOR) YYFILL(1);
1235         yych = *YYCURSOR;
1236         if (yych <= '/') goto yy18;
1237         if (yych <= '9') goto yy97;
1238         if (yych != ';') goto yy18;
1239         ++YYCURSOR;
1240         {
1241         long id;
1242 
1243         *p = YYCURSOR;
1244         if (!var_hash) return 0;
1245 
1246         id = parse_iv(start + 2) - 1;
1247         if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) {
1248                 return 0;
1249         }
1250 
1251         if (*rval != NULL) {
1252                 var_push_dtor_no_addref(var_hash, rval);
1253         }
1254         *rval = *rval_ref;
1255         Z_ADDREF_PP(rval);
1256         Z_SET_ISREF_PP(rval);
1257 
1258         return 1;
1259 }
1260 }
1261 
1262 
1263         return 0;
1264 }

/* [<][>][^][v][top][bottom][index][help] */