Removes 4kb stack allocation in the XenD subdriver. --- src/util/sexpr.c | 142 +++++++++++++++++++++++------------------------ src/util/sexpr.h | 3 +- src/xen/xend_internal.c | 17 +++++- 3 files changed, 86 insertions(+), 76 deletions(-) diff --git a/src/util/sexpr.c b/src/util/sexpr.c index 7f14206..ae1692a 100644 --- a/src/util/sexpr.c +++ b/src/util/sexpr.c @@ -199,78 +199,56 @@ sexpr_append(struct sexpr *lst, const struct sexpr *value) * sexpr2string: * @sexpr: an S-Expression pointer * @buffer: the output buffer - * @n_buffer: the size of the buffer in bytes * * Serialize the S-Expression in the buffer. - * Note that the output may be truncated if @n_buffer is too small - * resulting in an unparseable value. * - * Returns the number of bytes used by the serialization in the buffer or - * 0 in case of error. + * Returns 0 on success, -1 on error. */ -size_t -sexpr2string(const struct sexpr * sexpr, char *buffer, size_t n_buffer) +int +sexpr2string(const struct sexpr *sexpr, virBufferPtr buffer) { - size_t ret = 0, tmp; - - if ((sexpr == NULL) || (buffer == NULL) || (n_buffer <= 0)) - return (0); + if ((sexpr == NULL) || (buffer == NULL)) + return -1; switch (sexpr->kind) { - case SEXPR_CONS: - tmp = snprintf(buffer + ret, n_buffer - ret, "("); - if (tmp == 0) - goto error; - ret += tmp; - tmp = sexpr2string(sexpr->u.s.car, buffer + ret, n_buffer - ret); - if (tmp == 0) - goto error; - ret += tmp; - while (sexpr->u.s.cdr->kind != SEXPR_NIL) { - sexpr = sexpr->u.s.cdr; - tmp = snprintf(buffer + ret, n_buffer - ret, " "); - if (tmp == 0) - goto error; - ret += tmp; - tmp = - sexpr2string(sexpr->u.s.car, buffer + ret, n_buffer - ret); - if (tmp == 0) - goto error; - ret += tmp; - } - tmp = snprintf(buffer + ret, n_buffer - ret, ")"); - if (tmp == 0) - goto error; - ret += tmp; - break; - case SEXPR_VALUE: - if (strchr(sexpr->u.value, ' ') || - strchr(sexpr->u.value, ')') || - strchr(sexpr->u.value, '(')) - tmp = snprintf(buffer + ret, n_buffer - ret, "'%s'", - sexpr->u.value); - else - tmp = snprintf(buffer + ret, n_buffer - ret, "%s", - sexpr->u.value); - if (tmp == 0) - goto error; - ret += tmp; - break; - case SEXPR_NIL: - tmp = snprintf(buffer + ret, n_buffer - ret, "()"); - if (tmp == 0) - goto error; - ret += tmp; - break; - default: + case SEXPR_CONS: + virBufferAddChar(buffer, '('); + + if (sexpr2string(sexpr->u.s.car, buffer) < 0) goto error; + + while (sexpr->u.s.cdr->kind != SEXPR_NIL) { + sexpr = sexpr->u.s.cdr; + + virBufferAddChar(buffer, ' '); + + if (sexpr2string(sexpr->u.s.car, buffer) < 0) + goto error; + } + + virBufferAddChar(buffer, ')'); + break; + case SEXPR_VALUE: + if (strchr(sexpr->u.value, ' ') || + strchr(sexpr->u.value, ')') || + strchr(sexpr->u.value, '(')) + virBufferVSprintf(buffer, "'%s'", sexpr->u.value); + else + virBufferVSprintf(buffer, "%s", sexpr->u.value); + + break; + case SEXPR_NIL: + virBufferAddLit(buffer, "()"); + break; + default: + goto error; } - return (ret); + return 0; + error: - buffer[n_buffer - 1] = 0; - virSexprError(VIR_ERR_SEXPR_SERIAL, "%s", buffer); - return (0); + virSexprError(VIR_ERR_SEXPR_SERIAL, NULL); + return -1; } #define IS_SPACE(c) ((c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA)) @@ -413,22 +391,28 @@ string2sexpr(const char *buffer) static struct sexpr * sexpr_lookup_key(const struct sexpr *sexpr, const char *node) { - char buffer[4096], *ptr, *token; + struct sexpr *result = NULL; + char *buffer, *ptr, *token; if ((node == NULL) || (sexpr == NULL)) - return (NULL); + return NULL; - snprintf(buffer, sizeof(buffer), "%s", node); + buffer = strdup(node); + + if (buffer == NULL) { + virReportOOMError(); + return NULL; + } ptr = buffer; token = strsep(&ptr, "/"); if (sexpr->kind != SEXPR_CONS || sexpr->u.s.car->kind != SEXPR_VALUE) { - return NULL; + goto cleanup; } if (STRNEQ(sexpr->u.s.car->u.value, token)) { - return NULL; + goto cleanup; } for (token = strsep(&ptr, "/"); token; token = strsep(&ptr, "/")) { @@ -454,10 +438,15 @@ sexpr_lookup_key(const struct sexpr *sexpr, const char *node) } if (token != NULL) { - return NULL; + goto cleanup; } - return (struct sexpr *) sexpr; + result = (struct sexpr *) sexpr; + +cleanup: + VIR_FREE(buffer); + + return result; } /** @@ -550,21 +539,30 @@ int sexpr_node_copy(const struct sexpr *sexpr, const char *node, char **dst) * @... extra data to build the path * * Search a node value in the S-Expression based on its path - * NOTE: path are limited to 4096 bytes. * * Returns the value of the node or NULL if not found. */ const char * sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...) { + int result; va_list ap; - char node[4096]; + char *node; + const char *value; va_start(ap, fmt); - vsnprintf(node, sizeof(node), fmt, ap); + result = virVasprintf(&node, fmt, ap); va_end(ap); - return sexpr_node(sexpr, node); + if (result < 0) { + return NULL; + } + + value = sexpr_node(sexpr, node); + + VIR_FREE(node); + + return value; } /** diff --git a/src/util/sexpr.h b/src/util/sexpr.h index dc6687d..8dfd89a 100644 --- a/src/util/sexpr.h +++ b/src/util/sexpr.h @@ -14,6 +14,7 @@ # define _LIBVIR_SEXPR_H_ # include "internal.h" +# include "buf.h" # include <sys/types.h> # include <stdint.h> @@ -36,7 +37,7 @@ struct sexpr { }; /* conversion to/from strings */ -size_t sexpr2string(const struct sexpr *sexpr, char *buffer, size_t n_buffer); +int sexpr2string(const struct sexpr *sexpr, virBufferPtr buffer); struct sexpr *string2sexpr(const char *buffer); /* constructors and destructors */ diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index 8b07a8a..04122ba 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -3023,7 +3023,8 @@ xenDaemonDomainSetAutostart(virDomainPtr domain, int autostart) { struct sexpr *root, *autonode; - char buf[4096]; + virBuffer buffer = VIR_BUFFER_INITIALIZER; + char *content = NULL; int ret = -1; xenUnifiedPrivatePtr priv; @@ -3065,12 +3066,20 @@ xenDaemonDomainSetAutostart(virDomainPtr domain, goto error; } - if (sexpr2string(root, buf, sizeof(buf)) == 0) { + if (sexpr2string(root, &buffer) < 0) { virXendError(VIR_ERR_INTERNAL_ERROR, "%s", _("sexpr2string failed")); goto error; } - if (xend_op(domain->conn, "", "op", "new", "config", buf, NULL) != 0) { + + if (virBufferError(&buffer)) { + virReportOOMError(); + goto error; + } + + content = virBufferContentAndReset(&buffer); + + if (xend_op(domain->conn, "", "op", "new", "config", content, NULL) != 0) { virXendError(VIR_ERR_XEN_CALL, "%s", _("Failed to redefine sexpr")); goto error; @@ -3083,6 +3092,8 @@ xenDaemonDomainSetAutostart(virDomainPtr domain, ret = 0; error: + virBufferFreeAndReset(&buffer); + VIR_FREE(content); sexpr_free(root); return ret; } -- 1.7.0.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list