xref: /PHP-7.3/ext/standard/var.c (revision f0b2c2cb)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2018 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    | Authors: Jani Lehtimäki <jkl@njet.net>                               |
16    |          Thies C. Arntzen <thies@thieso.net>                         |
17    |          Sascha Schumann <sascha@schumann.cx>                        |
18    +----------------------------------------------------------------------+
19 */
20 
21 /* {{{ includes
22 */
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include "php.h"
27 #include "php_string.h"
28 #include "php_var.h"
29 #include "zend_smart_str.h"
30 #include "basic_functions.h"
31 #include "php_incomplete_class.h"
32 /* }}} */
33 
34 struct php_serialize_data {
35 	HashTable ht;
36 	uint32_t n;
37 };
38 
39 #define COMMON (is_ref ? "&" : "")
40 
php_array_element_dump(zval * zv,zend_ulong index,zend_string * key,int level)41 static void php_array_element_dump(zval *zv, zend_ulong index, zend_string *key, int level) /* {{{ */
42 {
43 	if (key == NULL) { /* numeric key */
44 		php_printf("%*c[" ZEND_LONG_FMT "]=>\n", level + 1, ' ', index);
45 	} else { /* string key */
46 		php_printf("%*c[\"", level + 1, ' ');
47 		PHPWRITE(ZSTR_VAL(key), ZSTR_LEN(key));
48 		php_printf("\"]=>\n");
49 	}
50 	php_var_dump(zv, level + 2);
51 }
52 /* }}} */
53 
php_object_property_dump(zval * zv,zend_ulong index,zend_string * key,int level)54 static void php_object_property_dump(zval *zv, zend_ulong index, zend_string *key, int level) /* {{{ */
55 {
56 	const char *prop_name, *class_name;
57 
58 	if (key == NULL) { /* numeric key */
59 		php_printf("%*c[" ZEND_LONG_FMT "]=>\n", level + 1, ' ', index);
60 	} else { /* string key */
61 		int unmangle = zend_unmangle_property_name(key, &class_name, &prop_name);
62 		php_printf("%*c[", level + 1, ' ');
63 
64 		if (class_name && unmangle == SUCCESS) {
65 			if (class_name[0] == '*') {
66 				php_printf("\"%s\":protected", prop_name);
67 			} else {
68 				php_printf("\"%s\":\"%s\":private", prop_name, class_name);
69 			}
70 		} else {
71 			php_printf("\"");
72 			PHPWRITE(ZSTR_VAL(key), ZSTR_LEN(key));
73 			php_printf("\"");
74 		}
75 		ZEND_PUTS("]=>\n");
76 	}
77 	php_var_dump(zv, level + 2);
78 }
79 /* }}} */
80 
php_var_dump(zval * struc,int level)81 PHPAPI void php_var_dump(zval *struc, int level) /* {{{ */
82 {
83 	HashTable *myht;
84 	zend_string *class_name;
85 	int is_temp;
86 	int is_ref = 0;
87 	zend_ulong num;
88 	zend_string *key;
89 	zval *val;
90 	uint32_t count;
91 
92 	if (level > 1) {
93 		php_printf("%*c", level - 1, ' ');
94 	}
95 
96 again:
97 	switch (Z_TYPE_P(struc)) {
98 		case IS_FALSE:
99 			php_printf("%sbool(false)\n", COMMON);
100 			break;
101 		case IS_TRUE:
102 			php_printf("%sbool(true)\n", COMMON);
103 			break;
104 		case IS_NULL:
105 			php_printf("%sNULL\n", COMMON);
106 			break;
107 		case IS_LONG:
108 			php_printf("%sint(" ZEND_LONG_FMT ")\n", COMMON, Z_LVAL_P(struc));
109 			break;
110 		case IS_DOUBLE:
111 			php_printf("%sfloat(%.*G)\n", COMMON, (int) EG(precision), Z_DVAL_P(struc));
112 			break;
113 		case IS_STRING:
114 			php_printf("%sstring(%zd) \"", COMMON, Z_STRLEN_P(struc));
115 			PHPWRITE(Z_STRVAL_P(struc), Z_STRLEN_P(struc));
116 			PUTS("\"\n");
117 			break;
118 		case IS_ARRAY:
119 			myht = Z_ARRVAL_P(struc);
120 			if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) {
121 				if (level > 1) {
122 					if (GC_IS_RECURSIVE(myht)) {
123 						PUTS("*RECURSION*\n");
124 						return;
125 					}
126 					GC_PROTECT_RECURSION(myht);
127 				}
128 				GC_ADDREF(myht);
129 			}
130 			count = zend_array_count(myht);
131 			php_printf("%sarray(%d) {\n", COMMON, count);
132 			ZEND_HASH_FOREACH_KEY_VAL_IND(myht, num, key, val) {
133 				php_array_element_dump(val, num, key, level);
134 			} ZEND_HASH_FOREACH_END();
135 			if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) {
136 				if (level > 1) {
137 					GC_UNPROTECT_RECURSION(myht);
138 				}
139 				GC_DELREF(myht);
140 			}
141 			if (level > 1) {
142 				php_printf("%*c", level-1, ' ');
143 			}
144 			PUTS("}\n");
145 			break;
146 		case IS_OBJECT:
147 			if (Z_IS_RECURSIVE_P(struc)) {
148 				PUTS("*RECURSION*\n");
149 				return;
150 			}
151 			Z_PROTECT_RECURSION_P(struc);
152 
153 			myht = Z_OBJDEBUG_P(struc, is_temp);
154 			class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc));
155 			php_printf("%sobject(%s)#%d (%d) {\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0);
156 			zend_string_release_ex(class_name, 0);
157 
158 			if (myht) {
159 				zend_ulong num;
160 				zend_string *key;
161 				zval *val;
162 
163 				ZEND_HASH_FOREACH_KEY_VAL_IND(myht, num, key, val) {
164 					php_object_property_dump(val, num, key, level);
165 				} ZEND_HASH_FOREACH_END();
166 				if (is_temp) {
167 					zend_hash_destroy(myht);
168 					efree(myht);
169 				}
170 			}
171 			if (level > 1) {
172 				php_printf("%*c", level-1, ' ');
173 			}
174 			PUTS("}\n");
175 			Z_UNPROTECT_RECURSION_P(struc);
176 			break;
177 		case IS_RESOURCE: {
178 			const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(struc));
179 			php_printf("%sresource(%d) of type (%s)\n", COMMON, Z_RES_P(struc)->handle, type_name ? type_name : "Unknown");
180 			break;
181 		}
182 		case IS_REFERENCE:
183 			//??? hide references with refcount==1 (for compatibility)
184 			if (Z_REFCOUNT_P(struc) > 1) {
185 				is_ref = 1;
186 			}
187 			struc = Z_REFVAL_P(struc);
188 			goto again;
189 			break;
190 		default:
191 			php_printf("%sUNKNOWN:0\n", COMMON);
192 			break;
193 	}
194 }
195 /* }}} */
196 
197 /* {{{ proto void var_dump(mixed var)
198    Dumps a string representation of variable to output */
PHP_FUNCTION(var_dump)199 PHP_FUNCTION(var_dump)
200 {
201 	zval *args;
202 	int argc;
203 	int	i;
204 
205 	ZEND_PARSE_PARAMETERS_START(1, -1)
206 		Z_PARAM_VARIADIC('+', args, argc)
207 	ZEND_PARSE_PARAMETERS_END();
208 
209 	for (i = 0; i < argc; i++) {
210 		php_var_dump(&args[i], 1);
211 	}
212 }
213 /* }}} */
214 
zval_array_element_dump(zval * zv,zend_ulong index,zend_string * key,int level)215 static void zval_array_element_dump(zval *zv, zend_ulong index, zend_string *key, int level) /* {{{ */
216 {
217 	if (key == NULL) { /* numeric key */
218 		php_printf("%*c[" ZEND_LONG_FMT "]=>\n", level + 1, ' ', index);
219 	} else { /* string key */
220 		php_printf("%*c[\"", level + 1, ' ');
221 		PHPWRITE(ZSTR_VAL(key), ZSTR_LEN(key));
222 		php_printf("\"]=>\n");
223 	}
224 	php_debug_zval_dump(zv, level + 2);
225 }
226 /* }}} */
227 
zval_object_property_dump(zval * zv,zend_ulong index,zend_string * key,int level)228 static void zval_object_property_dump(zval *zv, zend_ulong index, zend_string *key, int level) /* {{{ */
229 {
230 	const char *prop_name, *class_name;
231 
232 	if (key == NULL) { /* numeric key */
233 		php_printf("%*c[" ZEND_LONG_FMT "]=>\n", level + 1, ' ', index);
234 	} else { /* string key */
235 		zend_unmangle_property_name(key, &class_name, &prop_name);
236 		php_printf("%*c[", level + 1, ' ');
237 
238 		if (class_name) {
239 			if (class_name[0] == '*') {
240 				php_printf("\"%s\":protected", prop_name);
241 			} else {
242 				php_printf("\"%s\":\"%s\":private", prop_name, class_name);
243 			}
244 		} else {
245 			php_printf("\"%s\"", prop_name);
246 		}
247 		ZEND_PUTS("]=>\n");
248 	}
249 	php_debug_zval_dump(zv, level + 2);
250 }
251 /* }}} */
252 
php_debug_zval_dump(zval * struc,int level)253 PHPAPI void php_debug_zval_dump(zval *struc, int level) /* {{{ */
254 {
255 	HashTable *myht = NULL;
256 	zend_string *class_name;
257 	int is_temp = 0;
258 	int is_ref = 0;
259 	zend_ulong index;
260 	zend_string *key;
261 	zval *val;
262 	uint32_t count;
263 
264 	if (level > 1) {
265 		php_printf("%*c", level - 1, ' ');
266 	}
267 
268 again:
269 	switch (Z_TYPE_P(struc)) {
270 	case IS_FALSE:
271 		php_printf("%sbool(false)\n", COMMON);
272 		break;
273 	case IS_TRUE:
274 		php_printf("%sbool(true)\n", COMMON);
275 		break;
276 	case IS_NULL:
277 		php_printf("%sNULL\n", COMMON);
278 		break;
279 	case IS_LONG:
280 		php_printf("%sint(" ZEND_LONG_FMT ")\n", COMMON, Z_LVAL_P(struc));
281 		break;
282 	case IS_DOUBLE:
283 		php_printf("%sfloat(%.*G)\n", COMMON, (int) EG(precision), Z_DVAL_P(struc));
284 		break;
285 	case IS_STRING:
286 		php_printf("%sstring(%zd) \"", COMMON, Z_STRLEN_P(struc));
287 		PHPWRITE(Z_STRVAL_P(struc), Z_STRLEN_P(struc));
288 		php_printf("\" refcount(%u)\n", Z_REFCOUNTED_P(struc) ? Z_REFCOUNT_P(struc) : 1);
289 		break;
290 	case IS_ARRAY:
291 		myht = Z_ARRVAL_P(struc);
292 		if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) {
293 			if (level > 1) {
294 				if (GC_IS_RECURSIVE(myht)) {
295 					PUTS("*RECURSION*\n");
296 					return;
297 				}
298 				GC_PROTECT_RECURSION(myht);
299 			}
300 			GC_ADDREF(myht);
301 		}
302 		count = zend_array_count(myht);
303 		php_printf("%sarray(%d) refcount(%u){\n", COMMON, count, Z_REFCOUNTED_P(struc) ? Z_REFCOUNT_P(struc) - 1 : 1);
304 		ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
305 			zval_array_element_dump(val, index, key, level);
306 		} ZEND_HASH_FOREACH_END();
307 		if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) {
308 			if (level > 1) {
309 				GC_UNPROTECT_RECURSION(myht);
310 			}
311 			GC_DELREF(myht);
312 		}
313 		if (is_temp) {
314 			zend_hash_destroy(myht);
315 			efree(myht);
316 		}
317 		if (level > 1) {
318 			php_printf("%*c", level - 1, ' ');
319 		}
320 		PUTS("}\n");
321 		break;
322 	case IS_OBJECT:
323 		myht = Z_OBJDEBUG_P(struc, is_temp);
324 		if (myht) {
325 			if (GC_IS_RECURSIVE(myht)) {
326 				PUTS("*RECURSION*\n");
327 				return;
328 			}
329 			GC_PROTECT_RECURSION(myht);
330 		}
331 		class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc));
332 		php_printf("%sobject(%s)#%d (%d) refcount(%u){\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0, Z_REFCOUNT_P(struc));
333 		zend_string_release_ex(class_name, 0);
334 		if (myht) {
335 			ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
336 				zval_object_property_dump(val, index, key, level);
337 			} ZEND_HASH_FOREACH_END();
338 			GC_UNPROTECT_RECURSION(myht);
339 			if (is_temp) {
340 				zend_hash_destroy(myht);
341 				efree(myht);
342 			}
343 		}
344 		if (level > 1) {
345 			php_printf("%*c", level - 1, ' ');
346 		}
347 		PUTS("}\n");
348 		break;
349 	case IS_RESOURCE: {
350 		const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(struc));
351 		php_printf("%sresource(%d) of type (%s) refcount(%u)\n", COMMON, Z_RES_P(struc)->handle, type_name ? type_name : "Unknown", Z_REFCOUNT_P(struc));
352 		break;
353 	}
354 	case IS_REFERENCE:
355 		//??? hide references with refcount==1 (for compatibility)
356 		if (Z_REFCOUNT_P(struc) > 1) {
357 			is_ref = 1;
358 		}
359 		struc = Z_REFVAL_P(struc);
360 		goto again;
361 	default:
362 		php_printf("%sUNKNOWN:0\n", COMMON);
363 		break;
364 	}
365 }
366 /* }}} */
367 
368 /* {{{ proto void debug_zval_dump(mixed var)
369    Dumps a string representation of an internal zend value to output. */
PHP_FUNCTION(debug_zval_dump)370 PHP_FUNCTION(debug_zval_dump)
371 {
372 	zval *args;
373 	int argc;
374 	int	i;
375 
376 	ZEND_PARSE_PARAMETERS_START(1, -1)
377 		Z_PARAM_VARIADIC('+', args, argc)
378 	ZEND_PARSE_PARAMETERS_END();
379 
380 	for (i = 0; i < argc; i++) {
381 		php_debug_zval_dump(&args[i], 1);
382 	}
383 }
384 /* }}} */
385 
386 #define buffer_append_spaces(buf, num_spaces) \
387 	do { \
388 		char *tmp_spaces; \
389 		size_t tmp_spaces_len; \
390 		tmp_spaces_len = spprintf(&tmp_spaces, 0,"%*c", num_spaces, ' '); \
391 		smart_str_appendl(buf, tmp_spaces, tmp_spaces_len); \
392 		efree(tmp_spaces); \
393 	} while(0);
394 
php_array_element_export(zval * zv,zend_ulong index,zend_string * key,int level,smart_str * buf)395 static void php_array_element_export(zval *zv, zend_ulong index, zend_string *key, int level, smart_str *buf) /* {{{ */
396 {
397 	if (key == NULL) { /* numeric key */
398 		buffer_append_spaces(buf, level+1);
399 		smart_str_append_long(buf, (zend_long) index);
400 		smart_str_appendl(buf, " => ", 4);
401 
402 	} else { /* string key */
403 		zend_string *tmp_str;
404 		zend_string *ckey = php_addcslashes(key, "'\\", 2);
405 		tmp_str = php_str_to_str(ZSTR_VAL(ckey), ZSTR_LEN(ckey), "\0", 1, "' . \"\\0\" . '", 12);
406 
407 		buffer_append_spaces(buf, level + 1);
408 
409 		smart_str_appendc(buf, '\'');
410 		smart_str_append(buf, tmp_str);
411 		smart_str_appendl(buf, "' => ", 5);
412 
413 		zend_string_free(ckey);
414 		zend_string_free(tmp_str);
415 	}
416 	php_var_export_ex(zv, level + 2, buf);
417 
418 	smart_str_appendc(buf, ',');
419 	smart_str_appendc(buf, '\n');
420 }
421 /* }}} */
422 
php_object_element_export(zval * zv,zend_ulong index,zend_string * key,int level,smart_str * buf)423 static void php_object_element_export(zval *zv, zend_ulong index, zend_string *key, int level, smart_str *buf) /* {{{ */
424 {
425 	buffer_append_spaces(buf, level + 2);
426 	if (key != NULL) {
427 		const char *class_name, *prop_name;
428 		size_t prop_name_len;
429 		zend_string *pname_esc;
430 
431 		zend_unmangle_property_name_ex(key, &class_name, &prop_name, &prop_name_len);
432 		pname_esc = php_addcslashes_str(prop_name, prop_name_len, "'\\", 2);
433 
434 		smart_str_appendc(buf, '\'');
435 		smart_str_append(buf, pname_esc);
436 		smart_str_appendc(buf, '\'');
437 		zend_string_release_ex(pname_esc, 0);
438 	} else {
439 		smart_str_append_long(buf, (zend_long) index);
440 	}
441 	smart_str_appendl(buf, " => ", 4);
442 	php_var_export_ex(zv, level + 2, buf);
443 	smart_str_appendc(buf, ',');
444 	smart_str_appendc(buf, '\n');
445 }
446 /* }}} */
447 
php_var_export_ex(zval * struc,int level,smart_str * buf)448 PHPAPI void php_var_export_ex(zval *struc, int level, smart_str *buf) /* {{{ */
449 {
450 	HashTable *myht;
451 	char tmp_str[PHP_DOUBLE_MAX_LENGTH];
452 	zend_string *ztmp, *ztmp2;
453 	zend_ulong index;
454 	zend_string *key;
455 	zval *val;
456 
457 again:
458 	switch (Z_TYPE_P(struc)) {
459 		case IS_FALSE:
460 			smart_str_appendl(buf, "false", 5);
461 			break;
462 		case IS_TRUE:
463 			smart_str_appendl(buf, "true", 4);
464 			break;
465 		case IS_NULL:
466 			smart_str_appendl(buf, "NULL", 4);
467 			break;
468 		case IS_LONG:
469 			/* INT_MIN as a literal will be parsed as a float. Emit something like
470 			 * -9223372036854775807-1 to avoid this. */
471 			if (Z_LVAL_P(struc) == ZEND_LONG_MIN) {
472 				smart_str_append_long(buf, ZEND_LONG_MIN+1);
473 				smart_str_appends(buf, "-1");
474 				break;
475 			}
476 			smart_str_append_long(buf, Z_LVAL_P(struc));
477 			break;
478 		case IS_DOUBLE:
479 			php_gcvt(Z_DVAL_P(struc), (int)PG(serialize_precision), '.', 'E', tmp_str);
480 			smart_str_appends(buf, tmp_str);
481 			/* Without a decimal point, PHP treats a number literal as an int.
482 			 * This check even works for scientific notation, because the
483 			 * mantissa always contains a decimal point.
484 			 * We need to check for finiteness, because INF, -INF and NAN
485 			 * must not have a decimal point added.
486 			 */
487 			if (zend_finite(Z_DVAL_P(struc)) && NULL == strchr(tmp_str, '.')) {
488 				smart_str_appendl(buf, ".0", 2);
489 			}
490 			break;
491 		case IS_STRING:
492 			ztmp = php_addcslashes(Z_STR_P(struc), "'\\", 2);
493 			ztmp2 = php_str_to_str(ZSTR_VAL(ztmp), ZSTR_LEN(ztmp), "\0", 1, "' . \"\\0\" . '", 12);
494 
495 			smart_str_appendc(buf, '\'');
496 			smart_str_append(buf, ztmp2);
497 			smart_str_appendc(buf, '\'');
498 
499 			zend_string_free(ztmp);
500 			zend_string_free(ztmp2);
501 			break;
502 		case IS_ARRAY:
503 			myht = Z_ARRVAL_P(struc);
504 			if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) {
505 				if (GC_IS_RECURSIVE(myht)) {
506 					smart_str_appendl(buf, "NULL", 4);
507 					zend_error(E_WARNING, "var_export does not handle circular references");
508 					return;
509 				}
510 				GC_ADDREF(myht);
511 				GC_PROTECT_RECURSION(myht);
512 			}
513 			if (level > 1) {
514 				smart_str_appendc(buf, '\n');
515 				buffer_append_spaces(buf, level - 1);
516 			}
517 			smart_str_appendl(buf, "array (\n", 8);
518 			ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
519 				php_array_element_export(val, index, key, level, buf);
520 			} ZEND_HASH_FOREACH_END();
521 			if (!(GC_FLAGS(myht) & GC_IMMUTABLE)) {
522 				GC_UNPROTECT_RECURSION(myht);
523 				GC_DELREF(myht);
524 			}
525 			if (level > 1) {
526 				buffer_append_spaces(buf, level - 1);
527 			}
528 			smart_str_appendc(buf, ')');
529 
530 			break;
531 
532 		case IS_OBJECT:
533 			myht = Z_OBJPROP_P(struc);
534 			if (myht) {
535 				if (GC_IS_RECURSIVE(myht)) {
536 					smart_str_appendl(buf, "NULL", 4);
537 					zend_error(E_WARNING, "var_export does not handle circular references");
538 					return;
539 				} else {
540 					GC_TRY_PROTECT_RECURSION(myht);
541 				}
542 			}
543 			if (level > 1) {
544 				smart_str_appendc(buf, '\n');
545 				buffer_append_spaces(buf, level - 1);
546 			}
547 
548 			/* stdClass has no __set_state method, but can be casted to */
549 			if (Z_OBJCE_P(struc) == zend_standard_class_def) {
550 				smart_str_appendl(buf, "(object) array(\n", 16);
551 			} else {
552 				smart_str_append(buf, Z_OBJCE_P(struc)->name);
553 				smart_str_appendl(buf, "::__set_state(array(\n", 21);
554 			}
555 
556 			if (myht) {
557 				ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, val) {
558 					php_object_element_export(val, index, key, level, buf);
559 				} ZEND_HASH_FOREACH_END();
560 				GC_TRY_UNPROTECT_RECURSION(myht);
561 			}
562 			if (level > 1) {
563 				buffer_append_spaces(buf, level - 1);
564 			}
565 			if (Z_OBJCE_P(struc) == zend_standard_class_def) {
566 				smart_str_appendc(buf, ')');
567 			} else {
568 				smart_str_appendl(buf, "))", 2);
569 			}
570 
571 			break;
572 		case IS_REFERENCE:
573 			struc = Z_REFVAL_P(struc);
574 			goto again;
575 			break;
576 		default:
577 			smart_str_appendl(buf, "NULL", 4);
578 			break;
579 	}
580 }
581 /* }}} */
582 
583 /* FOR BC reasons, this will always perform and then print */
php_var_export(zval * struc,int level)584 PHPAPI void php_var_export(zval *struc, int level) /* {{{ */
585 {
586 	smart_str buf = {0};
587 	php_var_export_ex(struc, level, &buf);
588 	smart_str_0(&buf);
589 	PHPWRITE(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s));
590 	smart_str_free(&buf);
591 }
592 /* }}} */
593 
594 /* {{{ proto mixed var_export(mixed var [, bool return])
595    Outputs or returns a string representation of a variable */
PHP_FUNCTION(var_export)596 PHP_FUNCTION(var_export)
597 {
598 	zval *var;
599 	zend_bool return_output = 0;
600 	smart_str buf = {0};
601 
602 	ZEND_PARSE_PARAMETERS_START(1, 2)
603 		Z_PARAM_ZVAL(var)
604 		Z_PARAM_OPTIONAL
605 		Z_PARAM_BOOL(return_output)
606 	ZEND_PARSE_PARAMETERS_END();
607 
608 	php_var_export_ex(var, 1, &buf);
609 	smart_str_0 (&buf);
610 
611 	if (return_output) {
612 		RETURN_NEW_STR(buf.s);
613 	} else {
614 		PHPWRITE(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s));
615 		smart_str_free(&buf);
616 	}
617 }
618 /* }}} */
619 
620 static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_data_t var_hash);
621 
php_add_var_hash(php_serialize_data_t data,zval * var)622 static inline zend_long php_add_var_hash(php_serialize_data_t data, zval *var) /* {{{ */
623 {
624 	zval *zv;
625 	zend_ulong key;
626 	zend_bool is_ref = Z_ISREF_P(var);
627 
628 	data->n += 1;
629 
630 	if (!is_ref && Z_TYPE_P(var) != IS_OBJECT) {
631 		return 0;
632 	}
633 
634 	/* References to objects are treated as if the reference didn't exist */
635 	if (is_ref && Z_TYPE_P(Z_REFVAL_P(var)) == IS_OBJECT) {
636 		var = Z_REFVAL_P(var);
637 	}
638 
639 	/* Index for the variable is stored using the numeric value of the pointer to
640 	 * the zend_refcounted struct */
641 	key = (zend_ulong) (zend_uintptr_t) Z_COUNTED_P(var);
642 	zv = zend_hash_index_find(&data->ht, key);
643 
644 	if (zv) {
645 		/* References are only counted once, undo the data->n increment above */
646 		if (is_ref) {
647 			data->n -= 1;
648 		}
649 
650 		return Z_LVAL_P(zv);
651 	} else {
652 		zval zv_n;
653 		ZVAL_LONG(&zv_n, data->n);
654 		zend_hash_index_add_new(&data->ht, key, &zv_n);
655 
656 		/* Additionally to the index, we also store the variable, to ensure that it is
657 		 * not destroyed during serialization and its pointer reused. The variable is
658 		 * stored at the numeric value of the pointer + 1, which cannot be the location
659 		 * of another zend_refcounted structure. */
660 		zend_hash_index_add_new(&data->ht, key + 1, var);
661 		Z_ADDREF_P(var);
662 
663 		return 0;
664 	}
665 }
666 /* }}} */
667 
php_var_serialize_long(smart_str * buf,zend_long val)668 static inline void php_var_serialize_long(smart_str *buf, zend_long val) /* {{{ */
669 {
670 	smart_str_appendl(buf, "i:", 2);
671 	smart_str_append_long(buf, val);
672 	smart_str_appendc(buf, ';');
673 }
674 /* }}} */
675 
php_var_serialize_string(smart_str * buf,char * str,size_t len)676 static inline void php_var_serialize_string(smart_str *buf, char *str, size_t len) /* {{{ */
677 {
678 	smart_str_appendl(buf, "s:", 2);
679 	smart_str_append_unsigned(buf, len);
680 	smart_str_appendl(buf, ":\"", 2);
681 	smart_str_appendl(buf, str, len);
682 	smart_str_appendl(buf, "\";", 2);
683 }
684 /* }}} */
685 
php_var_serialize_class_name(smart_str * buf,zval * struc)686 static inline zend_bool php_var_serialize_class_name(smart_str *buf, zval *struc) /* {{{ */
687 {
688 	PHP_CLASS_ATTRIBUTES;
689 
690 	PHP_SET_CLASS_ATTRIBUTES(struc);
691 	smart_str_appendl(buf, "O:", 2);
692 	smart_str_append_unsigned(buf, ZSTR_LEN(class_name));
693 	smart_str_appendl(buf, ":\"", 2);
694 	smart_str_append(buf, class_name);
695 	smart_str_appendl(buf, "\":", 2);
696 	PHP_CLEANUP_CLASS_ATTRIBUTES();
697 	return incomplete_class;
698 }
699 /* }}} */
700 
php_var_serialize_call_sleep(zval * retval,zval * struc)701 static int php_var_serialize_call_sleep(zval *retval, zval *struc) /* {{{ */
702 {
703 	zval fname;
704 	int res;
705 
706 	ZVAL_STRINGL(&fname, "__sleep", sizeof("__sleep") - 1);
707 	BG(serialize_lock)++;
708 	res = call_user_function(CG(function_table), struc, &fname, retval, 0, 0);
709 	BG(serialize_lock)--;
710 	zval_ptr_dtor_str(&fname);
711 
712 	if (res == FAILURE || Z_ISUNDEF_P(retval)) {
713 		zval_ptr_dtor(retval);
714 		return FAILURE;
715 	}
716 
717 	if (!HASH_OF(retval)) {
718 		zval_ptr_dtor(retval);
719 		php_error_docref(NULL, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize");
720 		return FAILURE;
721 	}
722 
723 	return SUCCESS;
724 }
725 /* }}} */
726 
php_var_serialize_collect_names(HashTable * ht,HashTable * src)727 static void php_var_serialize_collect_names(HashTable *ht, HashTable *src) /* {{{ */
728 {
729 	zval *val;
730 	zend_string *name, *tmp_name;
731 
732 	zend_hash_init(ht, zend_hash_num_elements(src), NULL, NULL, 0);
733 	ZEND_HASH_FOREACH_VAL(src, val) {
734 		if (Z_TYPE_P(val) != IS_STRING) {
735 			php_error_docref(NULL, E_NOTICE,
736 					"__sleep should return an array only containing the names of instance-variables to serialize.");
737 		}
738 
739 		name = zval_get_tmp_string(val, &tmp_name);
740 		if (zend_hash_exists(ht, name)) {
741 			php_error_docref(NULL, E_NOTICE,
742 					"\"%s\" is returned from __sleep multiple times", ZSTR_VAL(name));
743 			zend_tmp_string_release(tmp_name);
744 			continue;
745 		}
746 		zend_hash_add_empty_element(ht, name);
747 		zend_tmp_string_release(tmp_name);
748 	} ZEND_HASH_FOREACH_END();
749 }
750 /* }}} */
751 
php_var_serialize_class(smart_str * buf,zval * struc,zval * retval_ptr,php_serialize_data_t var_hash)752 static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_ptr, php_serialize_data_t var_hash) /* {{{ */
753 {
754 	zend_class_entry *ce = Z_OBJCE_P(struc);
755 	HashTable names, *propers;
756 	zval nval;
757 	zend_string *name;
758 
759 	php_var_serialize_class_name(buf, struc);
760 	php_var_serialize_collect_names(&names, HASH_OF(retval_ptr));
761 
762 	smart_str_append_unsigned(buf, zend_hash_num_elements(&names));
763 	smart_str_appendl(buf, ":{", 2);
764 
765 	ZVAL_NULL(&nval);
766 	propers = Z_OBJPROP_P(struc);
767 
768 	ZEND_HASH_FOREACH_STR_KEY(&names, name) {
769 		zend_string *prot_name, *priv_name;
770 
771 		zval *val = zend_hash_find_ex(propers, name, 1);
772 		if (val != NULL) {
773 			if (Z_TYPE_P(val) == IS_INDIRECT) {
774 				val = Z_INDIRECT_P(val);
775 				if (Z_TYPE_P(val) == IS_UNDEF) {
776 					goto undef_prop;
777 				}
778 			}
779 
780 			php_var_serialize_string(buf, ZSTR_VAL(name), ZSTR_LEN(name));
781 			php_var_serialize_intern(buf, val, var_hash);
782 			continue;
783 		}
784 
785 		priv_name = zend_mangle_property_name(
786 				ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), ZSTR_VAL(name), ZSTR_LEN(name), 0);
787 		val = zend_hash_find(propers, priv_name);
788 		if (val != NULL) {
789 			if (Z_TYPE_P(val) == IS_INDIRECT) {
790 				val = Z_INDIRECT_P(val);
791 				if (Z_ISUNDEF_P(val)) {
792 					zend_string_free(priv_name);
793 					goto undef_prop;
794 				}
795 			}
796 
797 			php_var_serialize_string(buf, ZSTR_VAL(priv_name), ZSTR_LEN(priv_name));
798 			zend_string_free(priv_name);
799 			php_var_serialize_intern(buf, val, var_hash);
800 			continue;
801 		}
802 		zend_string_free(priv_name);
803 
804 		prot_name = zend_mangle_property_name(
805 				"*", 1, ZSTR_VAL(name), ZSTR_LEN(name), 0);
806 		val = zend_hash_find(propers, prot_name);
807 		if (val != NULL) {
808 			if (Z_TYPE_P(val) == IS_INDIRECT) {
809 				val = Z_INDIRECT_P(val);
810 				if (Z_TYPE_P(val) == IS_UNDEF) {
811 					zend_string_free(prot_name);
812 					goto undef_prop;
813 				}
814 			}
815 
816 			php_var_serialize_string(buf, ZSTR_VAL(prot_name), ZSTR_LEN(prot_name));
817 			zend_string_free(prot_name);
818 			php_var_serialize_intern(buf, val, var_hash);
819 			continue;
820 		}
821 		zend_string_free(prot_name);
822 
823 undef_prop:
824 		php_var_serialize_string(buf, ZSTR_VAL(name), ZSTR_LEN(name));
825 		php_var_serialize_intern(buf, &nval, var_hash);
826 		php_error_docref(NULL, E_NOTICE,
827 				"\"%s\" returned as member variable from __sleep() but does not exist", ZSTR_VAL(name));
828 	} ZEND_HASH_FOREACH_END();
829 	smart_str_appendc(buf, '}');
830 
831 	zend_hash_destroy(&names);
832 }
833 /* }}} */
834 
php_var_serialize_intern(smart_str * buf,zval * struc,php_serialize_data_t var_hash)835 static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_data_t var_hash) /* {{{ */
836 {
837 	zend_long var_already;
838 	HashTable *myht;
839 
840 	if (EG(exception)) {
841 		return;
842 	}
843 
844 	if (var_hash && (var_already = php_add_var_hash(var_hash, struc))) {
845 		if (var_already == -1) {
846 			/* Reference to an object that failed to serialize, replace with null. */
847 			smart_str_appendl(buf, "N;", 2);
848 			return;
849 		} else if (Z_ISREF_P(struc)) {
850 			smart_str_appendl(buf, "R:", 2);
851 			smart_str_append_long(buf, var_already);
852 			smart_str_appendc(buf, ';');
853 			return;
854 		} else if (Z_TYPE_P(struc) == IS_OBJECT) {
855 			smart_str_appendl(buf, "r:", 2);
856 			smart_str_append_long(buf, var_already);
857 			smart_str_appendc(buf, ';');
858 			return;
859 		}
860 	}
861 
862 again:
863 	switch (Z_TYPE_P(struc)) {
864 		case IS_FALSE:
865 			smart_str_appendl(buf, "b:0;", 4);
866 			return;
867 
868 		case IS_TRUE:
869 			smart_str_appendl(buf, "b:1;", 4);
870 			return;
871 
872 		case IS_NULL:
873 			smart_str_appendl(buf, "N;", 2);
874 			return;
875 
876 		case IS_LONG:
877 			php_var_serialize_long(buf, Z_LVAL_P(struc));
878 			return;
879 
880 		case IS_DOUBLE: {
881 			char tmp_str[PHP_DOUBLE_MAX_LENGTH];
882 			smart_str_appendl(buf, "d:", 2);
883 			php_gcvt(Z_DVAL_P(struc), (int)PG(serialize_precision), '.', 'E', tmp_str);
884 			smart_str_appends(buf, tmp_str);
885 			smart_str_appendc(buf, ';');
886 			return;
887 		}
888 
889 		case IS_STRING:
890 			php_var_serialize_string(buf, Z_STRVAL_P(struc), Z_STRLEN_P(struc));
891 			return;
892 
893 		case IS_OBJECT: {
894 				zend_class_entry *ce = Z_OBJCE_P(struc);
895 
896 				if (ce->serialize != NULL) {
897 					/* has custom handler */
898 					unsigned char *serialized_data = NULL;
899 					size_t serialized_length;
900 
901 					if (ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash) == SUCCESS) {
902 						smart_str_appendl(buf, "C:", 2);
903 						smart_str_append_unsigned(buf, ZSTR_LEN(Z_OBJCE_P(struc)->name));
904 						smart_str_appendl(buf, ":\"", 2);
905 						smart_str_append(buf, Z_OBJCE_P(struc)->name);
906 						smart_str_appendl(buf, "\":", 2);
907 
908 						smart_str_append_unsigned(buf, serialized_length);
909 						smart_str_appendl(buf, ":{", 2);
910 						smart_str_appendl(buf, (char *) serialized_data, serialized_length);
911 						smart_str_appendc(buf, '}');
912 					} else {
913 						/* Mark this value in the var_hash, to avoid creating references to it. */
914 						zval *var_idx = zend_hash_index_find(&var_hash->ht,
915 							(zend_ulong) (zend_uintptr_t) Z_COUNTED_P(struc));
916 						ZVAL_LONG(var_idx, -1);
917 						smart_str_appendl(buf, "N;", 2);
918 					}
919 					if (serialized_data) {
920 						efree(serialized_data);
921 					}
922 					return;
923 				}
924 
925 				if (ce != PHP_IC_ENTRY && zend_hash_str_exists(&ce->function_table, "__sleep", sizeof("__sleep")-1)) {
926 					zval retval, tmp;
927 					ZVAL_COPY(&tmp, struc);
928 
929 					if (php_var_serialize_call_sleep(&retval, &tmp) == FAILURE) {
930 						if (!EG(exception)) {
931 							/* we should still add element even if it's not OK,
932 							 * since we already wrote the length of the array before */
933 							smart_str_appendl(buf, "N;", 2);
934 						}
935 						zval_ptr_dtor(&tmp);
936 						return;
937 					}
938 
939 					php_var_serialize_class(buf, &tmp, &retval, var_hash);
940 					zval_ptr_dtor(&retval);
941 					zval_ptr_dtor(&tmp);
942 					return;
943 				}
944 
945 				/* fall-through */
946 			}
947 		case IS_ARRAY: {
948 			uint32_t i;
949 			zend_bool incomplete_class = 0;
950 			if (Z_TYPE_P(struc) == IS_ARRAY) {
951 				smart_str_appendl(buf, "a:", 2);
952 				myht = Z_ARRVAL_P(struc);
953 				i = zend_array_count(myht);
954 			} else {
955 				incomplete_class = php_var_serialize_class_name(buf, struc);
956 				myht = Z_OBJPROP_P(struc);
957 				/* count after serializing name, since php_var_serialize_class_name
958 				 * changes the count if the variable is incomplete class */
959 				i = zend_array_count(myht);
960 				if (i > 0 && incomplete_class) {
961 					--i;
962 				}
963 			}
964 			smart_str_append_unsigned(buf, i);
965 			smart_str_appendl(buf, ":{", 2);
966 			if (i > 0) {
967 				zend_string *key;
968 				zval *data;
969 				zend_ulong index;
970 
971 				ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, data) {
972 
973 					if (incomplete_class && strcmp(ZSTR_VAL(key), MAGIC_MEMBER) == 0) {
974 						continue;
975 					}
976 
977 					if (!key) {
978 						php_var_serialize_long(buf, index);
979 					} else {
980 						php_var_serialize_string(buf, ZSTR_VAL(key), ZSTR_LEN(key));
981 					}
982 
983 					if (Z_ISREF_P(data) && Z_REFCOUNT_P(data) == 1) {
984 						data = Z_REFVAL_P(data);
985 					}
986 
987 					/* we should still add element even if it's not OK,
988 					 * since we already wrote the length of the array before */
989 					if (Z_TYPE_P(data) == IS_ARRAY) {
990 						if (UNEXPECTED(Z_IS_RECURSIVE_P(data))
991 							|| UNEXPECTED(Z_TYPE_P(struc) == IS_ARRAY && Z_ARR_P(data) == Z_ARR_P(struc))) {
992 							php_add_var_hash(var_hash, struc);
993 							smart_str_appendl(buf, "N;", 2);
994 						} else {
995 							if (Z_REFCOUNTED_P(data)) {
996 								Z_PROTECT_RECURSION_P(data);
997 							}
998 							php_var_serialize_intern(buf, data, var_hash);
999 							if (Z_REFCOUNTED_P(data)) {
1000 								Z_UNPROTECT_RECURSION_P(data);
1001 							}
1002 						}
1003 					} else {
1004 						php_var_serialize_intern(buf, data, var_hash);
1005 					}
1006 				} ZEND_HASH_FOREACH_END();
1007 			}
1008 			smart_str_appendc(buf, '}');
1009 			return;
1010 		}
1011 		case IS_REFERENCE:
1012 			struc = Z_REFVAL_P(struc);
1013 			goto again;
1014 		default:
1015 			smart_str_appendl(buf, "i:0;", 4);
1016 			return;
1017 	}
1018 }
1019 /* }}} */
1020 
php_var_serialize(smart_str * buf,zval * struc,php_serialize_data_t * data)1021 PHPAPI void php_var_serialize(smart_str *buf, zval *struc, php_serialize_data_t *data) /* {{{ */
1022 {
1023 	php_var_serialize_intern(buf, struc, *data);
1024 	smart_str_0(buf);
1025 }
1026 /* }}} */
1027 
php_var_serialize_init()1028 PHPAPI php_serialize_data_t php_var_serialize_init() {
1029 	struct php_serialize_data *d;
1030 	/* fprintf(stderr, "SERIALIZE_INIT      == lock: %u, level: %u\n", BG(serialize_lock), BG(serialize).level); */
1031 	if (BG(serialize_lock) || !BG(serialize).level) {
1032 		d = emalloc(sizeof(struct php_serialize_data));
1033 		zend_hash_init(&d->ht, 16, NULL, ZVAL_PTR_DTOR, 0);
1034 		d->n = 0;
1035 		if (!BG(serialize_lock)) {
1036 			BG(serialize).data = d;
1037 			BG(serialize).level = 1;
1038 		}
1039 	} else {
1040 		d = BG(serialize).data;
1041 		++BG(serialize).level;
1042 	}
1043 	return d;
1044 }
1045 
php_var_serialize_destroy(php_serialize_data_t d)1046 PHPAPI void php_var_serialize_destroy(php_serialize_data_t d) {
1047 	/* fprintf(stderr, "SERIALIZE_DESTROY   == lock: %u, level: %u\n", BG(serialize_lock), BG(serialize).level); */
1048 	if (BG(serialize_lock) || BG(serialize).level == 1) {
1049 		zend_hash_destroy(&d->ht);
1050 		efree(d);
1051 	}
1052 	if (!BG(serialize_lock) && !--BG(serialize).level) {
1053 		BG(serialize).data = NULL;
1054 	}
1055 }
1056 
1057 /* {{{ proto string serialize(mixed variable)
1058    Returns a string representation of variable (which can later be unserialized) */
PHP_FUNCTION(serialize)1059 PHP_FUNCTION(serialize)
1060 {
1061 	zval *struc;
1062 	php_serialize_data_t var_hash;
1063 	smart_str buf = {0};
1064 
1065 	ZEND_PARSE_PARAMETERS_START(1, 1)
1066 		Z_PARAM_ZVAL(struc)
1067 	ZEND_PARSE_PARAMETERS_END();
1068 
1069 	PHP_VAR_SERIALIZE_INIT(var_hash);
1070 	php_var_serialize(&buf, struc, &var_hash);
1071 	PHP_VAR_SERIALIZE_DESTROY(var_hash);
1072 
1073 	if (EG(exception)) {
1074 		smart_str_free(&buf);
1075 		RETURN_FALSE;
1076 	}
1077 
1078 	if (buf.s) {
1079 		RETURN_NEW_STR(buf.s);
1080 	} else {
1081 		RETURN_NULL();
1082 	}
1083 }
1084 /* }}} */
1085 
1086 /* {{{ proto mixed unserialize(string variable_representation[, array allowed_classes])
1087    Takes a string representation of variable and recreates it */
PHP_FUNCTION(unserialize)1088 PHP_FUNCTION(unserialize)
1089 {
1090 	char *buf = NULL;
1091 	size_t buf_len;
1092 	const unsigned char *p;
1093 	php_unserialize_data_t var_hash;
1094 	zval *options = NULL, *classes = NULL;
1095 	zval *retval;
1096 	HashTable *class_hash = NULL, *prev_class_hash;
1097 
1098 	ZEND_PARSE_PARAMETERS_START(1, 2)
1099 		Z_PARAM_STRING(buf, buf_len)
1100 		Z_PARAM_OPTIONAL
1101 		Z_PARAM_ARRAY(options)
1102 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
1103 
1104 	if (buf_len == 0) {
1105 		RETURN_FALSE;
1106 	}
1107 
1108 	p = (const unsigned char*) buf;
1109 	PHP_VAR_UNSERIALIZE_INIT(var_hash);
1110 
1111 	prev_class_hash = php_var_unserialize_get_allowed_classes(var_hash);
1112 	if (options != NULL) {
1113 		classes = zend_hash_str_find(Z_ARRVAL_P(options), "allowed_classes", sizeof("allowed_classes")-1);
1114 		if (classes && Z_TYPE_P(classes) != IS_ARRAY && Z_TYPE_P(classes) != IS_TRUE && Z_TYPE_P(classes) != IS_FALSE) {
1115 			php_error_docref(NULL, E_WARNING, "allowed_classes option should be array or boolean");
1116 			PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1117 			RETURN_FALSE;
1118 		}
1119 
1120 		if(classes && (Z_TYPE_P(classes) == IS_ARRAY || !zend_is_true(classes))) {
1121 			ALLOC_HASHTABLE(class_hash);
1122 			zend_hash_init(class_hash, (Z_TYPE_P(classes) == IS_ARRAY)?zend_hash_num_elements(Z_ARRVAL_P(classes)):0, NULL, NULL, 0);
1123 		}
1124 		if(class_hash && Z_TYPE_P(classes) == IS_ARRAY) {
1125 			zval *entry;
1126 			zend_string *lcname;
1127 
1128 			ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(classes), entry) {
1129 				convert_to_string_ex(entry);
1130 				lcname = zend_string_tolower(Z_STR_P(entry));
1131 				zend_hash_add_empty_element(class_hash, lcname);
1132 		        zend_string_release_ex(lcname, 0);
1133 			} ZEND_HASH_FOREACH_END();
1134 		}
1135 		php_var_unserialize_set_allowed_classes(var_hash, class_hash);
1136 	}
1137 
1138 	retval = var_tmp_var(&var_hash);
1139 	if (!php_var_unserialize(retval, &p, p + buf_len, &var_hash)) {
1140 		if (!EG(exception)) {
1141 			php_error_docref(NULL, E_NOTICE, "Error at offset " ZEND_LONG_FMT " of %zd bytes",
1142 				(zend_long)((char*)p - buf), buf_len);
1143 		}
1144 		RETVAL_FALSE;
1145 	} else {
1146 		ZVAL_COPY(return_value, retval);
1147 	}
1148 
1149 	if (class_hash) {
1150 		zend_hash_destroy(class_hash);
1151 		FREE_HASHTABLE(class_hash);
1152 	}
1153 
1154 	/* Reset to previous allowed_classes in case this is a nested call */
1155 	php_var_unserialize_set_allowed_classes(var_hash, prev_class_hash);
1156 	PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1157 
1158 	/* Per calling convention we must not return a reference here, so unwrap. We're doing this at
1159 	 * the very end, because __wakeup() calls performed during UNSERIALIZE_DESTROY might affect
1160 	 * the value we unwrap here. This is compatible with behavior in PHP <=7.0. */
1161 	if (Z_ISREF_P(return_value)) {
1162 		zend_unwrap_reference(return_value);
1163 	}
1164 }
1165 /* }}} */
1166 
1167 /* {{{ proto int memory_get_usage([bool real_usage])
1168    Returns the allocated by PHP memory */
PHP_FUNCTION(memory_get_usage)1169 PHP_FUNCTION(memory_get_usage) {
1170 	zend_bool real_usage = 0;
1171 
1172 	ZEND_PARSE_PARAMETERS_START(0, 1)
1173 		Z_PARAM_OPTIONAL
1174 		Z_PARAM_BOOL(real_usage)
1175 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
1176 
1177 	RETURN_LONG(zend_memory_usage(real_usage));
1178 }
1179 /* }}} */
1180 
1181 /* {{{ proto int memory_get_peak_usage([bool real_usage])
1182    Returns the peak allocated by PHP memory */
PHP_FUNCTION(memory_get_peak_usage)1183 PHP_FUNCTION(memory_get_peak_usage) {
1184 	zend_bool real_usage = 0;
1185 
1186 	ZEND_PARSE_PARAMETERS_START(0, 1)
1187 		Z_PARAM_OPTIONAL
1188 		Z_PARAM_BOOL(real_usage)
1189 	ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
1190 
1191 	RETURN_LONG(zend_memory_peak_usage(real_usage));
1192 }
1193 /* }}} */
1194 
1195 /*
1196  * Local variables:
1197  * tab-width: 4
1198  * c-basic-offset: 4
1199  * End:
1200  * vim600: sw=4 ts=4 fdm=marker
1201  * vim<600: sw=4 ts=4
1202  */
1203