diff --git a/Zend/zend.c b/Zend/zend.c index 97afdb936fd..eccd477f778 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -55,6 +55,7 @@ ZEND_API void (*zend_unblock_interruptions)(void); ZEND_API void (*zend_ticks_function)(int ticks TSRMLS_DC); ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); +zend_string *(*zend_vstrpprintf)(size_t max_len, const char *format, va_list ap); ZEND_API char *(*zend_getenv)(char *name, size_t name_len TSRMLS_DC); ZEND_API char *(*zend_resolve_path)(const char *filename, int filename_len TSRMLS_DC); @@ -676,6 +677,7 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions TS zend_ticks_function = utility_functions->ticks_function; zend_on_timeout = utility_functions->on_timeout; zend_vspprintf = utility_functions->vspprintf_function; + zend_vstrpprintf = utility_functions->vstrpprintf_function; zend_getenv = utility_functions->getenv_function; zend_resolve_path = utility_functions->resolve_path_function; diff --git a/Zend/zend.h b/Zend/zend.h index cabe64a56aa..27801815443 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -522,6 +522,7 @@ typedef struct _zend_utility_functions { void (*on_timeout)(int seconds TSRMLS_DC); int (*stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); int (*vspprintf_function)(char **pbuf, size_t max_len, const char *format, va_list ap); + zend_string *(*vstrpprintf_function)(size_t max_len, const char *format, va_list ap); char *(*getenv_function)(char *name, size_t name_len TSRMLS_DC); char *(*resolve_path_function)(const char *filename, int filename_len TSRMLS_DC); } zend_utility_functions; @@ -632,6 +633,7 @@ extern ZEND_API void (*zend_error_cb)(int type, const char *error_filename, cons extern ZEND_API void (*zend_on_timeout)(int seconds TSRMLS_DC); extern ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); extern int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); +extern zend_string *(*zend_vstrpprintf)(size_t max_len, const char *format, va_list ap); extern ZEND_API char *(*zend_getenv)(char *name, size_t name_len TSRMLS_DC); extern ZEND_API char *(*zend_resolve_path)(const char *filename, int filename_len TSRMLS_DC); diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 9d48dab9f26..1eae481829c 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -313,23 +313,20 @@ static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_ array_init(&val); for (i = 0; i < closure->func.common.num_args; i++) { - char *name, *info; - int name_len, info_len; + zend_string *name; + zval info; if (arg_info->name) { - name_len = zend_spprintf(&name, 0, "%s$%s", - arg_info->pass_by_reference ? "&" : "", - arg_info->name); + name = zend_strpprintf(0, "%s$%s", + arg_info->pass_by_reference ? "&" : "", + arg_info->name); } else { - name_len = zend_spprintf(&name, 0, "%s$param%d", - arg_info->pass_by_reference ? "&" : "", - i + 1); + name = zend_strpprintf(0, "%s$param%d", + arg_info->pass_by_reference ? "&" : "", + i + 1); } - info_len = zend_spprintf(&info, 0, "%s", - i >= required ? "" : ""); - // TODO: avoid reallocation ??? - add_assoc_stringl_ex(&val, name, name_len, info, info_len); - efree(info); - efree(name); + ZVAL_STR(&info, zend_strpprintf(0, "%s", i >= required ? "" : "")); + zend_hash_update(Z_ARRVAL(val), name, &info); + STR_RELEASE(name); arg_info++; } zend_hash_str_update(closure->debug_info, "parameter", sizeof("parameter")-1, &val); diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index 8b897961792..ae0ae834e43 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -618,7 +618,7 @@ ZEND_METHOD(exception, getPrevious) previous = zend_read_property(default_exception_ce, getThis(), "previous", sizeof("previous")-1, 1 TSRMLS_CC); RETURN_ZVAL(previous, 1, 0); -} +} /* }}} */ int zend_spprintf(char **message, int max_len, const char *format, ...) /* {{{ */ { @@ -632,19 +632,30 @@ int zend_spprintf(char **message, int max_len, const char *format, ...) /* {{{ * } /* }}} */ +zend_string *zend_strpprintf(int max_len, const char *format, ...) /* {{{ */ +{ + va_list arg; + zend_string *str; + + va_start(arg, format); + str = zend_vstrpprintf(max_len, format, arg); + va_end(arg); + return str; +} +/* }}} */ + /* {{{ proto string Exception::__toString() Obtain the string representation of the Exception object */ ZEND_METHOD(exception, __toString) { zval message, file, line, trace, *exception; - char *str, *prev_str; - int len = 0; + zend_string *str, *prev_str; zend_fcall_info fci; zval fname; DEFAULT_0_PARAMS; - str = estrndup("", 0); + str = STR_EMPTY_ALLOC(); exception = getThis(); ZVAL_STRINGL(&fname, "gettraceasstring", sizeof("gettraceasstring")-1); @@ -677,17 +688,17 @@ ZEND_METHOD(exception, __toString) } if (Z_STRLEN(message) > 0) { - len = zend_spprintf(&str, 0, "exception '%s' with message '%s' in %s:%ld\nStack trace:\n%s%s%s", - Z_OBJCE_P(exception)->name->val, Z_STRVAL(message), Z_STRVAL(file), Z_LVAL(line), - (Z_TYPE(trace) == IS_STRING && Z_STRLEN(trace)) ? Z_STRVAL(trace) : "#0 {main}\n", - len ? "\n\nNext " : "", prev_str); + str = zend_strpprintf(0, "exception '%s' with message '%s' in %s:%ld\nStack trace:\n%s%s%s", + Z_OBJCE_P(exception)->name->val, Z_STRVAL(message), Z_STRVAL(file), Z_LVAL(line), + (Z_TYPE(trace) == IS_STRING && Z_STRLEN(trace)) ? Z_STRVAL(trace) : "#0 {main}\n", + prev_str->len ? "\n\nNext " : "", prev_str->val); } else { - len = zend_spprintf(&str, 0, "exception '%s' in %s:%ld\nStack trace:\n%s%s%s", - Z_OBJCE_P(exception)->name->val, Z_STRVAL(file), Z_LVAL(line), - (Z_TYPE(trace) == IS_STRING && Z_STRLEN(trace)) ? Z_STRVAL(trace) : "#0 {main}\n", - len ? "\n\nNext " : "", prev_str); + str = zend_strpprintf(0, "exception '%s' in %s:%ld\nStack trace:\n%s%s%s", + Z_OBJCE_P(exception)->name->val, Z_STRVAL(file), Z_LVAL(line), + (Z_TYPE(trace) == IS_STRING && Z_STRLEN(trace)) ? Z_STRVAL(trace) : "#0 {main}\n", + prev_str->len ? "\n\nNext " : "", prev_str->val); } - efree(prev_str); + STR_RELEASE(prev_str); zval_dtor(&message); zval_dtor(&file); zval_dtor(&line); @@ -701,11 +712,9 @@ ZEND_METHOD(exception, __toString) /* We store the result in the private property string so we can access * the result in uncaught exception handlers without memleaks. */ - zend_update_property_string(default_exception_ce, getThis(), "string", sizeof("string")-1, str TSRMLS_CC); + zend_update_property_str(default_exception_ce, getThis(), "string", sizeof("string")-1, str TSRMLS_CC); - // TODO: avoid reallocation ??? - RETVAL_STRINGL(str, len); - efree(str); + RETURN_STR(str); } /* }}} */ diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index 24113d6f8d8..a7997867517 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -54,6 +54,7 @@ ZEND_API void zend_exception_error(zend_object *exception, int severity TSRMLS_D /* do not export, in php it's available thru spprintf directly */ int zend_spprintf(char **message, int max_len, const char *format, ...); +zend_string *zend_strpprintf(int max_len, const char *format, ...); END_EXTERN_C() diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 9cf0497d220..4c9db852621 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -621,15 +621,13 @@ ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC) /* {{{ */ break; } case IS_DOUBLE: { - char *str; - int len; + zend_string *str; double dval = Z_DVAL_P(op); TSRMLS_FETCH(); - len = zend_spprintf(&str, 0, "%.*G", (int) EG(precision), dval); + str = zend_strpprintf(0, "%.*G", (int) EG(precision), dval); /* %G already handles removing trailing zeros from the fractional part, yay */ - ZVAL_NEW_STR(op, STR_INIT(str, len, 0)); - efree(str); + ZVAL_NEW_STR(op, str); break; } case IS_ARRAY: @@ -910,11 +908,7 @@ try_again: return STR_INIT(buf, len, 0); } case IS_DOUBLE: { - char *str; - int len = zend_spprintf(&str, 0, "%.*G", (int) EG(precision), Z_DVAL_P(op)); - zend_string *retval = STR_INIT(str, len, 0); - efree(str); - return retval; + return zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(op)); } case IS_ARRAY: zend_error(E_NOTICE, "Array to string conversion"); @@ -2529,12 +2523,10 @@ ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC) / ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */ { TSRMLS_FETCH(); - char *str; - int len; + zend_string *str; - len = zend_spprintf(&str, 0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op)); - ZVAL_NEW_STR(op, STR_INIT(str, len, 0)); - efree(str); + str = zend_strpprintf(0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op)); + ZVAL_NEW_STR(op, str); } /* }}} */ diff --git a/main/main.c b/main/main.c index ebe0655d3a2..87e0b39c6c0 100644 --- a/main/main.c +++ b/main/main.c @@ -2095,6 +2095,7 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod zuf.on_timeout = php_on_timeout; zuf.stream_open_function = php_stream_open_for_zend; zuf.vspprintf_function = vspprintf; + zuf.vstrpprintf_function = vstrpprintf; zuf.getenv_function = sapi_getenv; zuf.resolve_path_function = php_resolve_path_for_zend; zend_startup(&zuf, NULL TSRMLS_CC); diff --git a/main/spprintf.c b/main/spprintf.c index 57548a5fcbd..50ebc3b31e0 100644 --- a/main/spprintf.c +++ b/main/spprintf.c @@ -799,7 +799,7 @@ PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap xbuf_format_converter(&xbuf, format, ap); - if (max_len && xbuf.s->len > max_len) { + if (max_len && xbuf.s && xbuf.s->len > max_len) { xbuf.s->len = max_len; } smart_str_0(&xbuf); @@ -829,6 +829,33 @@ PHPAPI int spprintf(char **pbuf, size_t max_len, const char *format, ...) /* {{{ } /* }}} */ +PHPAPI zend_string *vstrpprintf(size_t max_len, const char *format, va_list ap) /* {{{ */ +{ + smart_str xbuf = {0}; + + xbuf_format_converter(&xbuf, format, ap); + + if (max_len && xbuf.s && xbuf.s->len > max_len) { + xbuf.s->len = max_len; + } + smart_str_0(&xbuf); + + return xbuf.s; +} +/* }}} */ + +PHPAPI zend_string *strpprintf(size_t max_len, const char *format, ...) /* {{{ */ +{ + va_list ap; + zend_string *str; + + va_start(ap, format); + str = vstrpprintf(max_len, format, ap); + va_end(ap); + return str; +} +/* }}} */ + /* * Local variables: * tab-width: 4 diff --git a/main/spprintf.h b/main/spprintf.h index 813bbde01ae..ae26a3b9ec6 100644 --- a/main/spprintf.h +++ b/main/spprintf.h @@ -40,6 +40,10 @@ BEGIN_EXTERN_C() PHPAPI int spprintf( char **pbuf, size_t max_len, const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 3, 4); PHPAPI int vspprintf(char **pbuf, size_t max_len, const char *format, va_list ap) PHP_ATTRIBUTE_FORMAT(printf, 3, 0); + +PHPAPI zend_string *vstrpprintf(size_t max_len, const char *format, va_list ap); + +PHPAPI zend_string *strpprintf(size_t max_len, const char *format, ...); END_EXTERN_C() #endif /* SNPRINTF_H */