8fced6
From 46c3298774b976cc6a1cd834751e644fb482b08e Mon Sep 17 00:00:00 2001
8fced6
From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= <marcandre.lureau@redhat.com>
8fced6
Date: Wed, 16 Dec 2020 16:06:10 -0500
8fced6
Subject: [PATCH 09/14] error: New macro ERRP_GUARD()
8fced6
MIME-Version: 1.0
8fced6
Content-Type: text/plain; charset=UTF-8
8fced6
Content-Transfer-Encoding: 8bit
8fced6
8fced6
RH-Author: Marc-André Lureau <marcandre.lureau@redhat.com>
8fced6
Message-id: <20201216160615.324213-6-marcandre.lureau@redhat.com>
8fced6
Patchwork-id: 100476
8fced6
O-Subject: [RHEL-8.4.0 qemu-kvm PATCH v2 05/10] error: New macro ERRP_GUARD()
8fced6
Bugzilla: 1859494
8fced6
RH-Acked-by: Danilo de Paula <ddepaula@redhat.com>
8fced6
RH-Acked-by: Sergio Lopez Pascual <slp@redhat.com>
8fced6
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
8fced6
8fced6
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8fced6
8fced6
Introduce a new ERRP_GUARD() macro, to be used at start of functions
8fced6
with an errp OUT parameter.
8fced6
8fced6
It has three goals:
8fced6
8fced6
1. Fix issue with error_fatal and error_prepend/error_append_hint: the
8fced6
user can't see this additional information, because exit() happens in
8fced6
error_setg earlier than information is added. [Reported by Greg Kurz]
8fced6
8fced6
2. Fix issue with error_abort and error_propagate: when we wrap
8fced6
error_abort by local_err+error_propagate, the resulting coredump will
8fced6
refer to error_propagate and not to the place where error happened.
8fced6
(the macro itself doesn't fix the issue, but it allows us to [3.] drop
8fced6
the local_err+error_propagate pattern, which will definitely fix the
8fced6
issue) [Reported by Kevin Wolf]
8fced6
8fced6
3. Drop local_err+error_propagate pattern, which is used to workaround
8fced6
void functions with errp parameter, when caller wants to know resulting
8fced6
status. (Note: actually these functions could be merely updated to
8fced6
return int error code).
8fced6
8fced6
To achieve these goals, later patches will add invocations
8fced6
of this macro at the start of functions with either use
8fced6
error_prepend/error_append_hint (solving 1) or which use
8fced6
local_err+error_propagate to check errors, switching those
8fced6
functions to use *errp instead (solving 2 and 3).
8fced6
8fced6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8fced6
Reviewed-by: Paul Durrant <paul@xen.org>
8fced6
Reviewed-by: Greg Kurz <groug@kaod.org>
8fced6
Reviewed-by: Eric Blake <eblake@redhat.com>
8fced6
[Merge comments properly with recent commit "error: Document Error API
8fced6
usage rules", and edit for clarity.  Put ERRP_AUTO_PROPAGATE() before
8fced6
its helpers, and touch up style.  Tweak commit message.]
8fced6
Signed-off-by: Markus Armbruster <armbru@redhat.com>
8fced6
Message-Id: <20200707165037.1026246-2-armbru@redhat.com>
8fced6
8fced6
(cherry picked from commit ae7c80a7bd73685437bf6ba9d7c26098351f4166)
8fced6
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
8fced6
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
8fced6
---
8fced6
 include/qapi/error.h | 158 +++++++++++++++++++++++++++++++++++++------
8fced6
 1 file changed, 139 insertions(+), 19 deletions(-)
8fced6
8fced6
diff --git a/include/qapi/error.h b/include/qapi/error.h
8fced6
index 08d48e74836..e658790acfc 100644
8fced6
--- a/include/qapi/error.h
8fced6
+++ b/include/qapi/error.h
8fced6
@@ -30,6 +30,10 @@
8fced6
  *   job.  Since the value of @errp is about handling the error, the
8fced6
  *   function should not examine it.
8fced6
  *
8fced6
+ * - The function may pass @errp to functions it calls to pass on
8fced6
+ *   their errors to its caller.  If it dereferences @errp to check
8fced6
+ *   for errors, it must use ERRP_GUARD().
8fced6
+ *
8fced6
  * - On success, the function should not touch *errp.  On failure, it
8fced6
  *   should set a new error, e.g. with error_setg(errp, ...), or
8fced6
  *   propagate an existing one, e.g. with error_propagate(errp, ...).
8fced6
@@ -45,15 +49,17 @@
8fced6
  * = Creating errors =
8fced6
  *
8fced6
  * Create an error:
8fced6
- *     error_setg(&err, "situation normal, all fouled up");
8fced6
+ *     error_setg(errp, "situation normal, all fouled up");
8fced6
+ * where @errp points to the location to receive the error.
8fced6
  *
8fced6
  * Create an error and add additional explanation:
8fced6
- *     error_setg(&err, "invalid quark");
8fced6
- *     error_append_hint(&err, "Valid quarks are up, down, strange, "
8fced6
+ *     error_setg(errp, "invalid quark");
8fced6
+ *     error_append_hint(errp, "Valid quarks are up, down, strange, "
8fced6
  *                       "charm, top, bottom.\n");
8fced6
+ * This may require use of ERRP_GUARD(); more on that below.
8fced6
  *
8fced6
  * Do *not* contract this to
8fced6
- *     error_setg(&err, "invalid quark\n" // WRONG!
8fced6
+ *     error_setg(errp, "invalid quark\n" // WRONG!
8fced6
  *                "Valid quarks are up, down, strange, charm, top, bottom.");
8fced6
  *
8fced6
  * = Reporting and destroying errors =
8fced6
@@ -107,18 +113,6 @@
8fced6
  * Errors get passed to the caller through the conventional @errp
8fced6
  * parameter.
8fced6
  *
8fced6
- * Pass an existing error to the caller:
8fced6
- *     error_propagate(errp, err);
8fced6
- * where Error **errp is a parameter, by convention the last one.
8fced6
- *
8fced6
- * Pass an existing error to the caller with the message modified:
8fced6
- *     error_propagate_prepend(errp, err,
8fced6
- *                             "Could not frobnicate '%s': ", name);
8fced6
- * This is more concise than
8fced6
- *     error_propagate(errp, err); // don't do this
8fced6
- *     error_prepend(errp, "Could not frobnicate '%s': ", name);
8fced6
- * and works even when @errp is &error_fatal.
8fced6
- *
8fced6
  * Create a new error and pass it to the caller:
8fced6
  *     error_setg(errp, "situation normal, all fouled up");
8fced6
  *
8fced6
@@ -129,18 +123,26 @@
8fced6
  *         handle the error...
8fced6
  *     }
8fced6
  * - when it does not, say because it is a void function:
8fced6
+ *     ERRP_GUARD();
8fced6
+ *     foo(arg, errp);
8fced6
+ *     if (*errp) {
8fced6
+ *         handle the error...
8fced6
+ *     }
8fced6
+ * More on ERRP_GUARD() below.
8fced6
+ *
8fced6
+ * Code predating ERRP_GUARD() still exists, and looks like this:
8fced6
  *     Error *err = NULL;
8fced6
  *     foo(arg, &err;;
8fced6
  *     if (err) {
8fced6
  *         handle the error...
8fced6
- *         error_propagate(errp, err);
8fced6
+ *         error_propagate(errp, err); // deprecated
8fced6
  *     }
8fced6
- * Do *not* "optimize" this to
8fced6
+ * Avoid in new code.  Do *not* "optimize" it to
8fced6
  *     foo(arg, errp);
8fced6
  *     if (*errp) { // WRONG!
8fced6
  *         handle the error...
8fced6
  *     }
8fced6
- * because errp may be NULL!
8fced6
+ * because errp may be NULL without the ERRP_GUARD() guard.
8fced6
  *
8fced6
  * But when all you do with the error is pass it on, please use
8fced6
  *     foo(arg, errp);
8fced6
@@ -160,6 +162,19 @@
8fced6
  *         handle the error...
8fced6
  *     }
8fced6
  *
8fced6
+ * Pass an existing error to the caller:
8fced6
+ *     error_propagate(errp, err);
8fced6
+ * This is rarely needed.  When @err is a local variable, use of
8fced6
+ * ERRP_GUARD() commonly results in more readable code.
8fced6
+ *
8fced6
+ * Pass an existing error to the caller with the message modified:
8fced6
+ *     error_propagate_prepend(errp, err,
8fced6
+ *                             "Could not frobnicate '%s': ", name);
8fced6
+ * This is more concise than
8fced6
+ *     error_propagate(errp, err); // don't do this
8fced6
+ *     error_prepend(errp, "Could not frobnicate '%s': ", name);
8fced6
+ * and works even when @errp is &error_fatal.
8fced6
+ *
8fced6
  * Receive and accumulate multiple errors (first one wins):
8fced6
  *     Error *err = NULL, *local_err = NULL;
8fced6
  *     foo(arg, &err;;
8fced6
@@ -187,6 +202,69 @@
8fced6
  *         error_setg(&err, ...); // WRONG!
8fced6
  *     }
8fced6
  * because this may pass a non-null err to error_setg().
8fced6
+ *
8fced6
+ * = Why, when and how to use ERRP_GUARD() =
8fced6
+ *
8fced6
+ * Without ERRP_GUARD(), use of the @errp parameter is restricted:
8fced6
+ * - It must not be dereferenced, because it may be null.
8fced6
+ * - It should not be passed to error_prepend() or
8fced6
+ *   error_append_hint(), because that doesn't work with &error_fatal.
8fced6
+ * ERRP_GUARD() lifts these restrictions.
8fced6
+ *
8fced6
+ * To use ERRP_GUARD(), add it right at the beginning of the function.
8fced6
+ * @errp can then be used without worrying about the argument being
8fced6
+ * NULL or &error_fatal.
8fced6
+ *
8fced6
+ * Using it when it's not needed is safe, but please avoid cluttering
8fced6
+ * the source with useless code.
8fced6
+ *
8fced6
+ * = Converting to ERRP_GUARD() =
8fced6
+ *
8fced6
+ * To convert a function to use ERRP_GUARD():
8fced6
+ *
8fced6
+ * 0. If the Error ** parameter is not named @errp, rename it to
8fced6
+ *    @errp.
8fced6
+ *
8fced6
+ * 1. Add an ERRP_GUARD() invocation, by convention right at the
8fced6
+ *    beginning of the function.  This makes @errp safe to use.
8fced6
+ *
8fced6
+ * 2. Replace &err by errp, and err by *errp.  Delete local variable
8fced6
+ *    @err.
8fced6
+ *
8fced6
+ * 3. Delete error_propagate(errp, *errp), replace
8fced6
+ *    error_propagate_prepend(errp, *errp, ...) by error_prepend(errp, ...)
8fced6
+ *
8fced6
+ * 4. Ensure @errp is valid at return: when you destroy *errp, set
8fced6
+ *    errp = NULL.
8fced6
+ *
8fced6
+ * Example:
8fced6
+ *
8fced6
+ *     bool fn(..., Error **errp)
8fced6
+ *     {
8fced6
+ *         Error *err = NULL;
8fced6
+ *
8fced6
+ *         foo(arg, &err;;
8fced6
+ *         if (err) {
8fced6
+ *             handle the error...
8fced6
+ *             error_propagate(errp, err);
8fced6
+ *             return false;
8fced6
+ *         }
8fced6
+ *         ...
8fced6
+ *     }
8fced6
+ *
8fced6
+ * becomes
8fced6
+ *
8fced6
+ *     bool fn(..., Error **errp)
8fced6
+ *     {
8fced6
+ *         ERRP_GUARD();
8fced6
+ *
8fced6
+ *         foo(arg, errp);
8fced6
+ *         if (*errp) {
8fced6
+ *             handle the error...
8fced6
+ *             return false;
8fced6
+ *         }
8fced6
+ *         ...
8fced6
+ *     }
8fced6
  */
8fced6
 
8fced6
 #ifndef ERROR_H
8fced6
@@ -287,6 +365,7 @@ void error_setg_win32_internal(Error **errp,
8fced6
  * the error object.
8fced6
  * Else, move the error object from @local_err to *@dst_errp.
8fced6
  * On return, @local_err is invalid.
8fced6
+ * Please use ERRP_GUARD() instead when possible.
8fced6
  * Please don't error_propagate(&error_fatal, ...), use
8fced6
  * error_report_err() and exit(), because that's more obvious.
8fced6
  */
8fced6
@@ -298,6 +377,7 @@ void error_propagate(Error **dst_errp, Error *local_err);
8fced6
  * Behaves like
8fced6
  *     error_prepend(&local_err, fmt, ...);
8fced6
  *     error_propagate(dst_errp, local_err);
8fced6
+ * Please use ERRP_GUARD() and error_prepend() instead when possible.
8fced6
  */
8fced6
 void error_propagate_prepend(Error **dst_errp, Error *local_err,
8fced6
                              const char *fmt, ...);
8fced6
@@ -395,6 +475,46 @@ void error_set_internal(Error **errp,
8fced6
                         ErrorClass err_class, const char *fmt, ...)
8fced6
     GCC_FMT_ATTR(6, 7);
8fced6
 
8fced6
+/*
8fced6
+ * Make @errp parameter easier to use regardless of argument value
8fced6
+ *
8fced6
+ * This macro is for use right at the beginning of a function that
8fced6
+ * takes an Error **errp parameter to pass errors to its caller.  The
8fced6
+ * parameter must be named @errp.
8fced6
+ *
8fced6
+ * It must be used when the function dereferences @errp or passes
8fced6
+ * @errp to error_prepend(), error_vprepend(), or error_append_hint().
8fced6
+ * It is safe to use even when it's not needed, but please avoid
8fced6
+ * cluttering the source with useless code.
8fced6
+ *
8fced6
+ * If @errp is NULL or &error_fatal, rewrite it to point to a local
8fced6
+ * Error variable, which will be automatically propagated to the
8fced6
+ * original @errp on function exit.
8fced6
+ *
8fced6
+ * Note: &error_abort is not rewritten, because that would move the
8fced6
+ * abort from the place where the error is created to the place where
8fced6
+ * it's propagated.
8fced6
+ */
8fced6
+#define ERRP_GUARD()                                            \
8fced6
+    g_auto(ErrorPropagator) _auto_errp_prop = {.errp = errp};   \
8fced6
+    do {                                                        \
8fced6
+        if (!errp || errp == &error_fatal) {                    \
8fced6
+            errp = &_auto_errp_prop.local_err;                  \
8fced6
+        }                                                       \
8fced6
+    } while (0)
8fced6
+
8fced6
+typedef struct ErrorPropagator {
8fced6
+    Error *local_err;
8fced6
+    Error **errp;
8fced6
+} ErrorPropagator;
8fced6
+
8fced6
+static inline void error_propagator_cleanup(ErrorPropagator *prop)
8fced6
+{
8fced6
+    error_propagate(prop->errp, prop->local_err);
8fced6
+}
8fced6
+
8fced6
+G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(ErrorPropagator, error_propagator_cleanup);
8fced6
+
8fced6
 /*
8fced6
  * Special error destination to abort on error.
8fced6
  * See error_setg() and error_propagate() for details.
8fced6
-- 
8fced6
2.27.0
8fced6