|
|
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 |
|