File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard / var_unserializer.re
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:03:57 2014 UTC (10 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29, HEAD
php 5.4.29

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>