Merge topic 'fix_oom_crash'
* changes: strings.c: Fix __ast_str_helper() to always return a terminated string. Add missing failure checks to ast_str_set_va() callers.
This commit is contained in:
commit
d73bd56b0a
3 changed files with 79 additions and 44 deletions
|
@ -2819,6 +2819,7 @@ AST_THREADSTORAGE(userevent_buf);
|
||||||
*/
|
*/
|
||||||
void astman_append(struct mansession *s, const char *fmt, ...)
|
void astman_append(struct mansession *s, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
int res;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
struct ast_str *buf;
|
struct ast_str *buf;
|
||||||
|
|
||||||
|
@ -2827,8 +2828,11 @@ void astman_append(struct mansession *s, const char *fmt, ...)
|
||||||
}
|
}
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
ast_str_set_va(&buf, 0, fmt, ap);
|
res = ast_str_set_va(&buf, 0, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
if (res == AST_DYNSTR_BUILD_FAILED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (s->f != NULL || s->session->f != NULL) {
|
if (s->f != NULL || s->session->f != NULL) {
|
||||||
send_string(s, ast_str_buffer(buf));
|
send_string(s, ast_str_buffer(buf));
|
||||||
|
@ -2888,6 +2892,7 @@ void astman_send_error(struct mansession *s, const struct message *m, char *erro
|
||||||
|
|
||||||
void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt, ...)
|
void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
int res;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
struct ast_str *buf;
|
struct ast_str *buf;
|
||||||
char *msg;
|
char *msg;
|
||||||
|
@ -2897,8 +2902,11 @@ void astman_send_error_va(struct mansession *s, const struct message *m, const c
|
||||||
}
|
}
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
ast_str_set_va(&buf, 0, fmt, ap);
|
res = ast_str_set_va(&buf, 0, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
if (res == AST_DYNSTR_BUILD_FAILED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* astman_append will use the same underlying buffer, so copy the message out
|
/* astman_append will use the same underlying buffer, so copy the message out
|
||||||
* before sending the response */
|
* before sending the response */
|
||||||
|
|
105
main/strings.c
105
main/strings.c
|
@ -60,55 +60,78 @@ int __ast_str_helper(struct ast_str **buf, ssize_t max_len,
|
||||||
int append, const char *fmt, va_list ap)
|
int append, const char *fmt, va_list ap)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int res, need;
|
int res;
|
||||||
|
int added;
|
||||||
|
int need;
|
||||||
int offset = (append && (*buf)->__AST_STR_LEN) ? (*buf)->__AST_STR_USED : 0;
|
int offset = (append && (*buf)->__AST_STR_LEN) ? (*buf)->__AST_STR_USED : 0;
|
||||||
va_list aq;
|
va_list aq;
|
||||||
|
|
||||||
|
if (max_len < 0) {
|
||||||
|
max_len = (*buf)->__AST_STR_LEN; /* don't exceed the allocated space */
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (max_len < 0) {
|
|
||||||
max_len = (*buf)->__AST_STR_LEN; /* don't exceed the allocated space */
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Ask vsnprintf how much space we need. Remember that vsnprintf
|
|
||||||
* does not count the final <code>'\\0'</code> so we must add 1.
|
|
||||||
*/
|
|
||||||
va_copy(aq, ap);
|
va_copy(aq, ap);
|
||||||
res = vsnprintf((*buf)->__AST_STR_STR + offset, (*buf)->__AST_STR_LEN - offset, fmt, aq);
|
res = vsnprintf((*buf)->__AST_STR_STR + offset, (*buf)->__AST_STR_LEN - offset, fmt, aq);
|
||||||
|
|
||||||
need = res + offset + 1;
|
|
||||||
/*
|
|
||||||
* If there is not enough space and we are below the max length,
|
|
||||||
* reallocate the buffer and return a message telling to retry.
|
|
||||||
*/
|
|
||||||
if (need > (*buf)->__AST_STR_LEN && (max_len == 0 || (*buf)->__AST_STR_LEN < max_len) ) {
|
|
||||||
int len = (int)(*buf)->__AST_STR_LEN;
|
|
||||||
if (max_len && max_len < need) { /* truncate as needed */
|
|
||||||
need = max_len;
|
|
||||||
} else if (max_len == 0) { /* if unbounded, give more room for next time */
|
|
||||||
need += 16 + need / 4;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
#if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
|
|
||||||
_ast_str_make_space(buf, need, file, lineno, function)
|
|
||||||
#else
|
|
||||||
ast_str_make_space(buf, need)
|
|
||||||
#endif
|
|
||||||
) {
|
|
||||||
ast_log_safe(LOG_VERBOSE, "failed to extend from %d to %d\n", len, need);
|
|
||||||
va_end(aq);
|
|
||||||
return AST_DYNSTR_BUILD_FAILED;
|
|
||||||
}
|
|
||||||
(*buf)->__AST_STR_STR[offset] = '\0'; /* Truncate the partial write. */
|
|
||||||
|
|
||||||
/* Restart va_copy before calling vsnprintf() again. */
|
|
||||||
va_end(aq);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
va_end(aq);
|
va_end(aq);
|
||||||
break;
|
|
||||||
|
if (res < 0) {
|
||||||
|
/*
|
||||||
|
* vsnprintf write to string failed.
|
||||||
|
* I don't think this is possible with a memory buffer.
|
||||||
|
*/
|
||||||
|
res = AST_DYNSTR_BUILD_FAILED;
|
||||||
|
added = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vsnprintf returns how much space we used or would need.
|
||||||
|
* Remember that vsnprintf does not count the nil terminator
|
||||||
|
* so we must add 1.
|
||||||
|
*/
|
||||||
|
added = res;
|
||||||
|
need = offset + added + 1;
|
||||||
|
if (need <= (*buf)->__AST_STR_LEN
|
||||||
|
|| (max_len && max_len <= (*buf)->__AST_STR_LEN)) {
|
||||||
|
/*
|
||||||
|
* There was enough room for the string or we are not
|
||||||
|
* allowed to try growing the string buffer.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reallocate the buffer and try again. */
|
||||||
|
if (max_len == 0) {
|
||||||
|
/* unbounded, give more room for next time */
|
||||||
|
need += 16 + need / 4;
|
||||||
|
} else if (max_len < need) {
|
||||||
|
/* truncate as needed */
|
||||||
|
need = max_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
#if (defined(MALLOC_DEBUG) && !defined(STANDALONE))
|
||||||
|
_ast_str_make_space(buf, need, file, lineno, function)
|
||||||
|
#else
|
||||||
|
ast_str_make_space(buf, need)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
ast_log_safe(LOG_VERBOSE, "failed to extend from %d to %d\n",
|
||||||
|
(int) (*buf)->__AST_STR_LEN, need);
|
||||||
|
|
||||||
|
res = AST_DYNSTR_BUILD_FAILED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
} while (1);
|
} while (1);
|
||||||
/* update space used, keep in mind the truncation */
|
|
||||||
(*buf)->__AST_STR_USED = (res + offset > (*buf)->__AST_STR_LEN) ? (*buf)->__AST_STR_LEN - 1: res + offset;
|
/* Update space used, keep in mind truncation may be necessary. */
|
||||||
|
(*buf)->__AST_STR_USED = ((*buf)->__AST_STR_LEN <= offset + added)
|
||||||
|
? (*buf)->__AST_STR_LEN - 1
|
||||||
|
: offset + added;
|
||||||
|
|
||||||
|
/* Ensure that the string is terminated. */
|
||||||
|
(*buf)->__AST_STR_STR[(*buf)->__AST_STR_USED] = '\0';
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2646,14 +2646,18 @@ struct ast_xml_xpath_results *__attribute__((format(printf, 1, 2))) ast_xmldoc_q
|
||||||
struct documentation_tree *doctree;
|
struct documentation_tree *doctree;
|
||||||
RAII_VAR(struct ast_str *, xpath_str, ast_str_create(128), ast_free);
|
RAII_VAR(struct ast_str *, xpath_str, ast_str_create(128), ast_free);
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
int res;
|
||||||
|
|
||||||
if (!xpath_str) {
|
if (!xpath_str) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
ast_str_set_va(&xpath_str, 0, fmt, ap);
|
res = ast_str_set_va(&xpath_str, 0, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
if (res == AST_DYNSTR_BUILD_FAILED) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
AST_RWLIST_RDLOCK(&xmldoc_tree);
|
AST_RWLIST_RDLOCK(&xmldoc_tree);
|
||||||
AST_LIST_TRAVERSE(&xmldoc_tree, doctree, entry) {
|
AST_LIST_TRAVERSE(&xmldoc_tree, doctree, entry) {
|
||||||
|
|
Loading…
Reference in a new issue