]> granicus.if.org Git - php/commitdiff
Switch zend_print_zval_r to use smart_str
authorNikita Popov <nikic@php.net>
Wed, 7 Oct 2015 09:35:43 +0000 (11:35 +0200)
committerNikita Popov <nikic@php.net>
Mon, 13 Jun 2016 16:04:22 +0000 (18:04 +0200)
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.

Zend/zend.c
Zend/zend.h
ext/standard/basic_functions.c
ext/standard/info.c
tests/output/ob_010.phpt

index f2fa4b12d9269e5b9ce4975b1e94e392bc7e8ad5..42cd65ed9cdaf8e43bf936f05f0bef7d165a064d 100644 (file)
@@ -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) {
index e886ba20d374c28b26c4498e6f62cef474736270..42130cadf8a3168901889a8435cbc3e6d71d91ce 100644 (file)
@@ -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);
index 5fb5246d92a08b50da4cc8b337d4722ab161c3c4..69663d983d1a9b4f327877e2f7532c2b3ed81d4a 100644 (file)
@@ -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;
        }
 }
index c0d8ea91d59492511865be14ccff052d5f557088..982d4e461b75b7add9731a38d3c7f6f6e1e9defc 100644 (file)
@@ -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("<pre>");
-                                       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("</pre>");
+                                       zend_string_release(str);
                                } else {
                                        zend_print_zval_r(tmp, 0);
                                }
index 24d650c50d803df59cf177e6fb9af4194ff6d916..7e362cabe18cbfe17ca371ad54b539b438844f4b 100644 (file)
@@ -4,10 +4,10 @@ output buffering - fatalism
 <?php
 function obh($s)
 {
-       print_r($s, 1);
+       return print_r($s, 1);
 }
 ob_start("obh");
 echo "foo\n";
 ?>
 --EXPECTF--
-Fatal error: print_r(): Cannot use output buffering in output buffering display handlers in %sob_010.php on line %d
+foo