[PATCH 2/6] util: virerror: Avoid a copy of the error messages

Peter Krempa pkrempa at redhat.com
Tue Mar 2 15:21:04 UTC 2021


Some error message reporting functions already have allocated buffers
which were used to format the error message, so copying the strings is
redundant.

Extract the internals from 'virRaiseErrorFull' to
'virRaiseErrorInternal' which takes allocated strings as arguments and
steals them, so that callers can reuse the buffers.

Signed-off-by: Peter Krempa <pkrempa at redhat.com>
---
 src/util/virerror.c | 159 ++++++++++++++++++++++++++------------------
 1 file changed, 95 insertions(+), 64 deletions(-)

diff --git a/src/util/virerror.c b/src/util/virerror.c
index b9a49ec70c..220fc362c1 100644
--- a/src/util/virerror.c
+++ b/src/util/virerror.c
@@ -755,6 +755,70 @@ void virRaiseErrorLog(const char *filename,
                       meta, "%s", err->message);
 }

+
+/**
+ * virRaiseErrorInternal:
+ *
+ * Internal helper to assign and raise error. Note that @msgarg, @str1arg,
+ * @str2arg and @str3arg if non-NULL must be heap-allocated strings and are
+ * stolen and freed by this function.
+ */
+static void
+virRaiseErrorInternal(const char *filename,
+                      const char *funcname,
+                      size_t linenr,
+                      int domain,
+                      int code,
+                      virErrorLevel level,
+                      char *msgarg,
+                      char *str1arg,
+                      char *str2arg,
+                      char *str3arg,
+                      int int1,
+                      int int2)
+{
+    g_autofree char *msg = msgarg;
+    g_autofree char *str1 = str1arg;
+    g_autofree char *str2 = str2arg;
+    g_autofree char *str3 = str3arg;
+    virErrorPtr to;
+    virLogMetadata meta[] = {
+        { .key = "LIBVIRT_DOMAIN", .s = NULL, .iv = domain },
+        { .key = "LIBVIRT_CODE", .s = NULL, .iv = code },
+        { .key = NULL },
+    };
+
+    /*
+     * All errors are recorded in thread local storage
+     * For compatibility, public API calls will copy them
+     * to the per-connection error object when necessary
+     */
+    if (!(to = virLastErrorObject()))
+        return;
+
+    virResetError(to);
+
+    if (code == VIR_ERR_OK)
+        return;
+
+    if (!msg)
+        msg = g_strdup(_("No error message provided"));
+
+    /* Deliberately not setting conn, dom & net fields sincethey're utterly unsafe. */
+    to->domain = domain;
+    to->code = code;
+    to->message = g_steal_pointer(&msg);
+    to->level = level;
+    to->str1 = g_steal_pointer(&str1);
+    to->str2 = g_steal_pointer(&str2);
+    to->str3 = g_steal_pointer(&str3);
+    to->int1 = int1;
+    to->int2 = int2;
+
+    virRaiseErrorLog(filename, funcname, linenr, to, meta);
+}
+
+
 /**
  * virRaiseErrorFull:
  * @filename: filename where error was raised
@@ -789,63 +853,20 @@ virRaiseErrorFull(const char *filename,
                   const char *fmt, ...)
 {
     int save_errno = errno;
-    virErrorPtr to;
-    char *str;
-    virLogMetadata meta[] = {
-        { .key = "LIBVIRT_DOMAIN", .s = NULL, .iv = domain },
-        { .key = "LIBVIRT_CODE", .s = NULL, .iv = code },
-        { .key = NULL },
-    };
-
-    /*
-     * All errors are recorded in thread local storage
-     * For compatibility, public API calls will copy them
-     * to the per-connection error object when necessary
-     */
-    to = virLastErrorObject();
-    if (!to) {
-        errno = save_errno;
-        return; /* Hit OOM allocating thread error object, sod all we can do now */
-    }
-
-    virResetError(to);
+    char *msg = NULL;

-    if (code == VIR_ERR_OK) {
-        errno = save_errno;
-        return;
-    }
-
-    /*
-     * formats the message; drop message on OOM situations
-     */
-    if (fmt == NULL) {
-        str = g_strdup(_("No error message provided"));
-    } else {
+    if (fmt) {
         va_list ap;
+
         va_start(ap, fmt);
-        str = g_strdup_vprintf(fmt, ap);
+        msg = g_strdup_vprintf(fmt, ap);
         va_end(ap);
     }

-    /*
-     * Save the information about the error
-     */
-    /*
-     * Deliberately not setting conn, dom & net fields since
-     * they're utterly unsafe
-     */
-    to->domain = domain;
-    to->code = code;
-    to->message = str;
-    to->level = level;
-    to->str1 = g_strdup(str1);
-    to->str2 = g_strdup(str2);
-    to->str3 = g_strdup(str3);
-    to->int1 = int1;
-    to->int2 = int2;
-
-    virRaiseErrorLog(filename, funcname, linenr,
-                     to, meta);
+    virRaiseErrorInternal(filename, funcname, linenr,
+                          domain, code, level,
+                          msg, g_strdup(str1), g_strdup(str2), g_strdup(str3),
+                          int1, int2);

     errno = save_errno;
 }
@@ -1286,8 +1307,9 @@ void virReportErrorHelper(int domcode,
                           const char *fmt, ...)
 {
     int save_errno = errno;
-    g_autofree char *detail = NULL;
-    const char *errormsg;
+    char *detail = NULL;
+    char *errormsg = NULL;
+    char *fullmsg = NULL;

     if (fmt) {
         va_list args;
@@ -1297,12 +1319,19 @@ void virReportErrorHelper(int domcode,
         va_end(args);
     }

-    errormsg = virErrorMsg(errorcode, detail);
+    errormsg = g_strdup(virErrorMsg(errorcode, detail));
+
+    if (errormsg) {
+        if (detail)
+            fullmsg = g_strdup_printf(errormsg, detail);
+        else
+            fullmsg = g_strdup(errormsg);
+    }
+
+    virRaiseErrorInternal(filename, funcname, linenr,
+                          domcode, errorcode, VIR_ERR_ERROR,
+                          fullmsg, errormsg, detail, NULL, -1, -1);

-    virRaiseErrorFull(filename, funcname, linenr,
-                      domcode, errorcode, VIR_ERR_ERROR,
-                      errormsg, detail, NULL,
-                      -1, -1, errormsg, detail);
     errno = save_errno;
 }

@@ -1327,8 +1356,9 @@ void virReportSystemErrorFull(int domcode,
 {
     int save_errno = errno;
     virBuffer buf = VIR_BUFFER_INITIALIZER;
-    g_autofree char *detail = NULL;
-    const char *errormsg;
+    char *detail = NULL;
+    char *errormsg = NULL;
+    char *fullmsg = NULL;

     if (fmt) {
         va_list args;
@@ -1343,11 +1373,12 @@ void virReportSystemErrorFull(int domcode,
     virBufferAdd(&buf, g_strerror(theerrno), -1);

     detail = virBufferContentAndReset(&buf);
-    errormsg = virErrorMsg(VIR_ERR_SYSTEM_ERROR, detail);
+    errormsg = g_strdup(virErrorMsg(VIR_ERR_SYSTEM_ERROR, detail));
+    fullmsg = g_strdup_printf(errormsg, detail);

-    virRaiseErrorFull(filename, funcname, linenr,
-                      domcode, VIR_ERR_SYSTEM_ERROR, VIR_ERR_ERROR,
-                      errormsg, detail, NULL, theerrno, -1, errormsg, detail);
+    virRaiseErrorInternal(filename, funcname, linenr,
+                          domcode, VIR_ERR_SYSTEM_ERROR, VIR_ERR_ERROR,
+                          fullmsg, errormsg, detail, NULL, theerrno, -1);
     errno = save_errno;
 }

-- 
2.29.2




More information about the libvir-list mailing list