From e246625a57d0877fce298aae06954adc8ae615fb Mon Sep 17 00:00:00 2001 From: Pierre Joye Date: Tue, 13 Jul 2010 18:53:12 +0000 Subject: [PATCH] - MFH: Fix a bug when var_export() causes a fatal error that could inadvertently display data due to flushing of the output buffer. --- ext/standard/php_var.h | 2 + .../general_functions/var_export_error2.phpt | 7 - .../general_functions/var_export_error3.phpt | 9 -- ext/standard/var.c | 134 ++++++++++++------ 4 files changed, 96 insertions(+), 56 deletions(-) diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index 1e19ed5f97..44988913b3 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -33,6 +33,8 @@ PHP_FUNCTION(memory_get_peak_usage); PHPAPI void php_var_dump(zval **struc, int level TSRMLS_DC); PHPAPI void php_var_export(zval **struc, int level TSRMLS_DC); +PHPAPI void php_var_export_ex(zval **struc, int level, smart_str *buf TSRMLS_DC); + PHPAPI void php_debug_zval_dump(zval **struc, int level TSRMLS_DC); /* typdef HashTable php_serialize_data_t; */ diff --git a/ext/standard/tests/general_functions/var_export_error2.phpt b/ext/standard/tests/general_functions/var_export_error2.phpt index 93d0dc1646..2b306696a6 100644 --- a/ext/standard/tests/general_functions/var_export_error2.phpt +++ b/ext/standard/tests/general_functions/var_export_error2.phpt @@ -14,12 +14,5 @@ var_export($obj, true); ?> ===DONE=== --EXPECTF-- -stdClass::__set_state(array( - 'p' => - stdClass::__set_state(array( - 'p' => - stdClass::__set_state(array( - 'p' => - stdClass::__set_state(array( Fatal error: Nesting level too deep - recursive dependency? in %s on line 9 \ No newline at end of file diff --git a/ext/standard/tests/general_functions/var_export_error3.phpt b/ext/standard/tests/general_functions/var_export_error3.phpt index 4ad5121682..03ed496aca 100644 --- a/ext/standard/tests/general_functions/var_export_error3.phpt +++ b/ext/standard/tests/general_functions/var_export_error3.phpt @@ -14,14 +14,5 @@ var_export($a, true); ?> ===DONE=== --EXPECTF-- -array ( - 0 => - array ( - 0 => - array ( - 0 => - array ( - 0 => - array ( Fatal error: Nesting level too deep - recursive dependency? in %s on line 9 \ No newline at end of file diff --git a/ext/standard/var.c b/ext/standard/var.c index d52c48b943..6d0dd6828d 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -346,54 +346,83 @@ PHP_FUNCTION(debug_zval_dump) } /* }}} */ +#define buffer_append_spaces(buf, num_spaces) \ + do { \ + char *tmp_spaces; \ + int tmp_spaces_len; \ + tmp_spaces_len = spprintf(&tmp_spaces, 0,"%*c", num_spaces, ' '); \ + smart_str_appendl(buf, tmp_spaces, tmp_spaces_len); \ + efree(tmp_spaces); \ + } while(0); /* {{{ php_var_export */ static int php_array_element_export(zval **zv, int num_args, va_list args, zend_hash_key *hash_key) { int level; + smart_str *buf; + TSRMLS_FETCH(); level = va_arg(args, int); + buf = va_arg(args, smart_str *); - if (hash_key->nKeyLength==0) { /* numeric key */ - php_printf("%*c%ld => ", level + 1, ' ', hash_key->h); + if (hash_key->nKeyLength == 0) { /* numeric key */ + buffer_append_spaces(buf, level+1); + smart_str_append_long(buf, hash_key->h); + smart_str_appendl(buf, " => ", 4); } else { /* string key */ char *key, *tmp_str; int key_len, tmp_len; key = php_addcslashes(hash_key->arKey, hash_key->nKeyLength - 1, &key_len, 0, "'\\", 2 TSRMLS_CC); tmp_str = php_str_to_str_ex(key, key_len, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len, 0, NULL); - php_printf("%*c'", level + 1, ' '); - PHPWRITE(tmp_str, tmp_len); - php_printf("' => "); + + buffer_append_spaces(buf, level + 1); + + smart_str_appendc(buf, '\''); + smart_str_appendl(buf, tmp_str, tmp_len); + smart_str_appendl(buf, "' => ", 5); + efree(key); efree(tmp_str); } - php_var_export(zv, level + 2 TSRMLS_CC); - PUTS (",\n"); + php_var_export_ex(zv, level + 2, buf TSRMLS_CC); + + smart_str_appendc(buf, ','); + smart_str_appendc(buf, '\n'); + return 0; } static int php_object_element_export(zval **zv, int num_args, va_list args, zend_hash_key *hash_key) { int level; + smart_str *buf; char *prop_name, *class_name; TSRMLS_FETCH(); level = va_arg(args, int); + buf = va_arg(args, smart_str *); - php_printf("%*c", level + 1, ' '); + buffer_append_spaces(buf, level + 2); if (hash_key->nKeyLength != 0) { zend_unmangle_property_name(hash_key->arKey, hash_key->nKeyLength - 1, &class_name, &prop_name); - php_printf(" '%s' => ", prop_name); + + smart_str_appendc(buf, '\''); + smart_str_appends(buf, prop_name); + smart_str_appendc(buf, '\''); } else { - php_printf(" %ld => ", hash_key->h); + smart_str_append_long(buf, hash_key->h); } - php_var_export(zv, level + 2 TSRMLS_CC); - PUTS (",\n"); + + smart_str_appendl(buf, " => ", 4); + php_var_export_ex(zv, level + 2, buf TSRMLS_CC); + smart_str_appendc(buf, ','); + smart_str_appendc(buf, '\n'); + return 0; } -PHPAPI void php_var_export(zval **struc, int level TSRMLS_DC) +PHPAPI void php_var_export_ex(zval **struc, int level, smart_str *buf TSRMLS_DC) /* {{{ */ { HashTable *myht; char *tmp_str, *tmp_str2; @@ -403,60 +432,85 @@ PHPAPI void php_var_export(zval **struc, int level TSRMLS_DC) switch (Z_TYPE_PP(struc)) { case IS_BOOL: - php_printf("%s", Z_LVAL_PP(struc) ? "true" : "false"); + if (Z_LVAL_PP(struc)) { + smart_str_appendl(buf, "true", 4); + } else { + smart_str_appendl(buf, "false", 5); + } break; case IS_NULL: - php_printf("NULL"); + smart_str_appendl(buf, "NULL", 4); break; case IS_LONG: - php_printf("%ld", Z_LVAL_PP(struc)); + smart_str_append_long(buf, Z_LVAL_PP(struc)); break; case IS_DOUBLE: - php_printf("%.*H", (int) EG(precision), Z_DVAL_PP(struc)); + tmp_len = spprintf(&tmp_str, 0,"%.*H", (int) EG(precision), Z_DVAL_PP(struc)); + smart_str_appendl(buf, tmp_str, tmp_len); + efree(tmp_str); break; case IS_STRING: tmp_str = php_addcslashes(Z_STRVAL_PP(struc), Z_STRLEN_PP(struc), &tmp_len, 0, "'\\", 2 TSRMLS_CC); tmp_str2 = php_str_to_str_ex(tmp_str, tmp_len, "\0", 1, "' . \"\\0\" . '", 12, &tmp_len2, 0, NULL); - PUTS ("'"); - PHPWRITE(tmp_str2, tmp_len2); - PUTS ("'"); + + smart_str_appendc(buf, '\''); + smart_str_appendl(buf, tmp_str2, tmp_len2); + smart_str_appendc(buf, '\''); + efree(tmp_str2); efree(tmp_str); break; case IS_ARRAY: myht = Z_ARRVAL_PP(struc); if (level > 1) { - php_printf("\n%*c", level - 1, ' '); + smart_str_appendc(buf, '\n'); + buffer_append_spaces(buf, level - 1); } - PUTS ("array (\n"); - zend_hash_apply_with_arguments(myht, (apply_func_args_t) php_array_element_export, 1, level, 0); + smart_str_appendl(buf, "array (\n", 8); + zend_hash_apply_with_arguments(myht, (apply_func_args_t) php_array_element_export, 2, level, buf); + if (level > 1) { - php_printf("%*c", level - 1, ' '); + buffer_append_spaces(buf, level - 1); } - PUTS(")"); + smart_str_appendc(buf, ')'); + break; case IS_OBJECT: myht = Z_OBJPROP_PP(struc); if (level > 1) { - php_printf("\n%*c", level - 1, ' '); + smart_str_appendc(buf, '\n'); + buffer_append_spaces(buf, level - 1); } Z_OBJ_HANDLER(**struc, get_class_name)(*struc, &class_name, &class_name_len, 0 TSRMLS_CC); - php_printf ("%s::__set_state(array(\n", class_name); + + smart_str_appendl(buf, class_name, class_name_len); + smart_str_appendl(buf, "::__set_state(array(\n", 21); + efree(class_name); if (myht) { - zend_hash_apply_with_arguments(myht, (apply_func_args_t) php_object_element_export, 1, level); + zend_hash_apply_with_arguments(myht, (apply_func_args_t) php_object_element_export, 2, level, buf); } if (level > 1) { - php_printf("%*c", level - 1, ' '); + buffer_append_spaces(buf, level - 1); } - php_printf ("))"); + smart_str_appendl(buf, "))", 2); + break; default: - PUTS ("NULL"); + smart_str_appendl(buf, "NULL", 4); break; } } +/* FOR BC reasons, this will always perform and then print */ +PHPAPI void php_var_export(zval **struc, int level TSRMLS_DC) /* {{{ */ +{ + smart_str buf = {0}; + php_var_export_ex(struc, level, &buf TSRMLS_CC); + smart_str_0 (&buf); + PHPWRITE(buf.c, buf.len); + smart_str_free(&buf); +} /* }}} */ /* {{{ proto mixed var_export(mixed var [, bool return]) @@ -465,21 +519,21 @@ PHP_FUNCTION(var_export) { zval *var; zend_bool return_output = 0; - + smart_str buf = {0}; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &var, &return_output) == FAILURE) { return; } - - if (return_output) { - php_start_ob_buffer (NULL, 0, 1 TSRMLS_CC); - } - - php_var_export(&var, 1 TSRMLS_CC); + + php_var_export_ex(&var, 1, &buf TSRMLS_CC); + smart_str_0 (&buf); if (return_output) { - php_ob_get_buffer (return_value TSRMLS_CC); - php_end_ob_buffer (0, 0 TSRMLS_CC); + RETVAL_STRINGL(buf.c, buf.len, 1); + } else { + PHPWRITE(buf.c, buf.len); } + smart_str_free(&buf); } /* }}} */ -- 2.40.0