Skip to content

Commit ae7c80a

Browse files
Vladimir Sementsov-OgievskiyMarkus Armbruster
authored andcommitted
error: New macro ERRP_GUARD()
Introduce a new ERRP_GUARD() 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: the 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 <[email protected]> Reviewed-by: Paul Durrant <[email protected]> Reviewed-by: Greg Kurz <[email protected]> Reviewed-by: Eric Blake <[email protected]> [Merge comments properly with recent commit "error: Document Error API usage rules", and edit for clarity. Put ERRP_AUTO_PROPAGATE() before its helpers, and touch up style. Tweak commit message.] Signed-off-by: Markus Armbruster <[email protected]> Message-Id: <[email protected]> [Rename ERRP_AUTO_PROPAGATE() to ERRP_GUARD(), tweak commit message again]
1 parent a43770d commit ae7c80a

File tree

1 file changed

+139
-19
lines changed

1 file changed

+139
-19
lines changed

include/qapi/error.h

Lines changed: 139 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030
* job. Since the value of @errp is about handling the error, the
3131
* function should not examine it.
3232
*
33+
* - The function may pass @errp to functions it calls to pass on
34+
* their errors to its caller. If it dereferences @errp to check
35+
* for errors, it must use ERRP_GUARD().
36+
*
3337
* - On success, the function should not touch *errp. On failure, it
3438
* should set a new error, e.g. with error_setg(errp, ...), or
3539
* propagate an existing one, e.g. with error_propagate(errp, ...).
@@ -45,15 +49,17 @@
4549
* = Creating errors =
4650
*
4751
* Create an error:
48-
* error_setg(&err, "situation normal, all fouled up");
52+
* error_setg(errp, "situation normal, all fouled up");
53+
* where @errp points to the location to receive the error.
4954
*
5055
* Create an error and add additional explanation:
51-
* error_setg(&err, "invalid quark");
52-
* error_append_hint(&err, "Valid quarks are up, down, strange, "
56+
* error_setg(errp, "invalid quark");
57+
* error_append_hint(errp, "Valid quarks are up, down, strange, "
5358
* "charm, top, bottom.\n");
59+
* This may require use of ERRP_GUARD(); more on that below.
5460
*
5561
* Do *not* contract this to
56-
* error_setg(&err, "invalid quark\n" // WRONG!
62+
* error_setg(errp, "invalid quark\n" // WRONG!
5763
* "Valid quarks are up, down, strange, charm, top, bottom.");
5864
*
5965
* = Reporting and destroying errors =
@@ -107,18 +113,6 @@
107113
* Errors get passed to the caller through the conventional @errp
108114
* parameter.
109115
*
110-
* Pass an existing error to the caller:
111-
* error_propagate(errp, err);
112-
* where Error **errp is a parameter, by convention the last one.
113-
*
114-
* Pass an existing error to the caller with the message modified:
115-
* error_propagate_prepend(errp, err,
116-
* "Could not frobnicate '%s': ", name);
117-
* This is more concise than
118-
* error_propagate(errp, err); // don't do this
119-
* error_prepend(errp, "Could not frobnicate '%s': ", name);
120-
* and works even when @errp is &error_fatal.
121-
*
122116
* Create a new error and pass it to the caller:
123117
* error_setg(errp, "situation normal, all fouled up");
124118
*
@@ -129,18 +123,26 @@
129123
* handle the error...
130124
* }
131125
* - when it does not, say because it is a void function:
126+
* ERRP_GUARD();
127+
* foo(arg, errp);
128+
* if (*errp) {
129+
* handle the error...
130+
* }
131+
* More on ERRP_GUARD() below.
132+
*
133+
* Code predating ERRP_GUARD() still exists, and looks like this:
132134
* Error *err = NULL;
133135
* foo(arg, &err);
134136
* if (err) {
135137
* handle the error...
136-
* error_propagate(errp, err);
138+
* error_propagate(errp, err); // deprecated
137139
* }
138-
* Do *not* "optimize" this to
140+
* Avoid in new code. Do *not* "optimize" it to
139141
* foo(arg, errp);
140142
* if (*errp) { // WRONG!
141143
* handle the error...
142144
* }
143-
* because errp may be NULL!
145+
* because errp may be NULL without the ERRP_GUARD() guard.
144146
*
145147
* But when all you do with the error is pass it on, please use
146148
* foo(arg, errp);
@@ -160,6 +162,19 @@
160162
* handle the error...
161163
* }
162164
*
165+
* Pass an existing error to the caller:
166+
* error_propagate(errp, err);
167+
* This is rarely needed. When @err is a local variable, use of
168+
* ERRP_GUARD() commonly results in more readable code.
169+
*
170+
* Pass an existing error to the caller with the message modified:
171+
* error_propagate_prepend(errp, err,
172+
* "Could not frobnicate '%s': ", name);
173+
* This is more concise than
174+
* error_propagate(errp, err); // don't do this
175+
* error_prepend(errp, "Could not frobnicate '%s': ", name);
176+
* and works even when @errp is &error_fatal.
177+
*
163178
* Receive and accumulate multiple errors (first one wins):
164179
* Error *err = NULL, *local_err = NULL;
165180
* foo(arg, &err);
@@ -187,6 +202,69 @@
187202
* error_setg(&err, ...); // WRONG!
188203
* }
189204
* because this may pass a non-null err to error_setg().
205+
*
206+
* = Why, when and how to use ERRP_GUARD() =
207+
*
208+
* Without ERRP_GUARD(), use of the @errp parameter is restricted:
209+
* - It must not be dereferenced, because it may be null.
210+
* - It should not be passed to error_prepend() or
211+
* error_append_hint(), because that doesn't work with &error_fatal.
212+
* ERRP_GUARD() lifts these restrictions.
213+
*
214+
* To use ERRP_GUARD(), add it right at the beginning of the function.
215+
* @errp can then be used without worrying about the argument being
216+
* NULL or &error_fatal.
217+
*
218+
* Using it when it's not needed is safe, but please avoid cluttering
219+
* the source with useless code.
220+
*
221+
* = Converting to ERRP_GUARD() =
222+
*
223+
* To convert a function to use ERRP_GUARD():
224+
*
225+
* 0. If the Error ** parameter is not named @errp, rename it to
226+
* @errp.
227+
*
228+
* 1. Add an ERRP_GUARD() invocation, by convention right at the
229+
* beginning of the function. This makes @errp safe to use.
230+
*
231+
* 2. Replace &err by errp, and err by *errp. Delete local variable
232+
* @err.
233+
*
234+
* 3. Delete error_propagate(errp, *errp), replace
235+
* error_propagate_prepend(errp, *errp, ...) by error_prepend(errp, ...)
236+
*
237+
* 4. Ensure @errp is valid at return: when you destroy *errp, set
238+
* errp = NULL.
239+
*
240+
* Example:
241+
*
242+
* bool fn(..., Error **errp)
243+
* {
244+
* Error *err = NULL;
245+
*
246+
* foo(arg, &err);
247+
* if (err) {
248+
* handle the error...
249+
* error_propagate(errp, err);
250+
* return false;
251+
* }
252+
* ...
253+
* }
254+
*
255+
* becomes
256+
*
257+
* bool fn(..., Error **errp)
258+
* {
259+
* ERRP_GUARD();
260+
*
261+
* foo(arg, errp);
262+
* if (*errp) {
263+
* handle the error...
264+
* return false;
265+
* }
266+
* ...
267+
* }
190268
*/
191269

192270
#ifndef ERROR_H
@@ -287,6 +365,7 @@ void error_setg_win32_internal(Error **errp,
287365
* the error object.
288366
* Else, move the error object from @local_err to *@dst_errp.
289367
* On return, @local_err is invalid.
368+
* Please use ERRP_GUARD() instead when possible.
290369
* Please don't error_propagate(&error_fatal, ...), use
291370
* error_report_err() and exit(), because that's more obvious.
292371
*/
@@ -298,6 +377,7 @@ void error_propagate(Error **dst_errp, Error *local_err);
298377
* Behaves like
299378
* error_prepend(&local_err, fmt, ...);
300379
* error_propagate(dst_errp, local_err);
380+
* Please use ERRP_GUARD() and error_prepend() instead when possible.
301381
*/
302382
void error_propagate_prepend(Error **dst_errp, Error *local_err,
303383
const char *fmt, ...);
@@ -395,6 +475,46 @@ void error_set_internal(Error **errp,
395475
ErrorClass err_class, const char *fmt, ...)
396476
GCC_FMT_ATTR(6, 7);
397477

478+
/*
479+
* Make @errp parameter easier to use regardless of argument value
480+
*
481+
* This macro is for use right at the beginning of a function that
482+
* takes an Error **errp parameter to pass errors to its caller. The
483+
* parameter must be named @errp.
484+
*
485+
* It must be used when the function dereferences @errp or passes
486+
* @errp to error_prepend(), error_vprepend(), or error_append_hint().
487+
* It is safe to use even when it's not needed, but please avoid
488+
* cluttering the source with useless code.
489+
*
490+
* If @errp is NULL or &error_fatal, rewrite it to point to a local
491+
* Error variable, which will be automatically propagated to the
492+
* original @errp on function exit.
493+
*
494+
* Note: &error_abort is not rewritten, because that would move the
495+
* abort from the place where the error is created to the place where
496+
* it's propagated.
497+
*/
498+
#define ERRP_GUARD() \
499+
g_auto(ErrorPropagator) _auto_errp_prop = {.errp = errp}; \
500+
do { \
501+
if (!errp || errp == &error_fatal) { \
502+
errp = &_auto_errp_prop.local_err; \
503+
} \
504+
} while (0)
505+
506+
typedef struct ErrorPropagator {
507+
Error *local_err;
508+
Error **errp;
509+
} ErrorPropagator;
510+
511+
static inline void error_propagator_cleanup(ErrorPropagator *prop)
512+
{
513+
error_propagate(prop->errp, prop->local_err);
514+
}
515+
516+
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(ErrorPropagator, error_propagator_cleanup);
517+
398518
/*
399519
* Special error destination to abort on error.
400520
* See error_setg() and error_propagate() for details.

0 commit comments

Comments
 (0)