From 67a710c3c37a6b3d8f35abaa45ebfeadf59c82f7 Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Thu, 25 Feb 2021 17:20:12 +0100 Subject: [PATCH] util: virerror: Avoid a copy of the error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Ján Tomko --- 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 }, - }; + char *msg = 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); - - 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; }