1 // Use ERRP_GUARD() (see include/qapi/error.h)
3 // Copyright (c) 2020 Virtuozzo International GmbH.
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see
17 // <http://www.gnu.org/licenses/>.
20 // spatch --sp-file scripts/coccinelle/errp-guard.cocci \
21 // --macro-file scripts/cocci-macro-file.h --in-place \
22 // --no-show-diff --max-width 80 FILES...
24 // Note: --max-width 80 is needed because coccinelle default is less
25 // than 80, and without this parameter coccinelle may reindent some
26 // lines which fit into 80 characters but not to coccinelle default,
27 // which in turn produces extra patch hunks for no reason.
29 // Switch unusual Error ** parameter names to errp
30 // (this is necessary to use ERRP_GUARD).
32 // Disable optional_qualifier to skip functions with
33 // "Error *const *errp" parameter.
35 // Skip functions with "assert(_errp && *_errp)" statement, because
36 // that signals unusual semantics, and the parameter name may well
37 // serve a purpose. (like nbd_iter_channel_error()).
39 // Skip util/error.c to not touch, for example, error_propagate() and
40 // error_propagate_prepend().
41 @ depends on !(file in "util/error.c") disable optional_qualifier@
43 identifier _errp != errp;
52 ... when != assert(_errp && *_errp)
61 // Add invocation of ERRP_GUARD() to errp-functions where // necessary
63 // Note, that without "when any" the final "..." does not mach
64 // something matched by previous pattern, i.e. the rule will not match
65 // double error_prepend in control flow like in
66 // vfio_set_irq_signaling().
68 // Note, "exists" says that we want apply rule even if it does not
69 // match on all possible control flows (otherwise, it will not match
70 // standard pattern when error_propagate() call is in if branch).
71 @ disable optional_qualifier exists@
72 identifier fn, local_err;
76 fn(..., Error **errp, ...)
79 ... when != ERRP_GUARD();
82 error_append_hint(errp, ...);
84 error_prepend(errp, ...);
86 error_vprepend(errp, ...);
90 Error *local_err = NULL;
93 error_propagate_prepend(errp, local_err, ...);
95 error_propagate(errp, local_err);
101 // Warn when several Error * definitions are in the control flow.
102 // This rule is not chained to rule1 and less restrictive, to cover more
103 // functions to warn (even those we are not going to convert).
105 // Note, that even with one (or zero) Error * definition in the each
106 // control flow we may have several (in total) Error * definitions in
107 // the function. This case deserves attention too, but I don't see
108 // simple way to match with help of coccinelle.
109 @check1 disable optional_qualifier exists@
110 identifier fn, _errp, local_err, local_err2;
114 fn(..., Error **_errp, ...)
117 Error *local_err = NULL;@p1
119 Error *local_err2 = NULL;@p2
129 print('Warning: function {} has several definitions of '
130 'Error * local variable: at {}:{} and then at {}:{}'.format(
131 fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
133 // Warn when several propagations are in the control flow.
134 @check2 disable optional_qualifier exists@
135 identifier fn, _errp;
139 fn(..., Error **_errp, ...)
143 error_propagate_prepend(_errp, ...);@p1
145 error_propagate(_errp, ...);@p1
149 error_propagate_prepend(_errp, ...);@p2
151 error_propagate(_errp, ...);@p2
162 print('Warning: function {} propagates to errp several times in '
163 'one control flow: at {}:{} and then at {}:{}'.format(
164 fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
166 // Match functions with propagation of local error to errp.
167 // We want to refer these functions in several following rules, but I
168 // don't know a proper way to inherit a function, not just its name
169 // (to not match another functions with same name in following rules).
170 // Not-proper way is as follows: rename errp parameter in functions
171 // header and match it in following rules. Rename it back after all
174 // The common case is a single definition of local_err with at most one
175 // error_propagate_prepend() or error_propagate() on each control-flow
176 // path. Functions with multiple definitions or propagates we want to
177 // examine manually. Rules check1 and check2 emit warnings to guide us
180 // Note that we match not only this "common case", but any function,
181 // which has the "common case" on at least one control-flow path.
182 @rule1 disable optional_qualifier exists@
183 identifier fn, local_err;
193 Error *local_err = NULL;
196 error_propagate_prepend(errp, local_err, ...);
198 error_propagate(errp, local_err);
203 // Convert special case with goto separately.
204 // I tried merging this into the following rule the obvious way, but
205 // it made Coccinelle hang on block.c
207 // Note interesting thing: if we don't do it here, and try to fixup
208 // "out: }" things later after all transformations (the rule will be
209 // the same, just without error_propagate() call), coccinelle fails to
210 // match this "out: }".
211 @ disable optional_qualifier@
212 identifier rule1.fn, rule1.local_err, out;
216 fn(..., Error ** ____, ...)
223 - error_propagate(errp, local_err);
226 // Convert most of local_err related stuff.
228 // Note, that we inherit rule1.fn and rule1.local_err names, not
229 // objects themselves. We may match something not related to the
230 // pattern matched by rule1. For example, local_err may be defined with
231 // the same name in different blocks inside one function, and in one
232 // block follow the propagation pattern and in other block doesn't.
234 // Note also that errp-cleaning functions
237 // error_reportf_errp
240 // are not yet implemented. They must call corresponding Error* -
241 // freeing function and then set *errp to NULL, to avoid further
242 // propagation to original errp (consider ERRP_GUARD in use).
243 // For example, error_free_errp may look like this:
245 // void error_free_errp(Error **errp)
247 // error_free(*errp);
250 @ disable optional_qualifier exists@
251 identifier rule1.fn, rule1.local_err;
252 expression list args;
256 fn(..., Error ** ____, ...)
260 - Error *local_err = NULL;
263 // Convert error clearing functions
265 - error_free(local_err);
266 + error_free_errp(errp);
268 - error_report_err(local_err);
269 + error_report_errp(errp);
271 - error_reportf_err(local_err, args);
272 + error_reportf_errp(errp, args);
274 - warn_report_err(local_err);
275 + warn_report_errp(errp);
277 - warn_reportf_err(local_err, args);
278 + warn_reportf_errp(errp, args);
283 - error_propagate_prepend(errp, local_err, args);
284 + error_prepend(errp, args);
286 - error_propagate(errp, local_err);
294 // Convert remaining local_err usage. For example, different kinds of
295 // error checking in if conditionals. We can't merge this into
296 // previous hunk, as this conflicts with other substitutions in it (at
297 // least with "- local_err = NULL").
298 @ disable optional_qualifier@
299 identifier rule1.fn, rule1.local_err;
303 fn(..., Error ** ____, ...)
311 // Always use the same pattern for checking error
312 @ disable optional_qualifier@
317 fn(..., Error ** ____, ...)
325 // Revert temporary ___ identifier.
326 @ disable optional_qualifier@