From: Nikita Popov Date: Wed, 7 Oct 2015 09:35:43 +0000 (+0200) Subject: Switch zend_print_zval_r to use smart_str X-Git-Tag: php-7.1.0alpha3~42^2~18^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1b29e0cacd4670d2f92456302bc5a3199b408a06;p=php Switch zend_print_zval_r to use smart_str Instead of directly writing to stdout. This allows doing a print_r into a string, without using output buffering. The motivation for this is bug #67467: print_r() in return mode will still dump the string to stdout (causing a potential information leak) if a fatal error occurs. --- diff --git a/Zend/zend.c b/Zend/zend.c index f2fa4b12d9..42cd65ed9c 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -31,6 +31,7 @@ #include "zend_vm.h" #include "zend_dtrace.h" #include "zend_virtual_cwd.h" +#include "zend_smart_str.h" #ifdef ZTS # define GLOBAL_FUNCTION_TABLE global_function_table @@ -159,7 +160,9 @@ static uint zend_version_info_length; #define ZEND_CORE_VERSION_INFO "Zend Engine v" ZEND_VERSION ", Copyright (c) 1998-2016 Zend Technologies\n" #define PRINT_ZVAL_INDENT 4 -static void print_hash(zend_write_func_t write_func, HashTable *ht, int indent, zend_bool is_object) /* {{{ */ +static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent); + +static void print_hash(smart_str *buf, HashTable *ht, int indent, zend_bool is_object) /* {{{ */ { zval *tmp; zend_string *string_key; @@ -167,54 +170,46 @@ static void print_hash(zend_write_func_t write_func, HashTable *ht, int indent, int i; for (i = 0; i < indent; i++) { - ZEND_PUTS_EX(" "); + smart_str_appendc(buf, ' '); } - ZEND_PUTS_EX("(\n"); + smart_str_appends(buf, "(\n"); indent += PRINT_ZVAL_INDENT; - ZEND_HASH_FOREACH_KEY_VAL(ht, num_key, string_key, tmp) { - if (Z_TYPE_P(tmp) == IS_INDIRECT) { - tmp = Z_INDIRECT_P(tmp); - if (Z_TYPE_P(tmp) == IS_UNDEF) { - continue; - } - } + ZEND_HASH_FOREACH_KEY_VAL_IND(ht, num_key, string_key, tmp) { for (i = 0; i < indent; i++) { - ZEND_PUTS_EX(" "); + smart_str_appendc(buf, ' '); } - ZEND_PUTS_EX("["); + smart_str_appendc(buf, '['); if (string_key) { if (is_object) { const char *prop_name, *class_name; size_t prop_len; int mangled = zend_unmangle_property_name_ex(string_key, &class_name, &prop_name, &prop_len); - ZEND_WRITE_EX(prop_name, prop_len); + smart_str_appendl(buf, prop_name, prop_len); if (class_name && mangled == SUCCESS) { - if (class_name[0]=='*') { - ZEND_PUTS_EX(":protected"); + if (class_name[0] == '*') { + smart_str_appends(buf, ":protected"); } else { - ZEND_PUTS_EX(":"); - ZEND_PUTS_EX(class_name); - ZEND_PUTS_EX(":private"); + smart_str_appends(buf, ":"); + smart_str_appends(buf, class_name); + smart_str_appends(buf, ":private"); } } } else { - ZEND_WRITE_EX(ZSTR_VAL(string_key), ZSTR_LEN(string_key)); + smart_str_append(buf, string_key); } } else { - char key[25]; - snprintf(key, sizeof(key), ZEND_LONG_FMT, num_key); - ZEND_PUTS_EX(key); + smart_str_append_long(buf, num_key); } - ZEND_PUTS_EX("] => "); - zend_print_zval_r_ex(write_func, tmp, indent+PRINT_ZVAL_INDENT); - ZEND_PUTS_EX("\n"); + smart_str_appends(buf, "] => "); + zend_print_zval_r_to_buf(buf, tmp, indent+PRINT_ZVAL_INDENT); + smart_str_appends(buf, "\n"); } ZEND_HASH_FOREACH_END(); indent -= PRINT_ZVAL_INDENT; for (i = 0; i < indent; i++) { - ZEND_PUTS_EX(" "); + smart_str_appendc(buf, ' '); } - ZEND_PUTS_EX(")\n"); + smart_str_appends(buf, ")\n"); } /* }}} */ @@ -253,18 +248,12 @@ ZEND_API int zend_make_printable_zval(zval *expr, zval *expr_copy) /* {{{ */ /* }}} */ ZEND_API size_t zend_print_zval(zval *expr, int indent) /* {{{ */ -{ - return zend_print_zval_ex(zend_write, expr, indent); -} -/* }}} */ - -ZEND_API size_t zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int indent) /* {{{ */ { zend_string *str = zval_get_string(expr); size_t len = ZSTR_LEN(str); if (len != 0) { - write_func(ZSTR_VAL(str), len); + zend_write(ZSTR_VAL(str), len); } zend_string_release(str); @@ -319,25 +308,19 @@ ZEND_API void zend_print_flat_zval_r(zval *expr) /* {{{ */ } /* }}} */ -ZEND_API void zend_print_zval_r(zval *expr, int indent) /* {{{ */ -{ - zend_print_zval_r_ex(zend_write, expr, indent); -} -/* }}} */ - -ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int indent) /* {{{ */ +static void zend_print_zval_r_to_buf(smart_str *buf, zval *expr, int indent) /* {{{ */ { ZVAL_DEREF(expr); switch (Z_TYPE_P(expr)) { case IS_ARRAY: - ZEND_PUTS_EX("Array\n"); + smart_str_appends(buf, "Array\n"); if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr)) && ++Z_ARRVAL_P(expr)->u.v.nApplyCount>1) { - ZEND_PUTS_EX(" *RECURSION*"); + smart_str_appends(buf, " *RECURSION*"); Z_ARRVAL_P(expr)->u.v.nApplyCount--; return; } - print_hash(write_func, Z_ARRVAL_P(expr), indent, 0); + print_hash(buf, Z_ARRVAL_P(expr), indent, 0); if (ZEND_HASH_APPLY_PROTECTION(Z_ARRVAL_P(expr))) { Z_ARRVAL_P(expr)->u.v.nApplyCount--; } @@ -348,12 +331,12 @@ ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int int is_temp; zend_string *class_name = Z_OBJ_HANDLER_P(expr, get_class_name)(Z_OBJ_P(expr)); - ZEND_PUTS_EX(ZSTR_VAL(class_name)); + smart_str_appends(buf, ZSTR_VAL(class_name)); zend_string_release(class_name); - ZEND_PUTS_EX(" Object\n"); + smart_str_appends(buf, " Object\n"); if (Z_OBJ_APPLY_COUNT_P(expr) > 0) { - ZEND_PUTS_EX(" *RECURSION*"); + smart_str_appends(buf, " *RECURSION*"); return; } if ((properties = Z_OBJDEBUG_P(expr, is_temp)) == NULL) { @@ -361,7 +344,7 @@ ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int } Z_OBJ_INC_APPLY_COUNT_P(expr); - print_hash(write_func, properties, indent, 1); + print_hash(buf, properties, indent, 1); Z_OBJ_DEC_APPLY_COUNT_P(expr); if (is_temp) { @@ -370,13 +353,37 @@ ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int } break; } + case IS_LONG: + smart_str_append_long(buf, Z_LVAL_P(expr)); + break; default: - zend_print_zval_ex(write_func, expr, indent); + { + zend_string *str = zval_get_string(expr); + smart_str_append(buf, str); + zend_string_release(str); + } break; } } /* }}} */ +ZEND_API zend_string *zend_print_zval_r_to_str(zval *expr, int indent) /* {{{ */ +{ + smart_str buf = {0}; + zend_print_zval_r_to_buf(&buf, expr, indent); + smart_str_0(&buf); + return buf.s; +} +/* }}} */ + +ZEND_API void zend_print_zval_r(zval *expr, int indent) /* {{{ */ +{ + zend_string *str = zend_print_zval_r_to_str(expr, indent); + zend_write(ZSTR_VAL(str), ZSTR_LEN(str)); + zend_string_release(str); +} +/* }}} */ + static FILE *zend_fopen_wrapper(const char *filename, zend_string **opened_path) /* {{{ */ { if (opened_path) { diff --git a/Zend/zend.h b/Zend/zend.h index e886ba20d3..42130cadf8 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -39,6 +39,7 @@ #include "zend_variables.h" #include "zend_iterators.h" #include "zend_stream.h" +#include "zend_smart_str_public.h" #ifdef ZEND_SIGNALS # include "zend_signal.h" @@ -243,10 +244,9 @@ ZEND_API ZEND_COLD void _zend_bailout(char *filename, uint lineno); ZEND_API char *get_zend_version(void); ZEND_API int zend_make_printable_zval(zval *expr, zval *expr_copy); ZEND_API size_t zend_print_zval(zval *expr, int indent); -ZEND_API size_t zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int indent); ZEND_API void zend_print_zval_r(zval *expr, int indent); +ZEND_API zend_string *zend_print_zval_r_to_str(zval *expr, int indent); ZEND_API void zend_print_flat_zval_r(zval *expr); -ZEND_API void zend_print_zval_r_ex(zend_write_func_t write_func, zval *expr, int indent); ZEND_API ZEND_COLD void zend_output_debug_string(zend_bool trigger_break, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); ZEND_API void zend_activate(void); diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 5fb5246d92..69663d983d 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -5477,15 +5477,9 @@ PHP_FUNCTION(print_r) } if (do_return) { - php_output_start_default(); - } - - zend_print_zval_r(var, 0); - - if (do_return) { - php_output_get_contents(return_value); - php_output_discard(); + RETURN_STR(zend_print_zval_r_to_str(var, 0)); } else { + zend_print_zval_r(var, 0); RETURN_TRUE; } } diff --git a/ext/standard/info.c b/ext/standard/info.c index c0d8ea91d5..982d4e461b 100644 --- a/ext/standard/info.c +++ b/ext/standard/info.c @@ -229,9 +229,11 @@ static void php_print_gpcse_array(char *name, uint name_length) } if (Z_TYPE_P(tmp) == IS_ARRAY) { if (!sapi_module.phpinfo_as_text) { + zend_string *str = zend_print_zval_r_to_str(tmp, 0); php_info_print("
");
-					zend_print_zval_r_ex((zend_write_func_t) php_info_print_html_esc, tmp, 0);
+					php_info_print_html_esc(ZSTR_VAL(str), ZSTR_LEN(str));
 					php_info_print("
"); + zend_string_release(str); } else { zend_print_zval_r(tmp, 0); } diff --git a/tests/output/ob_010.phpt b/tests/output/ob_010.phpt index 24d650c50d..7e362cabe1 100644 --- a/tests/output/ob_010.phpt +++ b/tests/output/ob_010.phpt @@ -4,10 +4,10 @@ output buffering - fatalism --EXPECTF-- -Fatal error: print_r(): Cannot use output buffering in output buffering display handlers in %sob_010.php on line %d +foo