[libvirt] [PATCH 20/20] Use virBufferPtr for sexpr2string instead of manual buffer handling

Matthias Bolte matthias.bolte at googlemail.com
Sun Apr 3 09:21:33 UTC 2011


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




More information about the libvir-list mailing list