[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v7 02/11] error: auto propagated local_err
From: |
Markus Armbruster |
Subject: |
Re: [PATCH v7 02/11] error: auto propagated local_err |
Date: |
Fri, 21 Feb 2020 10:19:22 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux) |
Vladimir Sementsov-Ogievskiy <address@hidden> writes:
> Here is introduced ERRP_AUTO_PROPAGATE macro, to be used at start of
> functions with an errp OUT parameter.
>
> It has three goals:
>
> 1. Fix issue with error_fatal and error_prepend/error_append_hint: user
> can't see this additional information, because exit() happens in
> error_setg earlier than information is added. [Reported by Greg Kurz]
>
> 2. Fix issue with error_abort and error_propagate: when we wrap
> error_abort by local_err+error_propagate, the resulting coredump will
> refer to error_propagate and not to the place where error happened.
> (the macro itself doesn't fix the issue, but it allows us to [3.] drop
> the local_err+error_propagate pattern, which will definitely fix the
> issue) [Reported by Kevin Wolf]
>
> 3. Drop local_err+error_propagate pattern, which is used to workaround
> void functions with errp parameter, when caller wants to know resulting
> status. (Note: actually these functions could be merely updated to
> return int error code).
>
> To achieve these goals, later patches will add invocations
> of this macro at the start of functions with either use
> error_prepend/error_append_hint (solving 1) or which use
> local_err+error_propagate to check errors, switching those
> functions to use *errp instead (solving 2 and 3).
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy <address@hidden>
> Reviewed-by: Greg Kurz <address@hidden>
> Reviewed-by: Eric Blake <address@hidden>
> ---
>
> CC: Eric Blake <address@hidden>
> CC: Kevin Wolf <address@hidden>
> CC: Max Reitz <address@hidden>
> CC: Greg Kurz <address@hidden>
> CC: Stefano Stabellini <address@hidden>
> CC: Anthony Perard <address@hidden>
> CC: Paul Durrant <address@hidden>
> CC: Stefan Hajnoczi <address@hidden>
> CC: "Philippe Mathieu-Daudé" <address@hidden>
> CC: Laszlo Ersek <address@hidden>
> CC: Gerd Hoffmann <address@hidden>
> CC: Stefan Berger <address@hidden>
> CC: Markus Armbruster <address@hidden>
> CC: Michael Roth <address@hidden>
> CC: address@hidden
> CC: address@hidden
>
> include/qapi/error.h | 83 +++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 82 insertions(+), 1 deletion(-)
>
> diff --git a/include/qapi/error.h b/include/qapi/error.h
> index d34987148d..b9452d4806 100644
> --- a/include/qapi/error.h
> +++ b/include/qapi/error.h
> @@ -78,7 +78,7 @@
> * Call a function treating errors as fatal:
> * foo(arg, &error_fatal);
> *
> - * Receive an error and pass it on to the caller:
> + * Receive an error and pass it on to the caller (DEPRECATED*):
> * Error *err = NULL;
> * foo(arg, &err);
> * if (err) {
> @@ -98,6 +98,50 @@
> * foo(arg, errp);
> * for readability.
> *
> + * DEPRECATED* This pattern is deprecated now, the use ERRP_AUTO_PROPAGATE
> macro
> + * instead (defined below).
> + * It's deprecated because of two things:
> + *
> + * 1. Issue with error_abort and error_propagate: when we wrap error_abort by
> + * local_err+error_propagate, the resulting coredump will refer to
> + * error_propagate and not to the place where error happened.
> + *
> + * 2. A lot of extra code of the same pattern
> + *
> + * How to update old code to use ERRP_AUTO_PROPAGATE?
> + *
> + * All you need is to add ERRP_AUTO_PROPAGATE() invocation at function start,
> + * than you may safely dereference errp to check errors and do not need any
> + * additional local Error variables or calls to error_propagate().
> + *
> + * Example:
> + *
> + * old code
> + *
> + * void fn(..., Error **errp) {
> + * Error *err = NULL;
> + * foo(arg, &err);
> + * if (err) {
> + * handle the error...
> + * error_propagate(errp, err);
> + * return;
> + * }
> + * ...
> + * }
> + *
> + * updated code
> + *
> + * void fn(..., Error **errp) {
> + * ERRP_AUTO_PROPAGATE();
> + * foo(arg, errp);
> + * if (*errp) {
> + * handle the error...
> + * return;
> + * }
> + * ...
> + * }
> + *
> + *
> * Receive and accumulate multiple errors (first one wins):
> * Error *err = NULL, *local_err = NULL;
> * foo(arg, &err);
Let's explain what should be done *first*, and only then talk about the
deprecated pattern and how to convert it to current usage.
> @@ -348,6 +392,43 @@ void error_set_internal(Error **errp,
> ErrorClass err_class, const char *fmt, ...)
> GCC_FMT_ATTR(6, 7);
>
> +typedef struct ErrorPropagator {
> + Error *local_err;
> + Error **errp;
> +} ErrorPropagator;
> +
> +static inline void error_propagator_cleanup(ErrorPropagator *prop)
> +{
> + error_propagate(prop->errp, prop->local_err);
> +}
> +
> +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(ErrorPropagator, error_propagator_cleanup);
> +
> +/*
> + * ERRP_AUTO_PROPAGATE
> + *
> + * This macro is created to be the first line of a function which use
> + * Error **errp parameter to report error. It's needed only in cases where we
> + * want to use error_prepend, error_append_hint or dereference *errp. It's
> + * still safe (but useless) in other cases.
> + *
> + * If errp is NULL or points to error_fatal, it is rewritten to point to a
> + * local Error object, which will be automatically propagated to the original
> + * errp on function exit (see error_propagator_cleanup).
> + *
> + * After invocation of this macro it is always safe to dereference errp
> + * (as it's not NULL anymore) and to add information by error_prepend or
> + * error_append_hint (as, if it was error_fatal, we swapped it with a
> + * local_error to be propagated on cleanup).
> + *
> + * Note: we don't wrap the error_abort case, as we want resulting coredump
> + * to point to the place where the error happened, not to error_propagate.
Tradeoff: we gain more useful backtraces, we lose message improvements
from error_prepend(), error_append_hint() and such, if any. Makes
sense.
> + */
The comment's contents looks okay to me. I'll want to tweak formatting
to better blend in with the rest of this file, but let's not worry about
that now.
> +#define ERRP_AUTO_PROPAGATE() \
> + g_auto(ErrorPropagator) _auto_errp_prop = {.errp = errp}; \
> + errp = ((errp == NULL || *errp == error_fatal) \
> + ? &_auto_errp_prop.local_err : errp)
> +
> /*
> * Special error destination to abort on error.
> * See error_setg() and error_propagate() for details.
*errp == error_fatal tests *errp == NULL, which is not what you want.
You need to test errp == &error_fatal, just like error_handle_fatal().
Superfluous parenthesis around the first operand of ?:.
Wouldn't
#define ERRP_AUTO_PROPAGATE() \
g_auto(ErrorPropagator) _auto_errp_prop = {.errp = errp}; \
if (!errp || errp == &error_fatal) { \
errp = &_auto_errp_prop.local_err; \
}
be clearer?
- Re: [PATCH v7 02/11] error: auto propagated local_err,
Markus Armbruster <=