From nobody Fri Nov 14 00:58:44 2025 Delivered-To: importer@patchew.org Received-SPF: none (zohomail.com: 192.237.175.120 is neither permitted nor denied by domain of lists.xenproject.org) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; spf=none (zohomail.com: 192.237.175.120 is neither permitted nor denied by domain of lists.xenproject.org) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail(p=none dis=none) header.from=virtuozzo.com ARC-Seal: i=1; a=rsa-sha256; t=1583471824; cv=none; d=zohomail.com; s=zohoarc; b=HmGOobM2w4MImNUBdzgI8wQSHqkNxJfk2xzVtBOHph3rPtnMtADOpF2kGKvyqykHz2aKFzUp8aTjd9nLWp3hLUcKULjYcjXjXoII5J1+0DLixBGjPO5Ik4sb2FBmo729a/uCmxCoA2mOBZguF170utZ1uNStLfSVoUupMVb3tt8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1583471824; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=NqBrSU7Zd4Vhz052EGFIa0pBneaTdFY2SdHClXxhhqU=; b=jnlxq2s0L90dfnTvoQXZk4o8XdJORtZbXvJd+2A6JvvXgBNrLobIUqM4xNlaOwiPUpsvlAFjs8+U60DGm0r9Q2D3QZBCVv+D1voMH+wo201aYyggdaozwPxbSPOxEvwr/VkDV4/WXMDNZAvZCfBsfQgxMbYFi/u2GNiXi1AOx6E= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=none (zohomail.com: 192.237.175.120 is neither permitted nor denied by domain of lists.xenproject.org) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1583471824431881.5024917716667; Thu, 5 Mar 2020 21:17:04 -0800 (PST) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jA5LF-0005TV-UY; Fri, 06 Mar 2020 05:16:09 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.89) (envelope-from ) id 1jA5LE-0005TP-SY for xen-devel@lists.xenproject.org; Fri, 06 Mar 2020 05:16:08 +0000 Received: from relay.sw.ru (unknown [185.231.240.75]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id 95496926-5f69-11ea-a720-12813bfff9fa; Fri, 06 Mar 2020 05:16:07 +0000 (UTC) Received: from vovaso.qa.sw.ru ([10.94.3.0] helo=kvm.qa.sw.ru) by relay.sw.ru with esmtp (Exim 4.92.3) (envelope-from ) id 1jA5Km-0001tg-16; Fri, 06 Mar 2020 08:15:40 +0300 X-Inumbo-ID: 95496926-5f69-11ea-a720-12813bfff9fa From: Vladimir Sementsov-Ogievskiy To: qemu-devel@nongnu.org Date: Fri, 6 Mar 2020 08:15:27 +0300 Message-Id: <20200306051536.27803-2-vsementsov@virtuozzo.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20200306051536.27803-1-vsementsov@virtuozzo.com> References: <20200306051536.27803-1-vsementsov@virtuozzo.com> MIME-Version: 1.0 Subject: [Xen-devel] [PATCH v8 01/10] error: auto propagated local_err X-BeenThere: xen-devel@lists.xenproject.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , vsementsov@virtuozzo.com, Laszlo Ersek , qemu-block@nongnu.org, Paul Durrant , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , Christian Schoenebeck , Greg Kurz , armbru@redhat.com, Stefano Stabellini , Gerd Hoffmann , Stefan Hajnoczi , Anthony Perard , xen-devel@lists.xenproject.org, Max Reitz , Eric Blake , Michael Roth , Stefan Berger Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Errors-To: xen-devel-bounces@lists.xenproject.org Sender: "Xen-devel" 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 Reviewed-by: Eric Blake Reviewed-by: Greg Kurz Reviewed-by: Paul Durrant --- Cc: Eric Blake Cc: Kevin Wolf Cc: Max Reitz Cc: Greg Kurz Cc: Christian Schoenebeck Cc: Stefano Stabellini Cc: Anthony Perard Cc: Paul Durrant Cc: Stefan Hajnoczi Cc: "Philippe Mathieu-Daud=C3=A9" Cc: Laszlo Ersek Cc: Gerd Hoffmann Cc: Stefan Berger Cc: Markus Armbruster Cc: Michael Roth Cc: qemu-block@nongnu.org Cc: qemu-devel@nongnu.org Cc: xen-devel@lists.xenproject.org include/qapi/error.h | 203 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 170 insertions(+), 33 deletions(-) diff --git a/include/qapi/error.h b/include/qapi/error.h index ad5b6e896d..bb9bcf02fb 100644 --- a/include/qapi/error.h +++ b/include/qapi/error.h @@ -15,6 +15,8 @@ /* * Error reporting system loosely patterned after Glib's GError. * + * =3D Deal with Error object =3D + * * Create an error: * error_setg(&err, "situation normal, all fouled up"); * @@ -47,28 +49,88 @@ * reporting it (primarily useful in testsuites): * error_free_or_abort(&err); * - * Pass an existing error to the caller: - * error_propagate(errp, err); - * where Error **errp is a parameter, by convention the last one. + * =3D Deal with Error ** function parameter =3D * - * Pass an existing error to the caller with the message modified: - * error_propagate_prepend(errp, err); + * Function may use error system to return errors. In this case function + * defines Error **errp parameter, which should be the last one (except for + * functions which varidic argument list), which has the following API: * - * Avoid - * error_propagate(errp, err); - * error_prepend(errp, "Could not frobnicate '%s': ", name); - * because this fails to prepend when @errp is &error_fatal. + * Caller may pass as errp: + * 1. &error_abort + * This means abort on any error + * 2. &error_fatal + * Exit with non-zero return code on error + * 3. NULL + * Ignore errors + * 4. Another value + * On error allocate error object and set errp * - * Create a new error and pass it to the caller: - * error_setg(errp, "situation normal, all fouled up"); + * Error API functions with Error ** (like error_setg) argument supports t= hese + * rules, so user functions just need to use them appropriately (read belo= w). * - * Call a function and receive an error from it: + * Simple pass error to the caller: + * error_setg(errp, "Some error"); + * + * Subcall of another errp-based function, passing the error to the caller + * f(..., errp); + * + * =3D=3D Checking success of subcall =3D=3D + * + * If function returns error code in addition to errp (which is recommende= d), + * you don't need any additional code, just do: + * int ret =3D f(..., errp); + * if (ret < 0) { + * ... handle error ... + * return ret; + * } + * + * If function returns nothing (which is not recommended API) and the only= way + * to check success is checking errp, we must care about cases [1-3] above= . We + * need to use macro ERRP_AUTO_PROPAGATE (see below for details) like this: + * + * int our_func(..., Error **errp) { + * ERRP_AUTO_PROPAGATE(); + * ... + * subcall(..., errp); + * if (*errp) { + * ... + * return -ERRNO; + * } + * ... + * } + * + * ERRP_AUTO_PROPAGATE cares about Error ** API, wraps original errp if ne= eded, + * so that it can be safely used (including dereferencing), and auto-propa= gates + * error to original errp on function end. + * + * In some cases, we need to check result of subcall, but do not want to + * propagate the Error object to our caller. In such cases we don't need + * ERRP_AUTO_PROPAGATE, but just a local Error object: + * + * Receive an error and not pass it: * Error *err =3D NULL; - * foo(arg, &err); + * subcall(arg, &err); * if (err) { * handle the error... + * error_free(err); * } * + * Note, that before ERRP_AUTO_PROPAGATE introduction the pattern above (w= ith + * error_propagate() instead of error_free()) was used to check and pass e= rror + * to the caller. Now this is DEPRECATED* (see below). + * + * Note also, that if you want to use error_append_hint/error_prepend or t= heir + * variants, you must use ERRP_AUTO_PROPAGATE too. Otherwise, in case of + * error_fatal, you'll miss the chance to insert your additional informati= on + * into Error object. + * + * In rare cases, we need to pass existing Error object to the caller by h= and: + * error_propagate(errp, err); + * + * Pass an existing error to the caller with the message modified: + * error_propagate_prepend(errp, err); + * + * * Call a function ignoring errors: * foo(arg, NULL); * @@ -78,26 +140,6 @@ * Call a function treating errors as fatal: * foo(arg, &error_fatal); * - * Receive an error and pass it on to the caller: - * Error *err =3D NULL; - * foo(arg, &err); - * if (err) { - * handle the error... - * error_propagate(errp, err); - * } - * where Error **errp is a parameter, by convention the last one. - * - * Do *not* "optimize" this to - * foo(arg, errp); - * if (*errp) { // WRONG! - * handle the error... - * } - * because errp may be NULL! - * - * But when all you do with the error is pass it on, please use - * foo(arg, errp); - * for readability. - * * Receive and accumulate multiple errors (first one wins): * Error *err =3D NULL, *local_err =3D NULL; * foo(arg, &err); @@ -114,6 +156,61 @@ * handle the error... * } * because this may pass a non-null err to bar(). + * + * DEPRECATED* + * + * The following pattern of receiving checking and passing the caller of t= he + * error by hand is deprecated now: + * + * Error *err =3D NULL; + * foo(arg, &err); + * if (err) { + * handle the error... + * error_propagate(errp, err); + * } + * + * Instead, use ERRP_AUTO_PROPAGATE macro (defined below). + * + * The old pattern is 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 sta= rt, + * 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 =3D 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; + * } + * ... + * } */ =20 #ifndef ERROR_H @@ -322,6 +419,46 @@ void error_set_internal(Error **errp, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(6, 7); =20 +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 origi= nal + * 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. + */ +#define ERRP_AUTO_PROPAGATE() \ + g_auto(ErrorPropagator) _auto_errp_prop =3D {.errp =3D errp}; \ + do { \ + if (!errp || errp =3D=3D &error_fatal) { \ + errp =3D &_auto_errp_prop.local_err; \ + } \ + } while (0) + /* * Special error destination to abort on error. * See error_setg() and error_propagate() for details. --=20 2.21.0 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xenproject.org https://lists.xenproject.org/mailman/listinfo/xen-devel