All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v9 00/10] error: auto propagated local_err part I
@ 2020-03-12  8:59 ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, vsementsov, Laszlo Ersek, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Greg Kurz, armbru, Stefano Stabellini,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Michael Roth, Stefan Berger

v9
01: A lot of rewordings [thanks to Eric]
    Still, keep all r-b marks, assuming that they are mostly about macro definition
02: significant changes are:
    1. Do not match double propagation pattern in ERRP_AUTO_PROPAGATE-adding rule
    2. Introduce errp->____->errp scheme to match only functions matched by rule1
       in rules inherited from rule1
    3. Add rules to warn about unusual patterns

    Also, add line to MAINTAINERS to keep error related coccinelle scripts under
    Error section.
07: add Christian's r-b
09: add Eric's r-b
10: a bit of context in xen_block_iothread_create  and qmp_object_add()
    signature are changed. Patch change is obvious, so I keep Paul's r-b

v9 is available at
 https://src.openvz.org/scm/~vsementsov/qemu.git #tag up-auto-local-err-partI-v9
v8 is available at
 https://src.openvz.org/scm/~vsementsov/qemu.git #tag up-auto-local-err-partI-v8

In these series, there is no commit-per-subsystem script, each generated
commit is generated in separate.

Still, generating commands are very similar, and looks like

    sed -n '/^<Subsystem name>$/,/^$/{s/^F: //p}' MAINTAINERS | \
    xargs git ls-files | grep '\.[hc]$' | \
    xargs spatch \
        --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
        --macro-file scripts/cocci-macro-file.h \
        --in-place --no-show-diff --max-width 80

Note, that in each generated commit, generation command is the only
text, indented by 8 spaces in 'git log -1' output, so, to regenerate all
commits (for example, after rebase, or change in coccinelle script), you
may use the following command:

git rebase -x "sh -c \"git show --pretty= --name-only | xargs git checkout HEAD^ -- ; git reset; git log -1 | grep '^        ' | sh\"" HEAD~7

Which will start automated interactive rebase for generated patches,
which will stop if generated patch changed
(you may do git commit --amend to apply updated generated changes).

Note:
  git show --pretty= --name-only   - lists files, changed in HEAD
  git log -1 | grep '^        ' | sh   - rerun generation command of HEAD


Check for compilation of changed .c files
git rebase -x "sh -c \"git show --pretty= --name-only | sed -n 's/\.c$/.o/p' | xargs make -j9\"" HEAD~7

Vladimir Sementsov-Ogievskiy (10):
  error: auto propagated local_err
  scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  hw/sd/ssi-sd: fix error handling in ssi_sd_realize
  SD (Secure Card): introduce ERRP_AUTO_PROPAGATE
  pflash: introduce ERRP_AUTO_PROPAGATE
  fw_cfg: introduce ERRP_AUTO_PROPAGATE
  virtio-9p: introduce ERRP_AUTO_PROPAGATE
  TPM: introduce ERRP_AUTO_PROPAGATE
  nbd: introduce ERRP_AUTO_PROPAGATE
  xen: introduce ERRP_AUTO_PROPAGATE

 scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
 include/block/nbd.h                           |   1 +
 include/qapi/error.h                          | 208 +++++++++--
 block/nbd.c                                   |  21 +-
 hw/9pfs/9p-local.c                            |  12 +-
 hw/9pfs/9p.c                                  |   1 +
 hw/block/dataplane/xen-block.c                |  17 +-
 hw/block/pflash_cfi01.c                       |   7 +-
 hw/block/pflash_cfi02.c                       |   7 +-
 hw/block/xen-block.c                          | 125 +++----
 hw/nvram/fw_cfg.c                             |  14 +-
 hw/pci-host/xen_igd_pt.c                      |   7 +-
 hw/sd/sdhci-pci.c                             |   7 +-
 hw/sd/sdhci.c                                 |  21 +-
 hw/sd/ssi-sd.c                                |  26 +-
 hw/tpm/tpm_util.c                             |   7 +-
 hw/xen/xen-backend.c                          |   7 +-
 hw/xen/xen-bus.c                              |  92 +++--
 hw/xen/xen-host-pci-device.c                  |  27 +-
 hw/xen/xen_pt.c                               |  25 +-
 hw/xen/xen_pt_config_init.c                   |  20 +-
 nbd/client.c                                  |   5 +
 nbd/server.c                                  |   5 +
 tpm.c                                         |   7 +-
 MAINTAINERS                                   |   1 +
 25 files changed, 717 insertions(+), 280 deletions(-)
 create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci

Cc: Eric Blake <eblake@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Max Reitz <mreitz@redhat.com>
Cc: Greg Kurz <groug@kaod.org>
Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Paul Durrant <paul@xen.org>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Stefan Berger <stefanb@linux.ibm.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
Cc: qemu-devel@nongnu.org
Cc: qemu-block@nongnu.org
Cc: xen-devel@lists.xenproject.org

-- 
2.21.0



^ permalink raw reply	[flat|nested] 67+ messages in thread

* [Xen-devel] [PATCH v9 00/10] error: auto propagated local_err part I
@ 2020-03-12  8:59 ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, vsementsov, Laszlo Ersek, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Greg Kurz, armbru, Stefano Stabellini,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Eric Blake, Michael Roth, Stefan Berger

v9
01: A lot of rewordings [thanks to Eric]
    Still, keep all r-b marks, assuming that they are mostly about macro definition
02: significant changes are:
    1. Do not match double propagation pattern in ERRP_AUTO_PROPAGATE-adding rule
    2. Introduce errp->____->errp scheme to match only functions matched by rule1
       in rules inherited from rule1
    3. Add rules to warn about unusual patterns

    Also, add line to MAINTAINERS to keep error related coccinelle scripts under
    Error section.
07: add Christian's r-b
09: add Eric's r-b
10: a bit of context in xen_block_iothread_create  and qmp_object_add()
    signature are changed. Patch change is obvious, so I keep Paul's r-b

v9 is available at
 https://src.openvz.org/scm/~vsementsov/qemu.git #tag up-auto-local-err-partI-v9
v8 is available at
 https://src.openvz.org/scm/~vsementsov/qemu.git #tag up-auto-local-err-partI-v8

In these series, there is no commit-per-subsystem script, each generated
commit is generated in separate.

Still, generating commands are very similar, and looks like

    sed -n '/^<Subsystem name>$/,/^$/{s/^F: //p}' MAINTAINERS | \
    xargs git ls-files | grep '\.[hc]$' | \
    xargs spatch \
        --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
        --macro-file scripts/cocci-macro-file.h \
        --in-place --no-show-diff --max-width 80

Note, that in each generated commit, generation command is the only
text, indented by 8 spaces in 'git log -1' output, so, to regenerate all
commits (for example, after rebase, or change in coccinelle script), you
may use the following command:

git rebase -x "sh -c \"git show --pretty= --name-only | xargs git checkout HEAD^ -- ; git reset; git log -1 | grep '^        ' | sh\"" HEAD~7

Which will start automated interactive rebase for generated patches,
which will stop if generated patch changed
(you may do git commit --amend to apply updated generated changes).

Note:
  git show --pretty= --name-only   - lists files, changed in HEAD
  git log -1 | grep '^        ' | sh   - rerun generation command of HEAD


Check for compilation of changed .c files
git rebase -x "sh -c \"git show --pretty= --name-only | sed -n 's/\.c$/.o/p' | xargs make -j9\"" HEAD~7

Vladimir Sementsov-Ogievskiy (10):
  error: auto propagated local_err
  scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  hw/sd/ssi-sd: fix error handling in ssi_sd_realize
  SD (Secure Card): introduce ERRP_AUTO_PROPAGATE
  pflash: introduce ERRP_AUTO_PROPAGATE
  fw_cfg: introduce ERRP_AUTO_PROPAGATE
  virtio-9p: introduce ERRP_AUTO_PROPAGATE
  TPM: introduce ERRP_AUTO_PROPAGATE
  nbd: introduce ERRP_AUTO_PROPAGATE
  xen: introduce ERRP_AUTO_PROPAGATE

 scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
 include/block/nbd.h                           |   1 +
 include/qapi/error.h                          | 208 +++++++++--
 block/nbd.c                                   |  21 +-
 hw/9pfs/9p-local.c                            |  12 +-
 hw/9pfs/9p.c                                  |   1 +
 hw/block/dataplane/xen-block.c                |  17 +-
 hw/block/pflash_cfi01.c                       |   7 +-
 hw/block/pflash_cfi02.c                       |   7 +-
 hw/block/xen-block.c                          | 125 +++----
 hw/nvram/fw_cfg.c                             |  14 +-
 hw/pci-host/xen_igd_pt.c                      |   7 +-
 hw/sd/sdhci-pci.c                             |   7 +-
 hw/sd/sdhci.c                                 |  21 +-
 hw/sd/ssi-sd.c                                |  26 +-
 hw/tpm/tpm_util.c                             |   7 +-
 hw/xen/xen-backend.c                          |   7 +-
 hw/xen/xen-bus.c                              |  92 +++--
 hw/xen/xen-host-pci-device.c                  |  27 +-
 hw/xen/xen_pt.c                               |  25 +-
 hw/xen/xen_pt_config_init.c                   |  20 +-
 nbd/client.c                                  |   5 +
 nbd/server.c                                  |   5 +
 tpm.c                                         |   7 +-
 MAINTAINERS                                   |   1 +
 25 files changed, 717 insertions(+), 280 deletions(-)
 create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci

Cc: Eric Blake <eblake@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Max Reitz <mreitz@redhat.com>
Cc: Greg Kurz <groug@kaod.org>
Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Paul Durrant <paul@xen.org>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Stefan Berger <stefanb@linux.ibm.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
Cc: qemu-devel@nongnu.org
Cc: qemu-block@nongnu.org
Cc: xen-devel@lists.xenproject.org

-- 
2.21.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* [PATCH v9 01/10] error: auto propagated local_err
  2020-03-12  8:59 ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-12  8:59   ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, vsementsov, Laszlo Ersek, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Greg Kurz, armbru, Stefano Stabellini,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Michael Roth, Stefan Berger

Introduce a new 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 <vsementsov@virtuozzo.com>
Reviewed-by: Paul Durrant <paul@xen.org>
Reviewed-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Eric Blake <eblake@redhat.com>
---

Cc: Eric Blake <eblake@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Max Reitz <mreitz@redhat.com>
Cc: Greg Kurz <groug@kaod.org>
Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Paul Durrant <paul@xen.org>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Stefan Berger <stefanb@linux.ibm.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
Cc: qemu-devel@nongnu.org
Cc: qemu-block@nongnu.org
Cc: xen-devel@lists.xenproject.org

 include/qapi/error.h | 205 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 173 insertions(+), 32 deletions(-)

diff --git a/include/qapi/error.h b/include/qapi/error.h
index ad5b6e896d..30140d9bfe 100644
--- a/include/qapi/error.h
+++ b/include/qapi/error.h
@@ -15,6 +15,8 @@
 /*
  * Error reporting system loosely patterned after Glib's GError.
  *
+ * = Deal with Error object =
+ *
  * Create an error:
  *     error_setg(&err, "situation normal, all fouled up");
  *
@@ -47,28 +49,91 @@
  * 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.
+ * = Deal with Error ** function parameter =
  *
- * Pass an existing error to the caller with the message modified:
- *     error_propagate_prepend(errp, err);
+ * A function may use the error system to return errors. In this case, the
+ * function defines an Error **errp parameter, by convention the last one (with
+ * exceptions for functions using ... or va_list).
  *
- * Avoid
- *     error_propagate(errp, err);
- *     error_prepend(errp, "Could not frobnicate '%s': ", name);
- * because this fails to prepend when @errp is &error_fatal.
+ * The caller may then pass in the following errp values:
  *
- * Create a new error and pass it to the caller:
+ * 1. &error_abort
+ *    Any error will result in abort().
+ * 2. &error_fatal
+ *    Any error will result in exit() with a non-zero status.
+ * 3. NULL
+ *    No error reporting through errp parameter.
+ * 4. The address of a NULL-initialized Error *err
+ *    Any error will populate errp with an error object.
+ *
+ * The following rules then implement the correct semantics desired by the
+ * caller.
+ *
+ * Create a new error to pass to the caller:
  *     error_setg(errp, "situation normal, all fouled up");
  *
- * Call a function and receive an error from it:
+ * Calling another errp-based function:
+ *     f(..., errp);
+ *
+ * == Checking success of subcall ==
+ *
+ * If a function returns a value indicating an error in addition to setting
+ * errp (which is recommended), then you don't need any additional code, just
+ * do:
+ *
+ *     int ret = f(..., errp);
+ *     if (ret < 0) {
+ *         ... handle error ...
+ *         return ret;
+ *     }
+ *
+ * If a function returns nothing (not recommended for new code), the only way
+ * to check success is by consulting errp; doing this safely requires the use
+ * of the ERRP_AUTO_PROPAGATE macro, like this:
+ *
+ *     int our_func(..., Error **errp) {
+ *         ERRP_AUTO_PROPAGATE();
+ *         ...
+ *         subcall(..., errp);
+ *         if (*errp) {
+ *             ...
+ *             return -EINVAL;
+ *         }
+ *         ...
+ *     }
+ *
+ * ERRP_AUTO_PROPAGATE takes care of wrapping the original errp as needed, so
+ * that the rest of the function can directly use errp (including
+ * dereferencing), where any errors will then be propagated on to the original
+ * errp when leaving the function.
+ *
+ * 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 = NULL;
- *     foo(arg, &err);
+ *     subcall(arg, &err);
  *     if (err) {
  *         handle the error...
+ *         error_free(err);
  *     }
  *
+ * Note that older code that did not use ERRP_AUTO_PROPAGATE would instead need
+ * a local Error * variable and the use of error_propagate() to properly handle
+ * all possible caller values of errp. Now this is DEPRECATED* (see below).
+ *
+ * Note that any function that wants to modify an error object, such as by
+ * calling error_append_hint or error_prepend, must use ERRP_AUTO_PROPAGATE, in
+ * order for a caller's use of &error_fatal to see the additional information.
+ *
+ * In rare cases, we need to pass existing Error object to the caller by hand:
+ *     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 +143,6 @@
  * Call a function treating errors as fatal:
  *     foo(arg, &error_fatal);
  *
- * Receive an error and pass it on to the caller:
- *     Error *err = 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 = NULL, *local_err = NULL;
  *     foo(arg, &err);
@@ -114,6 +159,61 @@
  *         handle the error...
  *     }
  * because this may pass a non-null err to bar().
+ *
+ * DEPRECATED*
+ *
+ * The following pattern of receiving, checking, and then forwarding an error
+ * to the caller by hand is now deprecated:
+ *
+ *     Error *err = NULL;
+ *     foo(arg, &err);
+ *     if (err) {
+ *         handle the error...
+ *         error_propagate(errp, err);
+ *     }
+ *
+ * Instead, use ERRP_AUTO_PROPAGATE macro.
+ *
+ * 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 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;
+ *         }
+ *         ...
+ *     }
  */
 
 #ifndef ERROR_H
@@ -322,6 +422,47 @@ 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 exists to assist with proper error handling in a function which
+ * uses an Error **errp parameter.  It must be used as the first line of a
+ * function which modifies an error (with error_prepend, error_append_hint, or
+ * similar) or which wants to dereference *errp.  It is still safe (but
+ * useless) to use in other functions.
+ *
+ * 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.
+ */
+#define ERRP_AUTO_PROPAGATE() \
+    g_auto(ErrorPropagator) _auto_errp_prop = {.errp = errp}; \
+    do { \
+        if (!errp || errp == &error_fatal) { \
+            errp = &_auto_errp_prop.local_err; \
+        } \
+    } while (0)
+
 /*
  * Special error destination to abort on error.
  * See error_setg() and error_propagate() for details.
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [Xen-devel] [PATCH v9 01/10] error: auto propagated local_err
@ 2020-03-12  8:59   ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, vsementsov, Laszlo Ersek, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Greg Kurz, armbru, Stefano Stabellini,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Eric Blake, Michael Roth, Stefan Berger

Introduce a new 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 <vsementsov@virtuozzo.com>
Reviewed-by: Paul Durrant <paul@xen.org>
Reviewed-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Eric Blake <eblake@redhat.com>
---

Cc: Eric Blake <eblake@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Max Reitz <mreitz@redhat.com>
Cc: Greg Kurz <groug@kaod.org>
Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Paul Durrant <paul@xen.org>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Stefan Berger <stefanb@linux.ibm.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
Cc: qemu-devel@nongnu.org
Cc: qemu-block@nongnu.org
Cc: xen-devel@lists.xenproject.org

 include/qapi/error.h | 205 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 173 insertions(+), 32 deletions(-)

diff --git a/include/qapi/error.h b/include/qapi/error.h
index ad5b6e896d..30140d9bfe 100644
--- a/include/qapi/error.h
+++ b/include/qapi/error.h
@@ -15,6 +15,8 @@
 /*
  * Error reporting system loosely patterned after Glib's GError.
  *
+ * = Deal with Error object =
+ *
  * Create an error:
  *     error_setg(&err, "situation normal, all fouled up");
  *
@@ -47,28 +49,91 @@
  * 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.
+ * = Deal with Error ** function parameter =
  *
- * Pass an existing error to the caller with the message modified:
- *     error_propagate_prepend(errp, err);
+ * A function may use the error system to return errors. In this case, the
+ * function defines an Error **errp parameter, by convention the last one (with
+ * exceptions for functions using ... or va_list).
  *
- * Avoid
- *     error_propagate(errp, err);
- *     error_prepend(errp, "Could not frobnicate '%s': ", name);
- * because this fails to prepend when @errp is &error_fatal.
+ * The caller may then pass in the following errp values:
  *
- * Create a new error and pass it to the caller:
+ * 1. &error_abort
+ *    Any error will result in abort().
+ * 2. &error_fatal
+ *    Any error will result in exit() with a non-zero status.
+ * 3. NULL
+ *    No error reporting through errp parameter.
+ * 4. The address of a NULL-initialized Error *err
+ *    Any error will populate errp with an error object.
+ *
+ * The following rules then implement the correct semantics desired by the
+ * caller.
+ *
+ * Create a new error to pass to the caller:
  *     error_setg(errp, "situation normal, all fouled up");
  *
- * Call a function and receive an error from it:
+ * Calling another errp-based function:
+ *     f(..., errp);
+ *
+ * == Checking success of subcall ==
+ *
+ * If a function returns a value indicating an error in addition to setting
+ * errp (which is recommended), then you don't need any additional code, just
+ * do:
+ *
+ *     int ret = f(..., errp);
+ *     if (ret < 0) {
+ *         ... handle error ...
+ *         return ret;
+ *     }
+ *
+ * If a function returns nothing (not recommended for new code), the only way
+ * to check success is by consulting errp; doing this safely requires the use
+ * of the ERRP_AUTO_PROPAGATE macro, like this:
+ *
+ *     int our_func(..., Error **errp) {
+ *         ERRP_AUTO_PROPAGATE();
+ *         ...
+ *         subcall(..., errp);
+ *         if (*errp) {
+ *             ...
+ *             return -EINVAL;
+ *         }
+ *         ...
+ *     }
+ *
+ * ERRP_AUTO_PROPAGATE takes care of wrapping the original errp as needed, so
+ * that the rest of the function can directly use errp (including
+ * dereferencing), where any errors will then be propagated on to the original
+ * errp when leaving the function.
+ *
+ * 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 = NULL;
- *     foo(arg, &err);
+ *     subcall(arg, &err);
  *     if (err) {
  *         handle the error...
+ *         error_free(err);
  *     }
  *
+ * Note that older code that did not use ERRP_AUTO_PROPAGATE would instead need
+ * a local Error * variable and the use of error_propagate() to properly handle
+ * all possible caller values of errp. Now this is DEPRECATED* (see below).
+ *
+ * Note that any function that wants to modify an error object, such as by
+ * calling error_append_hint or error_prepend, must use ERRP_AUTO_PROPAGATE, in
+ * order for a caller's use of &error_fatal to see the additional information.
+ *
+ * In rare cases, we need to pass existing Error object to the caller by hand:
+ *     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 +143,6 @@
  * Call a function treating errors as fatal:
  *     foo(arg, &error_fatal);
  *
- * Receive an error and pass it on to the caller:
- *     Error *err = 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 = NULL, *local_err = NULL;
  *     foo(arg, &err);
@@ -114,6 +159,61 @@
  *         handle the error...
  *     }
  * because this may pass a non-null err to bar().
+ *
+ * DEPRECATED*
+ *
+ * The following pattern of receiving, checking, and then forwarding an error
+ * to the caller by hand is now deprecated:
+ *
+ *     Error *err = NULL;
+ *     foo(arg, &err);
+ *     if (err) {
+ *         handle the error...
+ *         error_propagate(errp, err);
+ *     }
+ *
+ * Instead, use ERRP_AUTO_PROPAGATE macro.
+ *
+ * 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 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;
+ *         }
+ *         ...
+ *     }
  */
 
 #ifndef ERROR_H
@@ -322,6 +422,47 @@ 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 exists to assist with proper error handling in a function which
+ * uses an Error **errp parameter.  It must be used as the first line of a
+ * function which modifies an error (with error_prepend, error_append_hint, or
+ * similar) or which wants to dereference *errp.  It is still safe (but
+ * useless) to use in other functions.
+ *
+ * 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.
+ */
+#define ERRP_AUTO_PROPAGATE() \
+    g_auto(ErrorPropagator) _auto_errp_prop = {.errp = errp}; \
+    do { \
+        if (!errp || errp == &error_fatal) { \
+            errp = &_auto_errp_prop.local_err; \
+        } \
+    } while (0)
+
 /*
  * Special error destination to abort on error.
  * See error_setg() and error_propagate() for details.
-- 
2.21.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-12  8:59 ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-12  8:59   ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, vsementsov, Laszlo Ersek, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Greg Kurz, armbru, Stefano Stabellini,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Michael Roth, Stefan Berger

Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
does corresponding changes in code (look for details in
include/qapi/error.h)

Usage example:
spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
 --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
 --max-width 80 FILES...

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---

Cc: Eric Blake <eblake@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Max Reitz <mreitz@redhat.com>
Cc: Greg Kurz <groug@kaod.org>
Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Paul Durrant <paul@xen.org>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Stefan Berger <stefanb@linux.ibm.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
Cc: qemu-devel@nongnu.org
Cc: qemu-block@nongnu.org
Cc: xen-devel@lists.xenproject.org

 scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
 include/qapi/error.h                          |   3 +
 MAINTAINERS                                   |   1 +
 3 files changed, 331 insertions(+)
 create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci

diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
new file mode 100644
index 0000000000..7dac2dcfa4
--- /dev/null
+++ b/scripts/coccinelle/auto-propagated-errp.cocci
@@ -0,0 +1,327 @@
+// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
+//
+// Copyright (c) 2020 Virtuozzo International GmbH.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see
+// <http://www.gnu.org/licenses/>.
+//
+// Usage example:
+// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
+//  --macro-file scripts/cocci-macro-file.h --in-place \
+//  --no-show-diff --max-width 80 FILES...
+//
+// Note: --max-width 80 is needed because coccinelle default is less
+// than 80, and without this parameter coccinelle may reindent some
+// lines which fit into 80 characters but not to coccinelle default,
+// which in turn produces extra patch hunks for no reason.
+
+// Switch unusual Error ** parameter names to errp
+// (this is necessary to use ERRP_AUTO_PROPAGATE).
+//
+// Disable optional_qualifier to skip functions with
+// "Error *const *errp" parameter.
+//
+// Skip functions with "assert(_errp && *_errp)" statement, because
+// that signals unusual semantics, and the parameter name may well
+// serve a purpose. (like nbd_iter_channel_error()).
+//
+// Skip util/error.c to not touch, for example, error_propagate() and
+// error_propagate_prepend().
+@ depends on !(file in "util/error.c") disable optional_qualifier@
+identifier fn;
+identifier _errp != errp;
+@@
+
+ fn(...,
+-   Error **_errp
++   Error **errp
+    ,...)
+ {
+(
+     ... when != assert(_errp && *_errp)
+&
+     <...
+-    _errp
++    errp
+     ...>
+)
+ }
+
+// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
+// necessary
+//
+// Note, that without "when any" the final "..." does not mach
+// something matched by previous pattern, i.e. the rule will not match
+// double error_prepend in control flow like in
+// vfio_set_irq_signaling().
+//
+// Note, "exists" says that we want apply rule even if it matches not
+// on all possible control flows (otherwise, it will not match
+// standard pattern when error_propagate() call is in if branch).
+@ disable optional_qualifier exists@
+identifier fn, local_err;
+symbol errp;
+@@
+
+ fn(..., Error **errp, ...)
+ {
++   ERRP_AUTO_PROPAGATE();
+    ...  when != ERRP_AUTO_PROPAGATE();
+(
+(
+    error_append_hint(errp, ...);
+|
+    error_prepend(errp, ...);
+|
+    error_vprepend(errp, ...);
+)
+    ... when any
+|
+    Error *local_err = NULL;
+    ...
+(
+    error_propagate_prepend(errp, local_err, ...);
+|
+    error_propagate(errp, local_err);
+)
+    ...
+)
+ }
+
+
+// Match functions with propagation of local error to errp.
+// We want to refer these functions in several following rules, but I
+// don't know a proper way to inherit a function, not just its name
+// (to not match another functions with same name in following rules).
+// Not-proper way is as follows: rename errp parameter in functions
+// header and match it in following rules. Rename it back after all
+// transformations.
+//
+// The simplest case of propagation scheme is single definition of
+// local_err with at most one error_propagate_prepend or
+// error_propagate on each control-flow. Still, we want to match more
+// complex schemes too. We'll warn them with help of further rules.
+@rule1 disable optional_qualifier exists@
+identifier fn, local_err;
+symbol errp;
+@@
+
+ fn(..., Error **
+-    errp
++    ____
+    , ...)
+ {
+     ...
+     Error *local_err = NULL;
+     ...
+(
+     error_propagate_prepend(errp, local_err, ...);
+|
+     error_propagate(errp, local_err);
+)
+     ...
+ }
+
+
+// Warn several Error * definitions.
+@check1 disable optional_qualifier exists@
+identifier fn = rule1.fn, local_err, local_err2;
+@@
+
+ fn(..., Error ** ____, ...)
+ {
+     ...
+     Error *local_err = NULL;
+     ... when any
+     Error *local_err2 = NULL;
+     ... when any
+ }
+
+@ script:python @
+fn << check1.fn;
+@@
+
+print('Warning: function {} has several definitions of '
+      'Error * local variable'.format(fn))
+
+// Warn several propagations in control flow.
+@check2 disable optional_qualifier exists@
+identifier fn = rule1.fn;
+symbol errp;
+position p1, p2;
+@@
+
+ fn(..., Error ** ____, ...)
+ {
+     ...
+(
+     error_propagate_prepend(errp, ...);@p1
+|
+     error_propagate(errp, ...);@p1
+)
+     ...
+(
+     error_propagate_prepend(errp, ...);@p2
+|
+     error_propagate(errp, ...);@p2
+)
+     ... when any
+ }
+
+@ script:python @
+fn << check2.fn;
+p1 << check2.p1;
+p2 << check2.p2;
+@@
+
+print('Warning: function {} propagates to errp several times in '
+      'one control flow: at {}:{} and then at {}:{}'.format(
+          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
+
+// Convert special case with goto separately.
+// I tried merging this into the following rule the obvious way, but
+// it made Coccinelle hang on block.c
+//
+// Note interesting thing: if we don't do it here, and try to fixup
+// "out: }" things later after all transformations (the rule will be
+// the same, just without error_propagate() call), coccinelle fails to
+// match this "out: }".
+@ disable optional_qualifier@
+identifier rule1.fn, rule1.local_err, out;
+symbol errp;
+@@
+
+ fn(..., Error ** ____, ...)
+ {
+     <...
+-    goto out;
++    return;
+     ...>
+- out:
+-    error_propagate(errp, local_err);
+ }
+
+// Convert most of local_err related stuff.
+//
+// Note, that we update everything related to matched by rule1
+// function name and local_err name. We may match something not
+// related to the pattern matched by rule1. For example, local_err may
+// be defined with the same name in different blocks inside one
+// function, and in one block follow the propagation pattern and in
+// other block doesn't. Or we may have several functions with the same
+// name (for different configurations).
+//
+// Note also that errp-cleaning functions
+//   error_free_errp
+//   error_report_errp
+//   error_reportf_errp
+//   warn_report_errp
+//   warn_reportf_errp
+// are not yet implemented. They must call corresponding Error* -
+// freeing function and then set *errp to NULL, to avoid further
+// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
+// For example, error_free_errp may look like this:
+//
+//    void error_free_errp(Error **errp)
+//    {
+//        error_free(*errp);
+//        *errp = NULL;
+//    }
+@ disable optional_qualifier exists@
+identifier rule1.fn, rule1.local_err;
+expression list args;
+symbol errp;
+@@
+
+ fn(..., Error ** ____, ...)
+ {
+     <...
+(
+-    Error *local_err = NULL;
+|
+
+// Convert error clearing functions
+(
+-    error_free(local_err);
++    error_free_errp(errp);
+|
+-    error_report_err(local_err);
++    error_report_errp(errp);
+|
+-    error_reportf_err(local_err, args);
++    error_reportf_errp(errp, args);
+|
+-    warn_report_err(local_err);
++    warn_report_errp(errp);
+|
+-    warn_reportf_err(local_err, args);
++    warn_reportf_errp(errp, args);
+)
+?-    local_err = NULL;
+
+|
+-    error_propagate_prepend(errp, local_err, args);
++    error_prepend(errp, args);
+|
+-    error_propagate(errp, local_err);
+|
+-    &local_err
++    errp
+)
+     ...>
+ }
+
+// Convert remaining local_err usage. For example, different kinds of
+// error checking in if conditionals. We can't merge this into
+// previous hunk, as this conflicts with other substitutions in it (at
+// least with "- local_err = NULL").
+@ disable optional_qualifier@
+identifier rule1.fn, rule1.local_err;
+symbol errp;
+@@
+
+ fn(..., Error ** ____, ...)
+ {
+     <...
+-    local_err
++    *errp
+     ...>
+ }
+
+// Always use the same pattern for checking error
+@ disable optional_qualifier@
+identifier rule1.fn;
+symbol errp;
+@@
+
+ fn(..., Error ** ____, ...)
+ {
+     <...
+-    *errp != NULL
++    *errp
+     ...>
+ }
+
+// Revert temporary ___ identifier.
+@ disable optional_qualifier@
+identifier rule1.fn;
+@@
+
+ fn(..., Error **
+-   ____
++   errp
+    , ...)
+ {
+     ...
+ }
diff --git a/include/qapi/error.h b/include/qapi/error.h
index 30140d9bfe..56c133520d 100644
--- a/include/qapi/error.h
+++ b/include/qapi/error.h
@@ -214,6 +214,9 @@
  *         }
  *         ...
  *     }
+ *
+ * For mass-conversion use script
+ *   scripts/coccinelle/auto-propagated-errp.cocci
  */
 
 #ifndef ERROR_H
diff --git a/MAINTAINERS b/MAINTAINERS
index 857f969aa1..047f1b9714 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
 F: qapi/error.json
 F: util/error.c
 F: util/qemu-error.c
+F: scripts/coccinelle/*err*.cocci
 
 GDB stub
 M: Alex Bennée <alex.bennee@linaro.org>
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-12  8:59   ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, vsementsov, Laszlo Ersek, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Greg Kurz, armbru, Stefano Stabellini,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Eric Blake, Michael Roth, Stefan Berger

Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
does corresponding changes in code (look for details in
include/qapi/error.h)

Usage example:
spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
 --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
 --max-width 80 FILES...

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
---

Cc: Eric Blake <eblake@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>
Cc: Max Reitz <mreitz@redhat.com>
Cc: Greg Kurz <groug@kaod.org>
Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Anthony Perard <anthony.perard@citrix.com>
Cc: Paul Durrant <paul@xen.org>
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Stefan Berger <stefanb@linux.ibm.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
Cc: qemu-devel@nongnu.org
Cc: qemu-block@nongnu.org
Cc: xen-devel@lists.xenproject.org

 scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
 include/qapi/error.h                          |   3 +
 MAINTAINERS                                   |   1 +
 3 files changed, 331 insertions(+)
 create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci

diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
new file mode 100644
index 0000000000..7dac2dcfa4
--- /dev/null
+++ b/scripts/coccinelle/auto-propagated-errp.cocci
@@ -0,0 +1,327 @@
+// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
+//
+// Copyright (c) 2020 Virtuozzo International GmbH.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see
+// <http://www.gnu.org/licenses/>.
+//
+// Usage example:
+// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
+//  --macro-file scripts/cocci-macro-file.h --in-place \
+//  --no-show-diff --max-width 80 FILES...
+//
+// Note: --max-width 80 is needed because coccinelle default is less
+// than 80, and without this parameter coccinelle may reindent some
+// lines which fit into 80 characters but not to coccinelle default,
+// which in turn produces extra patch hunks for no reason.
+
+// Switch unusual Error ** parameter names to errp
+// (this is necessary to use ERRP_AUTO_PROPAGATE).
+//
+// Disable optional_qualifier to skip functions with
+// "Error *const *errp" parameter.
+//
+// Skip functions with "assert(_errp && *_errp)" statement, because
+// that signals unusual semantics, and the parameter name may well
+// serve a purpose. (like nbd_iter_channel_error()).
+//
+// Skip util/error.c to not touch, for example, error_propagate() and
+// error_propagate_prepend().
+@ depends on !(file in "util/error.c") disable optional_qualifier@
+identifier fn;
+identifier _errp != errp;
+@@
+
+ fn(...,
+-   Error **_errp
++   Error **errp
+    ,...)
+ {
+(
+     ... when != assert(_errp && *_errp)
+&
+     <...
+-    _errp
++    errp
+     ...>
+)
+ }
+
+// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
+// necessary
+//
+// Note, that without "when any" the final "..." does not mach
+// something matched by previous pattern, i.e. the rule will not match
+// double error_prepend in control flow like in
+// vfio_set_irq_signaling().
+//
+// Note, "exists" says that we want apply rule even if it matches not
+// on all possible control flows (otherwise, it will not match
+// standard pattern when error_propagate() call is in if branch).
+@ disable optional_qualifier exists@
+identifier fn, local_err;
+symbol errp;
+@@
+
+ fn(..., Error **errp, ...)
+ {
++   ERRP_AUTO_PROPAGATE();
+    ...  when != ERRP_AUTO_PROPAGATE();
+(
+(
+    error_append_hint(errp, ...);
+|
+    error_prepend(errp, ...);
+|
+    error_vprepend(errp, ...);
+)
+    ... when any
+|
+    Error *local_err = NULL;
+    ...
+(
+    error_propagate_prepend(errp, local_err, ...);
+|
+    error_propagate(errp, local_err);
+)
+    ...
+)
+ }
+
+
+// Match functions with propagation of local error to errp.
+// We want to refer these functions in several following rules, but I
+// don't know a proper way to inherit a function, not just its name
+// (to not match another functions with same name in following rules).
+// Not-proper way is as follows: rename errp parameter in functions
+// header and match it in following rules. Rename it back after all
+// transformations.
+//
+// The simplest case of propagation scheme is single definition of
+// local_err with at most one error_propagate_prepend or
+// error_propagate on each control-flow. Still, we want to match more
+// complex schemes too. We'll warn them with help of further rules.
+@rule1 disable optional_qualifier exists@
+identifier fn, local_err;
+symbol errp;
+@@
+
+ fn(..., Error **
+-    errp
++    ____
+    , ...)
+ {
+     ...
+     Error *local_err = NULL;
+     ...
+(
+     error_propagate_prepend(errp, local_err, ...);
+|
+     error_propagate(errp, local_err);
+)
+     ...
+ }
+
+
+// Warn several Error * definitions.
+@check1 disable optional_qualifier exists@
+identifier fn = rule1.fn, local_err, local_err2;
+@@
+
+ fn(..., Error ** ____, ...)
+ {
+     ...
+     Error *local_err = NULL;
+     ... when any
+     Error *local_err2 = NULL;
+     ... when any
+ }
+
+@ script:python @
+fn << check1.fn;
+@@
+
+print('Warning: function {} has several definitions of '
+      'Error * local variable'.format(fn))
+
+// Warn several propagations in control flow.
+@check2 disable optional_qualifier exists@
+identifier fn = rule1.fn;
+symbol errp;
+position p1, p2;
+@@
+
+ fn(..., Error ** ____, ...)
+ {
+     ...
+(
+     error_propagate_prepend(errp, ...);@p1
+|
+     error_propagate(errp, ...);@p1
+)
+     ...
+(
+     error_propagate_prepend(errp, ...);@p2
+|
+     error_propagate(errp, ...);@p2
+)
+     ... when any
+ }
+
+@ script:python @
+fn << check2.fn;
+p1 << check2.p1;
+p2 << check2.p2;
+@@
+
+print('Warning: function {} propagates to errp several times in '
+      'one control flow: at {}:{} and then at {}:{}'.format(
+          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
+
+// Convert special case with goto separately.
+// I tried merging this into the following rule the obvious way, but
+// it made Coccinelle hang on block.c
+//
+// Note interesting thing: if we don't do it here, and try to fixup
+// "out: }" things later after all transformations (the rule will be
+// the same, just without error_propagate() call), coccinelle fails to
+// match this "out: }".
+@ disable optional_qualifier@
+identifier rule1.fn, rule1.local_err, out;
+symbol errp;
+@@
+
+ fn(..., Error ** ____, ...)
+ {
+     <...
+-    goto out;
++    return;
+     ...>
+- out:
+-    error_propagate(errp, local_err);
+ }
+
+// Convert most of local_err related stuff.
+//
+// Note, that we update everything related to matched by rule1
+// function name and local_err name. We may match something not
+// related to the pattern matched by rule1. For example, local_err may
+// be defined with the same name in different blocks inside one
+// function, and in one block follow the propagation pattern and in
+// other block doesn't. Or we may have several functions with the same
+// name (for different configurations).
+//
+// Note also that errp-cleaning functions
+//   error_free_errp
+//   error_report_errp
+//   error_reportf_errp
+//   warn_report_errp
+//   warn_reportf_errp
+// are not yet implemented. They must call corresponding Error* -
+// freeing function and then set *errp to NULL, to avoid further
+// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
+// For example, error_free_errp may look like this:
+//
+//    void error_free_errp(Error **errp)
+//    {
+//        error_free(*errp);
+//        *errp = NULL;
+//    }
+@ disable optional_qualifier exists@
+identifier rule1.fn, rule1.local_err;
+expression list args;
+symbol errp;
+@@
+
+ fn(..., Error ** ____, ...)
+ {
+     <...
+(
+-    Error *local_err = NULL;
+|
+
+// Convert error clearing functions
+(
+-    error_free(local_err);
++    error_free_errp(errp);
+|
+-    error_report_err(local_err);
++    error_report_errp(errp);
+|
+-    error_reportf_err(local_err, args);
++    error_reportf_errp(errp, args);
+|
+-    warn_report_err(local_err);
++    warn_report_errp(errp);
+|
+-    warn_reportf_err(local_err, args);
++    warn_reportf_errp(errp, args);
+)
+?-    local_err = NULL;
+
+|
+-    error_propagate_prepend(errp, local_err, args);
++    error_prepend(errp, args);
+|
+-    error_propagate(errp, local_err);
+|
+-    &local_err
++    errp
+)
+     ...>
+ }
+
+// Convert remaining local_err usage. For example, different kinds of
+// error checking in if conditionals. We can't merge this into
+// previous hunk, as this conflicts with other substitutions in it (at
+// least with "- local_err = NULL").
+@ disable optional_qualifier@
+identifier rule1.fn, rule1.local_err;
+symbol errp;
+@@
+
+ fn(..., Error ** ____, ...)
+ {
+     <...
+-    local_err
++    *errp
+     ...>
+ }
+
+// Always use the same pattern for checking error
+@ disable optional_qualifier@
+identifier rule1.fn;
+symbol errp;
+@@
+
+ fn(..., Error ** ____, ...)
+ {
+     <...
+-    *errp != NULL
++    *errp
+     ...>
+ }
+
+// Revert temporary ___ identifier.
+@ disable optional_qualifier@
+identifier rule1.fn;
+@@
+
+ fn(..., Error **
+-   ____
++   errp
+    , ...)
+ {
+     ...
+ }
diff --git a/include/qapi/error.h b/include/qapi/error.h
index 30140d9bfe..56c133520d 100644
--- a/include/qapi/error.h
+++ b/include/qapi/error.h
@@ -214,6 +214,9 @@
  *         }
  *         ...
  *     }
+ *
+ * For mass-conversion use script
+ *   scripts/coccinelle/auto-propagated-errp.cocci
  */
 
 #ifndef ERROR_H
diff --git a/MAINTAINERS b/MAINTAINERS
index 857f969aa1..047f1b9714 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
 F: qapi/error.json
 F: util/error.c
 F: util/qemu-error.c
+F: scripts/coccinelle/*err*.cocci
 
 GDB stub
 M: Alex Bennée <alex.bennee@linaro.org>
-- 
2.21.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v9 03/10] hw/sd/ssi-sd: fix error handling in ssi_sd_realize
  2020-03-12  8:59 ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
                   ` (2 preceding siblings ...)
  (?)
@ 2020-03-12  8:59 ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: Philippe Mathieu-Daudé, vsementsov, armbru

It's wrong to use same err object as errp parameter for several
function calls without intermediate checking for error: we'll crash if
try to set err object twice.

Fix that, using new ERRP_AUTO_PROPAGATE macro.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 hw/sd/ssi-sd.c | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index 91db069212..bc44e1a0f5 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -241,10 +241,10 @@ static const VMStateDescription vmstate_ssi_sd = {
 
 static void ssi_sd_realize(SSISlave *d, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d);
     DeviceState *carddev;
     DriveInfo *dinfo;
-    Error *err = NULL;
 
     qbus_create_inplace(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS,
                         DEVICE(d), "sd-bus");
@@ -254,14 +254,26 @@ static void ssi_sd_realize(SSISlave *d, Error **errp)
     dinfo = drive_get_next(IF_SD);
     carddev = qdev_create(BUS(&s->sdbus), TYPE_SD_CARD);
     if (dinfo) {
-        qdev_prop_set_drive(carddev, "drive", blk_by_legacy_dinfo(dinfo), &err);
+        qdev_prop_set_drive(carddev, "drive", blk_by_legacy_dinfo(dinfo), errp);
+        if (*errp) {
+            goto fail;
+        }
+    }
+
+    object_property_set_bool(OBJECT(carddev), true, "spi", errp);
+    if (*errp) {
+        goto fail;
     }
-    object_property_set_bool(OBJECT(carddev), true, "spi", &err);
-    object_property_set_bool(OBJECT(carddev), true, "realized", &err);
-    if (err) {
-        error_setg(errp, "failed to init SD card: %s", error_get_pretty(err));
-        return;
+
+    object_property_set_bool(OBJECT(carddev), true, "realized", errp);
+    if (*errp) {
+        goto fail;
     }
+
+    return;
+
+fail:
+    error_prepend(errp, "failed to init SD card: ");
 }
 
 static void ssi_sd_reset(DeviceState *dev)
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v9 04/10] SD (Secure Card): introduce ERRP_AUTO_PROPAGATE
  2020-03-12  8:59 ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
                   ` (3 preceding siblings ...)
  (?)
@ 2020-03-12  8:59 ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, vsementsov, Philippe Mathieu-Daudé, armbru, Greg Kurz

If we want to add some info to errp (by error_prepend() or
error_append_hint()), we must use the ERRP_AUTO_PROPAGATE macro.
Otherwise, this info will not be added when errp == &error_fatal
(the program will exit prior to the error_append_hint() or
error_prepend() call).  Fix such cases.

If we want to check error after errp-function call, we need to
introduce local_err and then propagate it to errp. Instead, use
ERRP_AUTO_PROPAGATE macro, benefits are:
1. No need of explicit error_propagate call
2. No need of explicit local_err variable: use errp directly
3. ERRP_AUTO_PROPAGATE leaves errp as is if it's not NULL or
   &error_fatal, this means that we don't break error_abort
   (we'll abort on error_set, not on error_propagate)

This commit is generated by command

    sed -n '/^SD (Secure Card)$/,/^$/{s/^F: //p}' \
        MAINTAINERS | \
    xargs git ls-files | grep '\.[hc]$' | \
    xargs spatch \
        --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
        --macro-file scripts/cocci-macro-file.h \
        --in-place --no-show-diff --max-width 80

Reported-by: Kevin Wolf <kwolf@redhat.com>
Reported-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/sd/sdhci-pci.c |  7 +++----
 hw/sd/sdhci.c     | 21 +++++++++------------
 2 files changed, 12 insertions(+), 16 deletions(-)

diff --git a/hw/sd/sdhci-pci.c b/hw/sd/sdhci-pci.c
index 19fa8bd8ed..ceaf3ea35b 100644
--- a/hw/sd/sdhci-pci.c
+++ b/hw/sd/sdhci-pci.c
@@ -29,13 +29,12 @@ static Property sdhci_pci_properties[] = {
 
 static void sdhci_pci_realize(PCIDevice *dev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     SDHCIState *s = PCI_SDHCI(dev);
-    Error *local_err = NULL;
 
     sdhci_initfn(s);
-    sdhci_common_realize(s, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    sdhci_common_realize(s, errp);
+    if (*errp) {
         return;
     }
 
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index de63ffb037..c25ac3c099 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -1288,7 +1288,7 @@ static const MemoryRegionOps sdhci_mmio_ops = {
 
 static void sdhci_init_readonly_registers(SDHCIState *s, Error **errp)
 {
-    Error *local_err = NULL;
+    ERRP_AUTO_PROPAGATE();
 
     switch (s->sd_spec_version) {
     case 2 ... 3:
@@ -1299,9 +1299,8 @@ static void sdhci_init_readonly_registers(SDHCIState *s, Error **errp)
     }
     s->version = (SDHC_HCVER_VENDOR << 8) | (s->sd_spec_version - 1);
 
-    sdhci_check_capareg(s, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    sdhci_check_capareg(s, errp);
+    if (*errp) {
         return;
     }
 }
@@ -1332,11 +1331,10 @@ void sdhci_uninitfn(SDHCIState *s)
 
 void sdhci_common_realize(SDHCIState *s, Error **errp)
 {
-    Error *local_err = NULL;
+    ERRP_AUTO_PROPAGATE();
 
-    sdhci_init_readonly_registers(s, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    sdhci_init_readonly_registers(s, errp);
+    if (*errp) {
         return;
     }
     s->buf_maxsz = sdhci_get_fifolen(s);
@@ -1456,13 +1454,12 @@ static void sdhci_sysbus_finalize(Object *obj)
 
 static void sdhci_sysbus_realize(DeviceState *dev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     SDHCIState *s = SYSBUS_SDHCI(dev);
     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
-    Error *local_err = NULL;
 
-    sdhci_common_realize(s, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    sdhci_common_realize(s, errp);
+    if (*errp) {
         return;
     }
 
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v9 05/10] pflash: introduce ERRP_AUTO_PROPAGATE
  2020-03-12  8:59 ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
                   ` (4 preceding siblings ...)
  (?)
@ 2020-03-12  8:59 ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, vsementsov, qemu-block, armbru, Max Reitz, Greg Kurz,
	Philippe Mathieu-Daudé

If we want to add some info to errp (by error_prepend() or
error_append_hint()), we must use the ERRP_AUTO_PROPAGATE macro.
Otherwise, this info will not be added when errp == &error_fatal
(the program will exit prior to the error_append_hint() or
error_prepend() call).  Fix such cases.

If we want to check error after errp-function call, we need to
introduce local_err and then propagate it to errp. Instead, use
ERRP_AUTO_PROPAGATE macro, benefits are:
1. No need of explicit error_propagate call
2. No need of explicit local_err variable: use errp directly
3. ERRP_AUTO_PROPAGATE leaves errp as is if it's not NULL or
   &error_fatal, this means that we don't break error_abort
   (we'll abort on error_set, not on error_propagate)

This commit is generated by command

    sed -n '/^Parallel NOR Flash devices$/,/^$/{s/^F: //p}' \
        MAINTAINERS | \
    xargs git ls-files | grep '\.[hc]$' | \
    xargs spatch \
        --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
        --macro-file scripts/cocci-macro-file.h \
        --in-place --no-show-diff --max-width 80

Reported-by: Kevin Wolf <kwolf@redhat.com>
Reported-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi01.c | 7 +++----
 hw/block/pflash_cfi02.c | 7 +++----
 2 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 24f3bce7ef..a5755e6119 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -700,12 +700,12 @@ static const MemoryRegionOps pflash_cfi01_ops = {
 
 static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     PFlashCFI01 *pfl = PFLASH_CFI01(dev);
     uint64_t total_len;
     int ret;
     uint64_t blocks_per_device, sector_len_per_device, device_len;
     int num_devices;
-    Error *local_err = NULL;
 
     if (pfl->sector_len == 0) {
         error_setg(errp, "attribute \"sector-length\" not specified or zero.");
@@ -739,9 +739,8 @@ static void pflash_cfi01_realize(DeviceState *dev, Error **errp)
         &pfl->mem, OBJECT(dev),
         &pflash_cfi01_ops,
         pfl,
-        pfl->name, total_len, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+        pfl->name, total_len, errp);
+    if (*errp) {
         return;
     }
 
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 12f18d401a..3da9f56391 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -718,9 +718,9 @@ static const MemoryRegionOps pflash_cfi02_ops = {
 
 static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     PFlashCFI02 *pfl = PFLASH_CFI02(dev);
     int ret;
-    Error *local_err = NULL;
 
     if (pfl->uniform_sector_len == 0 && pfl->sector_len[0] == 0) {
         error_setg(errp, "attribute \"sector-length\" not specified or zero.");
@@ -786,9 +786,8 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
 
     memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl),
                                   &pflash_cfi02_ops, pfl, pfl->name,
-                                  pfl->chip_len, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+                                  pfl->chip_len, errp);
+    if (*errp) {
         return;
     }
 
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v9 06/10] fw_cfg: introduce ERRP_AUTO_PROPAGATE
  2020-03-12  8:59 ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
                   ` (5 preceding siblings ...)
  (?)
@ 2020-03-12  8:59 ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, vsementsov, Philippe Mathieu-Daudé,
	armbru, Greg Kurz, Gerd Hoffmann, Laszlo Ersek

If we want to add some info to errp (by error_prepend() or
error_append_hint()), we must use the ERRP_AUTO_PROPAGATE macro.
Otherwise, this info will not be added when errp == &error_fatal
(the program will exit prior to the error_append_hint() or
error_prepend() call).  Fix such cases.

If we want to check error after errp-function call, we need to
introduce local_err and then propagate it to errp. Instead, use
ERRP_AUTO_PROPAGATE macro, benefits are:
1. No need of explicit error_propagate call
2. No need of explicit local_err variable: use errp directly
3. ERRP_AUTO_PROPAGATE leaves errp as is if it's not NULL or
   &error_fatal, this means that we don't break error_abort
   (we'll abort on error_set, not on error_propagate)

This commit is generated by command

    sed -n '/^Firmware configuration (fw_cfg)$/,/^$/{s/^F: //p}' \
        MAINTAINERS | \
    xargs git ls-files | grep '\.[hc]$' | \
    xargs spatch \
        --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
        --macro-file scripts/cocci-macro-file.h \
        --in-place --no-show-diff --max-width 80

Reported-by: Kevin Wolf <kwolf@redhat.com>
Reported-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/nvram/fw_cfg.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 179b302f01..22ff2be0c0 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -1142,12 +1142,11 @@ static Property fw_cfg_io_properties[] = {
 
 static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     FWCfgIoState *s = FW_CFG_IO(dev);
-    Error *local_err = NULL;
 
-    fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    fw_cfg_file_slots_allocate(FW_CFG(s), errp);
+    if (*errp) {
         return;
     }
 
@@ -1193,14 +1192,13 @@ static Property fw_cfg_mem_properties[] = {
 
 static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     FWCfgMemState *s = FW_CFG_MEM(dev);
     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
     const MemoryRegionOps *data_ops = &fw_cfg_data_mem_ops;
-    Error *local_err = NULL;
 
-    fw_cfg_file_slots_allocate(FW_CFG(s), &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    fw_cfg_file_slots_allocate(FW_CFG(s), errp);
+    if (*errp) {
         return;
     }
 
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v9 07/10] virtio-9p: introduce ERRP_AUTO_PROPAGATE
  2020-03-12  8:59 ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
                   ` (6 preceding siblings ...)
  (?)
@ 2020-03-12  8:59 ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, vsementsov, Christian Schoenebeck, armbru, Greg Kurz

If we want to add some info to errp (by error_prepend() or
error_append_hint()), we must use the ERRP_AUTO_PROPAGATE macro.
Otherwise, this info will not be added when errp == &error_fatal
(the program will exit prior to the error_append_hint() or
error_prepend() call).  Fix such cases.

If we want to check error after errp-function call, we need to
introduce local_err and then propagate it to errp. Instead, use
ERRP_AUTO_PROPAGATE macro, benefits are:
1. No need of explicit error_propagate call
2. No need of explicit local_err variable: use errp directly
3. ERRP_AUTO_PROPAGATE leaves errp as is if it's not NULL or
   &error_fatal, this means that we don't break error_abort
   (we'll abort on error_set, not on error_propagate)

This commit is generated by command

    sed -n '/^virtio-9p$/,/^$/{s/^F: //p}' MAINTAINERS | \
    xargs git ls-files | grep '\.[hc]$' | \
    xargs spatch \
        --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
        --macro-file scripts/cocci-macro-file.h \
        --in-place --no-show-diff --max-width 80

Reported-by: Kevin Wolf <kwolf@redhat.com>
Reported-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Acked-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
---
 hw/9pfs/9p-local.c | 12 +++++-------
 hw/9pfs/9p.c       |  1 +
 2 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c
index 54e012e5b4..0361e0c0b4 100644
--- a/hw/9pfs/9p-local.c
+++ b/hw/9pfs/9p-local.c
@@ -1479,10 +1479,10 @@ static void error_append_security_model_hint(Error *const *errp)
 
 static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     const char *sec_model = qemu_opt_get(opts, "security_model");
     const char *path = qemu_opt_get(opts, "path");
     const char *multidevs = qemu_opt_get(opts, "multidevs");
-    Error *local_err = NULL;
 
     if (!sec_model) {
         error_setg(errp, "security_model property not set");
@@ -1516,11 +1516,10 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
             fse->export_flags &= ~V9FS_FORBID_MULTIDEVS;
             fse->export_flags &= ~V9FS_REMAP_INODES;
         } else {
-            error_setg(&local_err, "invalid multidevs property '%s'",
+            error_setg(errp, "invalid multidevs property '%s'",
                        multidevs);
-            error_append_hint(&local_err, "Valid options are: multidevs="
+            error_append_hint(errp, "Valid options are: multidevs="
                               "[remap|forbid|warn]\n");
-            error_propagate(errp, local_err);
             return -1;
         }
     }
@@ -1530,9 +1529,8 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp)
         return -1;
     }
 
-    if (fsdev_throttle_parse_opts(opts, &fse->fst, &local_err)) {
-        error_propagate_prepend(errp, local_err,
-                                "invalid throttle configuration: ");
+    if (fsdev_throttle_parse_opts(opts, &fse->fst, errp)) {
+        error_prepend(errp, "invalid throttle configuration: ");
         return -1;
     }
 
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 9e046f7acb..3aa6a57f3a 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -4023,6 +4023,7 @@ void pdu_submit(V9fsPDU *pdu, P9MsgHeader *hdr)
 int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t,
                                Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     int i, len;
     struct stat stat;
     FsDriverEntry *fse;
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v9 08/10] TPM: introduce ERRP_AUTO_PROPAGATE
  2020-03-12  8:59 ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
                   ` (7 preceding siblings ...)
  (?)
@ 2020-03-12  8:59 ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Stefan Berger, vsementsov, armbru, Greg Kurz

If we want to add some info to errp (by error_prepend() or
error_append_hint()), we must use the ERRP_AUTO_PROPAGATE macro.
Otherwise, this info will not be added when errp == &error_fatal
(the program will exit prior to the error_append_hint() or
error_prepend() call).  Fix such cases.

If we want to check error after errp-function call, we need to
introduce local_err and then propagate it to errp. Instead, use
ERRP_AUTO_PROPAGATE macro, benefits are:
1. No need of explicit error_propagate call
2. No need of explicit local_err variable: use errp directly
3. ERRP_AUTO_PROPAGATE leaves errp as is if it's not NULL or
   &error_fatal, this means that we don't break error_abort
   (we'll abort on error_set, not on error_propagate)

This commit is generated by command

    sed -n '/^TPM$/,/^$/{s/^F: //p}' MAINTAINERS | \
    xargs git ls-files | grep '\.[hc]$' | \
    xargs spatch \
        --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
        --macro-file scripts/cocci-macro-file.h \
        --in-place --no-show-diff --max-width 80

Reported-by: Kevin Wolf <kwolf@redhat.com>
Reported-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
 hw/tpm/tpm_util.c | 7 +++----
 tpm.c             | 7 +++----
 2 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c
index c0a0f3d71f..66e0e0c7f3 100644
--- a/hw/tpm/tpm_util.c
+++ b/hw/tpm/tpm_util.c
@@ -47,8 +47,8 @@ static void get_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
 static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
                     Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     DeviceState *dev = DEVICE(obj);
-    Error *local_err = NULL;
     Property *prop = opaque;
     TPMBackend *s, **be = qdev_get_prop_ptr(dev, prop);
     char *str;
@@ -58,9 +58,8 @@ static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
         return;
     }
 
-    visit_type_str(v, name, &str, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    visit_type_str(v, name, &str, errp);
+    if (*errp) {
         return;
     }
 
diff --git a/tpm.c b/tpm.c
index 9c9e20bbb7..359ebb7f68 100644
--- a/tpm.c
+++ b/tpm.c
@@ -81,11 +81,11 @@ TPMBackend *qemu_find_tpm_be(const char *id)
 
 static int tpm_init_tpmdev(void *dummy, QemuOpts *opts, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     const char *value;
     const char *id;
     const TPMBackendClass *be;
     TPMBackend *drv;
-    Error *local_err = NULL;
     int i;
 
     if (!QLIST_EMPTY(&tpm_backends)) {
@@ -116,9 +116,8 @@ static int tpm_init_tpmdev(void *dummy, QemuOpts *opts, Error **errp)
     }
 
     /* validate backend specific opts */
-    qemu_opts_validate(opts, be->opts, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    qemu_opts_validate(opts, be->opts, errp);
+    if (*errp) {
         return 1;
     }
 
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v9 09/10] nbd: introduce ERRP_AUTO_PROPAGATE
  2020-03-12  8:59 ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
                   ` (8 preceding siblings ...)
  (?)
@ 2020-03-12  8:59 ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, vsementsov, qemu-block, armbru, Max Reitz, Greg Kurz

If we want to add some info to errp (by error_prepend() or
error_append_hint()), we must use the ERRP_AUTO_PROPAGATE macro.
Otherwise, this info will not be added when errp == &error_fatal
(the program will exit prior to the error_append_hint() or
error_prepend() call).  Fix such cases.

If we want to check error after errp-function call, we need to
introduce local_err and then propagate it to errp. Instead, use
ERRP_AUTO_PROPAGATE macro, benefits are:
1. No need of explicit error_propagate call
2. No need of explicit local_err variable: use errp directly
3. ERRP_AUTO_PROPAGATE leaves errp as is if it's not NULL or
   &error_fatal, this means that we don't break error_abort
   (we'll abort on error_set, not on error_propagate)

This commit is generated by command

    sed -n '/^Network Block Device (NBD)$/,/^$/{s/^F: //p}' \
        MAINTAINERS | \
    xargs git ls-files | grep '\.[hc]$' | \
    xargs spatch \
        --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
        --macro-file scripts/cocci-macro-file.h \
        --in-place --no-show-diff --max-width 80

Reported-by: Kevin Wolf <kwolf@redhat.com>
Reported-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
---
 include/block/nbd.h |  1 +
 block/nbd.c         | 21 +++++++++------------
 nbd/client.c        |  5 +++++
 nbd/server.c        |  5 +++++
 4 files changed, 20 insertions(+), 12 deletions(-)

diff --git a/include/block/nbd.h b/include/block/nbd.h
index 20363280ae..f7d87636d3 100644
--- a/include/block/nbd.h
+++ b/include/block/nbd.h
@@ -361,6 +361,7 @@ void nbd_server_start_options(NbdServerOptions *arg, Error **errp);
 static inline int nbd_read(QIOChannel *ioc, void *buffer, size_t size,
                            const char *desc, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     int ret = qio_channel_read_all(ioc, buffer, size, errp) < 0 ? -EIO : 0;
 
     if (ret < 0) {
diff --git a/block/nbd.c b/block/nbd.c
index 976be76647..70274c31de 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -1410,16 +1410,15 @@ static void nbd_client_close(BlockDriverState *bs)
 static QIOChannelSocket *nbd_establish_connection(SocketAddress *saddr,
                                                   Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     QIOChannelSocket *sioc;
-    Error *local_err = NULL;
 
     sioc = qio_channel_socket_new();
     qio_channel_set_name(QIO_CHANNEL(sioc), "nbd-client");
 
-    qio_channel_socket_connect_sync(sioc, saddr, &local_err);
-    if (local_err) {
+    qio_channel_socket_connect_sync(sioc, saddr, errp);
+    if (*errp) {
         object_unref(OBJECT(sioc));
-        error_propagate(errp, local_err);
         return NULL;
     }
 
@@ -1725,10 +1724,10 @@ static bool nbd_process_legacy_socket_options(QDict *output_options,
 static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
                                  Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     SocketAddress *saddr = NULL;
     QDict *addr = NULL;
     Visitor *iv = NULL;
-    Error *local_err = NULL;
 
     qdict_extract_subqdict(options, &addr, "server.");
     if (!qdict_size(addr)) {
@@ -1741,9 +1740,8 @@ static SocketAddress *nbd_config(BDRVNBDState *s, QDict *options,
         goto done;
     }
 
-    visit_type_SocketAddress(iv, NULL, &saddr, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    visit_type_SocketAddress(iv, NULL, &saddr, errp);
+    if (*errp) {
         goto done;
     }
 
@@ -1836,15 +1834,14 @@ static QemuOptsList nbd_runtime_opts = {
 static int nbd_process_options(BlockDriverState *bs, QDict *options,
                                Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     BDRVNBDState *s = bs->opaque;
     QemuOpts *opts;
-    Error *local_err = NULL;
     int ret = -EINVAL;
 
     opts = qemu_opts_create(&nbd_runtime_opts, NULL, 0, &error_abort);
-    qemu_opts_absorb_qdict(opts, options, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    qemu_opts_absorb_qdict(opts, options, errp);
+    if (*errp) {
         goto error;
     }
 
diff --git a/nbd/client.c b/nbd/client.c
index ba173108ba..e258ef3f7e 100644
--- a/nbd/client.c
+++ b/nbd/client.c
@@ -68,6 +68,7 @@ static int nbd_send_option_request(QIOChannel *ioc, uint32_t opt,
                                    uint32_t len, const char *data,
                                    Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     NBDOption req;
     QEMU_BUILD_BUG_ON(sizeof(req) != 16);
 
@@ -153,6 +154,7 @@ static int nbd_receive_option_reply(QIOChannel *ioc, uint32_t opt,
 static int nbd_handle_reply_err(QIOChannel *ioc, NBDOptionReply *reply,
                                 bool strict, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     g_autofree char *msg = NULL;
 
     if (!(reply->type & (1 << 31))) {
@@ -337,6 +339,7 @@ static int nbd_receive_list(QIOChannel *ioc, char **name, char **description,
 static int nbd_opt_info_or_go(QIOChannel *ioc, uint32_t opt,
                               NBDExportInfo *info, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     NBDOptionReply reply;
     uint32_t len = strlen(info->name);
     uint16_t type;
@@ -882,6 +885,7 @@ static int nbd_start_negotiate(AioContext *aio_context, QIOChannel *ioc,
                                bool structured_reply, bool *zeroes,
                                Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     uint64_t magic;
 
     trace_nbd_start_negotiate(tlscreds, hostname ? hostname : "<null>");
@@ -1017,6 +1021,7 @@ int nbd_receive_negotiate(AioContext *aio_context, QIOChannel *ioc,
                           const char *hostname, QIOChannel **outioc,
                           NBDExportInfo *info, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     int result;
     bool zeroes;
     bool base_allocation = info->base_allocation;
diff --git a/nbd/server.c b/nbd/server.c
index 11a31094ff..ffc0cc69a7 100644
--- a/nbd/server.c
+++ b/nbd/server.c
@@ -211,6 +211,7 @@ static int GCC_FMT_ATTR(4, 0)
 nbd_negotiate_send_rep_verr(NBDClient *client, uint32_t type,
                             Error **errp, const char *fmt, va_list va)
 {
+    ERRP_AUTO_PROPAGATE();
     g_autofree char *msg = NULL;
     int ret;
     size_t len;
@@ -369,6 +370,7 @@ static int nbd_opt_read_name(NBDClient *client, char **name, uint32_t *length,
 static int nbd_negotiate_send_rep_list(NBDClient *client, NBDExport *exp,
                                        Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     size_t name_len, desc_len;
     uint32_t len;
     const char *name = exp->name ? exp->name : "";
@@ -432,6 +434,7 @@ static void nbd_check_meta_export(NBDClient *client)
 static int nbd_negotiate_handle_export_name(NBDClient *client, bool no_zeroes,
                                             Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     g_autofree char *name = NULL;
     char buf[NBD_REPLY_EXPORT_NAME_SIZE] = "";
     size_t len;
@@ -1272,6 +1275,7 @@ static int nbd_negotiate_options(NBDClient *client, Error **errp)
  */
 static coroutine_fn int nbd_negotiate(NBDClient *client, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     char buf[NBD_OLDSTYLE_NEGOTIATE_SIZE] = "";
     int ret;
 
@@ -1646,6 +1650,7 @@ void nbd_export_close(NBDExport *exp)
 
 void nbd_export_remove(NBDExport *exp, NbdServerRemoveMode mode, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     if (mode == NBD_SERVER_REMOVE_MODE_HARD || QTAILQ_EMPTY(&exp->clients)) {
         nbd_export_close(exp);
         return;
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [PATCH v9 10/10] xen: introduce ERRP_AUTO_PROPAGATE
  2020-03-12  8:59 ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-12  8:59   ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant, armbru,
	Greg Kurz, vsementsov, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz

If we want to add some info to errp (by error_prepend() or
error_append_hint()), we must use the ERRP_AUTO_PROPAGATE macro.
Otherwise, this info will not be added when errp == &error_fatal
(the program will exit prior to the error_append_hint() or
error_prepend() call).  Fix such cases.

If we want to check error after errp-function call, we need to
introduce local_err and then propagate it to errp. Instead, use
ERRP_AUTO_PROPAGATE macro, benefits are:
1. No need of explicit error_propagate call
2. No need of explicit local_err variable: use errp directly
3. ERRP_AUTO_PROPAGATE leaves errp as is if it's not NULL or
   &error_fatal, this means that we don't break error_abort
   (we'll abort on error_set, not on error_propagate)

This commit is generated by command

    sed -n '/^X86 Xen CPUs$/,/^$/{s/^F: //p}' MAINTAINERS | \
    xargs git ls-files | grep '\.[hc]$' | \
    xargs spatch \
        --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
        --macro-file scripts/cocci-macro-file.h \
        --in-place --no-show-diff --max-width 80

Reported-by: Kevin Wolf <kwolf@redhat.com>
Reported-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Paul Durrant <paul@xen.org>
---
 hw/block/dataplane/xen-block.c |  17 ++---
 hw/block/xen-block.c           | 125 ++++++++++++++-------------------
 hw/pci-host/xen_igd_pt.c       |   7 +-
 hw/xen/xen-backend.c           |   7 +-
 hw/xen/xen-bus.c               |  92 ++++++++++--------------
 hw/xen/xen-host-pci-device.c   |  27 ++++---
 hw/xen/xen_pt.c                |  25 +++----
 hw/xen/xen_pt_config_init.c    |  20 +++---
 8 files changed, 138 insertions(+), 182 deletions(-)

diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c
index 288a87a814..3a8469fe87 100644
--- a/hw/block/dataplane/xen-block.c
+++ b/hw/block/dataplane/xen-block.c
@@ -739,8 +739,8 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
                                unsigned int protocol,
                                Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenDevice *xendev = dataplane->xendev;
-    Error *local_err = NULL;
     unsigned int ring_size;
     unsigned int i;
 
@@ -776,9 +776,8 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
     }
 
     xen_device_set_max_grant_refs(xendev, dataplane->nr_ring_ref,
-                                  &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+                                  errp);
+    if (*errp) {
         goto stop;
     }
 
@@ -786,9 +785,8 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
                                               dataplane->ring_ref,
                                               dataplane->nr_ring_ref,
                                               PROT_READ | PROT_WRITE,
-                                              &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+                                              errp);
+    if (*errp) {
         goto stop;
     }
 
@@ -821,9 +819,8 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
     dataplane->event_channel =
         xen_device_bind_event_channel(xendev, event_channel,
                                       xen_block_dataplane_event, dataplane,
-                                      &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+                                      errp);
+    if (*errp) {
         goto stop;
     }
 
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
index 3885464513..5d4c94181c 100644
--- a/hw/block/xen-block.c
+++ b/hw/block/xen-block.c
@@ -195,6 +195,7 @@ static const BlockDevOps xen_block_dev_ops = {
 
 static void xen_block_realize(XenDevice *xendev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
     XenBlockDeviceClass *blockdev_class =
         XEN_BLOCK_DEVICE_GET_CLASS(xendev);
@@ -202,7 +203,6 @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
     XenBlockVdev *vdev = &blockdev->props.vdev;
     BlockConf *conf = &blockdev->props.conf;
     BlockBackend *blk = conf->blk;
-    Error *local_err = NULL;
 
     if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) {
         error_setg(errp, "vdev property not set");
@@ -212,9 +212,8 @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
     trace_xen_block_realize(type, vdev->disk, vdev->partition);
 
     if (blockdev_class->realize) {
-        blockdev_class->realize(blockdev, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
+        blockdev_class->realize(blockdev, errp);
+        if (*errp) {
             return;
         }
     }
@@ -284,8 +283,8 @@ static void xen_block_frontend_changed(XenDevice *xendev,
                                        enum xenbus_state frontend_state,
                                        Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     enum xenbus_state backend_state = xen_device_backend_get_state(xendev);
-    Error *local_err = NULL;
 
     switch (frontend_state) {
     case XenbusStateInitialised:
@@ -294,15 +293,13 @@ static void xen_block_frontend_changed(XenDevice *xendev,
             break;
         }
 
-        xen_block_disconnect(xendev, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
+        xen_block_disconnect(xendev, errp);
+        if (*errp) {
             break;
         }
 
-        xen_block_connect(xendev, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
+        xen_block_connect(xendev, errp);
+        if (*errp) {
             break;
         }
 
@@ -315,9 +312,8 @@ static void xen_block_frontend_changed(XenDevice *xendev,
 
     case XenbusStateClosed:
     case XenbusStateUnknown:
-        xen_block_disconnect(xendev, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
+        xen_block_disconnect(xendev, errp);
+        if (*errp) {
             break;
         }
 
@@ -404,10 +400,10 @@ static int vbd_name_to_disk(const char *name, const char **endp,
 static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name,
                                void *opaque, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop);
-    Error *local_err = NULL;
     char *str, *p;
     const char *end;
 
@@ -416,9 +412,8 @@ static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name,
         return;
     }
 
-    visit_type_str(v, name, &str, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    visit_type_str(v, name, &str, errp);
+    if (*errp) {
         return;
     }
 
@@ -672,9 +667,9 @@ static void xen_block_blockdev_del(const char *node_name, Error **errp)
 static char *xen_block_blockdev_add(const char *id, QDict *qdict,
                                     Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     const char *driver = qdict_get_try_str(qdict, "driver");
     BlockdevOptions *options = NULL;
-    Error *local_err = NULL;
     char *node_name;
     Visitor *v;
 
@@ -689,18 +684,16 @@ static char *xen_block_blockdev_add(const char *id, QDict *qdict,
     trace_xen_block_blockdev_add(node_name);
 
     v = qobject_input_visitor_new(QOBJECT(qdict));
-    visit_type_BlockdevOptions(v, NULL, &options, &local_err);
+    visit_type_BlockdevOptions(v, NULL, &options, errp);
     visit_free(v);
 
-    if (local_err) {
-        error_propagate(errp, local_err);
+    if (*errp) {
         goto fail;
     }
 
-    qmp_blockdev_add(options, &local_err);
+    qmp_blockdev_add(options, errp);
 
-    if (local_err) {
-        error_propagate(errp, local_err);
+    if (*errp) {
         goto fail;
     }
 
@@ -719,14 +712,12 @@ fail:
 
 static void xen_block_drive_destroy(XenBlockDrive *drive, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     char *node_name = drive->node_name;
 
     if (node_name) {
-        Error *local_err = NULL;
-
-        xen_block_blockdev_del(node_name, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
+        xen_block_blockdev_del(node_name, errp);
+        if (*errp) {
             return;
         }
         g_free(node_name);
@@ -740,6 +731,7 @@ static XenBlockDrive *xen_block_drive_create(const char *id,
                                              const char *device_type,
                                              QDict *opts, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     const char *params = qdict_get_try_str(opts, "params");
     const char *mode = qdict_get_try_str(opts, "mode");
     const char *direct_io_safe = qdict_get_try_str(opts, "direct-io-safe");
@@ -747,7 +739,6 @@ static XenBlockDrive *xen_block_drive_create(const char *id,
     char *driver = NULL;
     char *filename = NULL;
     XenBlockDrive *drive = NULL;
-    Error *local_err = NULL;
     QDict *file_layer;
     QDict *driver_layer;
 
@@ -826,13 +817,12 @@ static XenBlockDrive *xen_block_drive_create(const char *id,
 
     g_assert(!drive->node_name);
     drive->node_name = xen_block_blockdev_add(drive->id, driver_layer,
-                                              &local_err);
+                                              errp);
 
     qobject_unref(driver_layer);
 
 done:
-    if (local_err) {
-        error_propagate(errp, local_err);
+    if (*errp) {
         xen_block_drive_destroy(drive, NULL);
         return NULL;
     }
@@ -857,8 +847,8 @@ static void xen_block_iothread_destroy(XenBlockIOThread *iothread,
 static XenBlockIOThread *xen_block_iothread_create(const char *id,
                                                    Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenBlockIOThread *iothread = g_new(XenBlockIOThread, 1);
-    Error *local_err = NULL;
     QDict *opts;
     QObject *ret_data;
 
@@ -867,13 +857,11 @@ static XenBlockIOThread *xen_block_iothread_create(const char *id,
     opts = qdict_new();
     qdict_put_str(opts, "qom-type", TYPE_IOTHREAD);
     qdict_put_str(opts, "id", id);
-    qmp_object_add(opts, &ret_data, &local_err);
+    qmp_object_add(opts, &ret_data, errp);
     qobject_unref(opts);
     qobject_unref(ret_data);
 
-    if (local_err) {
-        error_propagate(errp, local_err);
-
+    if (*errp) {
         g_free(iothread->id);
         g_free(iothread);
         return NULL;
@@ -885,6 +873,7 @@ static XenBlockIOThread *xen_block_iothread_create(const char *id,
 static void xen_block_device_create(XenBackendInstance *backend,
                                     QDict *opts, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenBus *xenbus = xen_backend_get_bus(backend);
     const char *name = xen_backend_get_name(backend);
     unsigned long number;
@@ -892,7 +881,6 @@ static void xen_block_device_create(XenBackendInstance *backend,
     XenBlockDrive *drive = NULL;
     XenBlockIOThread *iothread = NULL;
     XenDevice *xendev = NULL;
-    Error *local_err = NULL;
     const char *type;
     XenBlockDevice *blockdev;
 
@@ -924,52 +912,48 @@ static void xen_block_device_create(XenBackendInstance *backend,
         goto fail;
     }
 
-    drive = xen_block_drive_create(vdev, device_type, opts, &local_err);
+    drive = xen_block_drive_create(vdev, device_type, opts, errp);
     if (!drive) {
-        error_propagate_prepend(errp, local_err, "failed to create drive: ");
+        error_prepend(errp, "failed to create drive: ");
         goto fail;
     }
 
-    iothread = xen_block_iothread_create(vdev, &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to create iothread: ");
+    iothread = xen_block_iothread_create(vdev, errp);
+    if (*errp) {
+        error_prepend(errp, "failed to create iothread: ");
         goto fail;
     }
 
     xendev = XEN_DEVICE(qdev_create(BUS(xenbus), type));
     blockdev = XEN_BLOCK_DEVICE(xendev);
 
-    object_property_set_str(OBJECT(xendev), vdev, "vdev", &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err, "failed to set 'vdev': ");
+    object_property_set_str(OBJECT(xendev), vdev, "vdev", errp);
+    if (*errp) {
+        error_prepend(errp, "failed to set 'vdev': ");
         goto fail;
     }
 
     object_property_set_str(OBJECT(xendev),
                             xen_block_drive_get_node_name(drive), "drive",
-                            &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err, "failed to set 'drive': ");
+                            errp);
+    if (*errp) {
+        error_prepend(errp, "failed to set 'drive': ");
         goto fail;
     }
 
     object_property_set_str(OBJECT(xendev), iothread->id, "iothread",
-                            &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to set 'iothread': ");
+                            errp);
+    if (*errp) {
+        error_prepend(errp, "failed to set 'iothread': ");
         goto fail;
     }
 
     blockdev->iothread = iothread;
     blockdev->drive = drive;
 
-    object_property_set_bool(OBJECT(xendev), true, "realized", &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "realization of device %s failed: ",
-                                type);
+    object_property_set_bool(OBJECT(xendev), true, "realized", errp);
+    if (*errp) {
+        error_prepend(errp, "realization of device %s failed: ", type);
         goto fail;
     }
 
@@ -993,6 +977,7 @@ fail:
 static void xen_block_device_destroy(XenBackendInstance *backend,
                                      Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenDevice *xendev = xen_backend_get_device(backend);
     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
     XenBlockVdev *vdev = &blockdev->props.vdev;
@@ -1004,23 +989,17 @@ static void xen_block_device_destroy(XenBackendInstance *backend,
     object_unparent(OBJECT(xendev));
 
     if (iothread) {
-        Error *local_err = NULL;
-
-        xen_block_iothread_destroy(iothread, &local_err);
-        if (local_err) {
-            error_propagate_prepend(errp, local_err,
-                                "failed to destroy iothread: ");
+        xen_block_iothread_destroy(iothread, errp);
+        if (*errp) {
+            error_prepend(errp, "failed to destroy iothread: ");
             return;
         }
     }
 
     if (drive) {
-        Error *local_err = NULL;
-
-        xen_block_drive_destroy(drive, &local_err);
-        if (local_err) {
-            error_propagate_prepend(errp, local_err,
-                                "failed to destroy drive: ");
+        xen_block_drive_destroy(drive, errp);
+        if (*errp) {
+            error_prepend(errp, "failed to destroy drive: ");
         }
     }
 }
diff --git a/hw/pci-host/xen_igd_pt.c b/hw/pci-host/xen_igd_pt.c
index efcc9347ff..29ade9ca25 100644
--- a/hw/pci-host/xen_igd_pt.c
+++ b/hw/pci-host/xen_igd_pt.c
@@ -79,17 +79,16 @@ static void host_pci_config_read(int pos, int len, uint32_t *val, Error **errp)
 
 static void igd_pt_i440fx_realize(PCIDevice *pci_dev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     uint32_t val = 0;
     size_t i;
     int pos, len;
-    Error *local_err = NULL;
 
     for (i = 0; i < ARRAY_SIZE(igd_host_bridge_infos); i++) {
         pos = igd_host_bridge_infos[i].offset;
         len = igd_host_bridge_infos[i].len;
-        host_pci_config_read(pos, len, &val, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
+        host_pci_config_read(pos, len, &val, errp);
+        if (*errp) {
             return;
         }
         pci_default_write_config(pci_dev, pos, val, len);
diff --git a/hw/xen/xen-backend.c b/hw/xen/xen-backend.c
index da065f81b7..1cc0694053 100644
--- a/hw/xen/xen-backend.c
+++ b/hw/xen/xen-backend.c
@@ -98,9 +98,9 @@ static void xen_backend_list_remove(XenBackendInstance *backend)
 void xen_backend_device_create(XenBus *xenbus, const char *type,
                                const char *name, QDict *opts, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     const XenBackendImpl *impl = xen_backend_table_lookup(type);
     XenBackendInstance *backend;
-    Error *local_error = NULL;
 
     if (!impl) {
         return;
@@ -110,9 +110,8 @@ void xen_backend_device_create(XenBus *xenbus, const char *type,
     backend->xenbus = xenbus;
     backend->name = g_strdup(name);
 
-    impl->create(backend, opts, &local_error);
-    if (local_error) {
-        error_propagate(errp, local_error);
+    impl->create(backend, opts, errp);
+    if (*errp) {
         g_free(backend->name);
         g_free(backend);
         return;
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
index 18237b34ea..97259c964b 100644
--- a/hw/xen/xen-bus.c
+++ b/hw/xen/xen-bus.c
@@ -53,9 +53,9 @@ static char *xen_device_get_frontend_path(XenDevice *xendev)
 
 static void xen_device_unplug(XenDevice *xendev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     const char *type = object_get_typename(OBJECT(xendev));
-    Error *local_err = NULL;
     xs_transaction_t tid;
 
     trace_xen_device_unplug(type, xendev->name);
@@ -69,14 +69,14 @@ again:
     }
 
     xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "online",
-                   &local_err, "%u", 0);
-    if (local_err) {
+                   errp, "%u", 0);
+    if (*errp) {
         goto abort;
     }
 
     xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "state",
-                   &local_err, "%u", XenbusStateClosing);
-    if (local_err) {
+                   errp, "%u", XenbusStateClosing);
+    if (*errp) {
         goto abort;
     }
 
@@ -96,7 +96,6 @@ abort:
      * from ending the transaction.
      */
     xs_transaction_end(xenbus->xsh, tid, true);
-    error_propagate(errp, local_err);
 }
 
 static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent)
@@ -205,15 +204,13 @@ static XenWatch *watch_list_add(XenWatchList *watch_list, const char *node,
                                 const char *key, XenWatchHandler handler,
                                 void *opaque, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenWatch *watch = new_watch(node, key, handler, opaque);
-    Error *local_err = NULL;
 
     notifier_list_add(&watch_list->notifiers, &watch->notifier);
 
-    xs_node_watch(watch_list->xsh, node, key, watch->token, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-
+    xs_node_watch(watch_list->xsh, node, key, watch->token, errp);
+    if (*errp) {
         notifier_remove(&watch->notifier);
         free_watch(watch);
 
@@ -255,11 +252,11 @@ static void xen_bus_backend_create(XenBus *xenbus, const char *type,
                                    const char *name, char *path,
                                    Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     xs_transaction_t tid;
     char **key;
     QDict *opts;
     unsigned int i, n;
-    Error *local_err = NULL;
 
     trace_xen_bus_backend_create(type, path);
 
@@ -314,13 +311,11 @@ again:
         return;
     }
 
-    xen_backend_device_create(xenbus, type, name, opts, &local_err);
+    xen_backend_device_create(xenbus, type, name, opts, errp);
     qobject_unref(opts);
 
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to create '%s' device '%s': ",
-                                type, name);
+    if (*errp) {
+        error_prepend(errp, "failed to create '%s' device '%s': ", type, name);
     }
 }
 
@@ -692,9 +687,9 @@ static void xen_device_remove_watch(XenDevice *xendev, XenWatch *watch,
 
 static void xen_device_backend_create(XenDevice *xendev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     struct xs_permissions perms[2];
-    Error *local_err = NULL;
 
     xendev->backend_path = xen_device_get_backend_path(xendev);
 
@@ -706,30 +701,27 @@ static void xen_device_backend_create(XenDevice *xendev, Error **errp)
     g_assert(xenbus->xsh);
 
     xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms,
-                   ARRAY_SIZE(perms), &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to create backend: ");
+                   ARRAY_SIZE(perms), errp);
+    if (*errp) {
+        error_prepend(errp, "failed to create backend: ");
         return;
     }
 
     xendev->backend_state_watch =
         xen_device_add_watch(xendev, xendev->backend_path,
                              "state", xen_device_backend_changed,
-                             &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to watch backend state: ");
+                             errp);
+    if (*errp) {
+        error_prepend(errp, "failed to watch backend state: ");
         return;
     }
 
     xendev->backend_online_watch =
         xen_device_add_watch(xendev, xendev->backend_path,
                              "online", xen_device_backend_changed,
-                             &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to watch backend online: ");
+                             errp);
+    if (*errp) {
+        error_prepend(errp, "failed to watch backend online: ");
         return;
     }
 }
@@ -866,9 +858,9 @@ static bool xen_device_frontend_exists(XenDevice *xendev)
 
 static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     struct xs_permissions perms[2];
-    Error *local_err = NULL;
 
     xendev->frontend_path = xen_device_get_frontend_path(xendev);
 
@@ -885,20 +877,18 @@ static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
         g_assert(xenbus->xsh);
 
         xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms,
-                       ARRAY_SIZE(perms), &local_err);
-        if (local_err) {
-            error_propagate_prepend(errp, local_err,
-                                    "failed to create frontend: ");
+                       ARRAY_SIZE(perms), errp);
+        if (*errp) {
+            error_prepend(errp, "failed to create frontend: ");
             return;
         }
     }
 
     xendev->frontend_state_watch =
         xen_device_add_watch(xendev, xendev->frontend_path, "state",
-                             xen_device_frontend_changed, &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to watch frontend state: ");
+                             xen_device_frontend_changed, errp);
+    if (*errp) {
+        error_prepend(errp, "failed to watch frontend state: ");
     }
 }
 
@@ -1247,11 +1237,11 @@ static void xen_device_exit(Notifier *n, void *data)
 
 static void xen_device_realize(DeviceState *dev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenDevice *xendev = XEN_DEVICE(dev);
     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     const char *type = object_get_typename(OBJECT(xendev));
-    Error *local_err = NULL;
 
     if (xendev->frontend_id == DOMID_INVALID) {
         xendev->frontend_id = xen_domid;
@@ -1267,10 +1257,9 @@ static void xen_device_realize(DeviceState *dev, Error **errp)
         goto unrealize;
     }
 
-    xendev->name = xendev_class->get_name(xendev, &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to get device name: ");
+    xendev->name = xendev_class->get_name(xendev, errp);
+    if (*errp) {
+        error_prepend(errp, "failed to get device name: ");
         goto unrealize;
     }
 
@@ -1293,22 +1282,19 @@ static void xen_device_realize(DeviceState *dev, Error **errp)
     xendev->feature_grant_copy =
         (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0);
 
-    xen_device_backend_create(xendev, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    xen_device_backend_create(xendev, errp);
+    if (*errp) {
         goto unrealize;
     }
 
-    xen_device_frontend_create(xendev, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    xen_device_frontend_create(xendev, errp);
+    if (*errp) {
         goto unrealize;
     }
 
     if (xendev_class->realize) {
-        xendev_class->realize(xendev, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
+        xendev_class->realize(xendev, errp);
+        if (*errp) {
             goto unrealize;
         }
     }
diff --git a/hw/xen/xen-host-pci-device.c b/hw/xen/xen-host-pci-device.c
index 1b44dcafaf..02379c341c 100644
--- a/hw/xen/xen-host-pci-device.c
+++ b/hw/xen/xen-host-pci-device.c
@@ -333,8 +333,8 @@ void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
                              uint8_t bus, uint8_t dev, uint8_t func,
                              Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     unsigned int v;
-    Error *err = NULL;
 
     d->config_fd = -1;
     d->domain = domain;
@@ -342,36 +342,36 @@ void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
     d->dev = dev;
     d->func = func;
 
-    xen_host_pci_config_open(d, &err);
-    if (err) {
+    xen_host_pci_config_open(d, errp);
+    if (*errp) {
         goto error;
     }
 
-    xen_host_pci_get_resource(d, &err);
-    if (err) {
+    xen_host_pci_get_resource(d, errp);
+    if (*errp) {
         goto error;
     }
 
-    xen_host_pci_get_hex_value(d, "vendor", &v, &err);
-    if (err) {
+    xen_host_pci_get_hex_value(d, "vendor", &v, errp);
+    if (*errp) {
         goto error;
     }
     d->vendor_id = v;
 
-    xen_host_pci_get_hex_value(d, "device", &v, &err);
-    if (err) {
+    xen_host_pci_get_hex_value(d, "device", &v, errp);
+    if (*errp) {
         goto error;
     }
     d->device_id = v;
 
-    xen_host_pci_get_dec_value(d, "irq", &v, &err);
-    if (err) {
+    xen_host_pci_get_dec_value(d, "irq", &v, errp);
+    if (*errp) {
         goto error;
     }
     d->irq = v;
 
-    xen_host_pci_get_hex_value(d, "class", &v, &err);
-    if (err) {
+    xen_host_pci_get_hex_value(d, "class", &v, errp);
+    if (*errp) {
         goto error;
     }
     d->class_code = v;
@@ -381,7 +381,6 @@ void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
     return;
 
 error:
-    error_propagate(errp, err);
 
     if (d->config_fd >= 0) {
         close(d->config_fd);
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index b91082cb8b..f57b81588e 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -767,12 +767,12 @@ static void xen_pt_destroy(PCIDevice *d) {
 
 static void xen_pt_realize(PCIDevice *d, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
     int i, rc = 0;
     uint8_t machine_irq = 0, scratch;
     uint16_t cmd = 0;
     int pirq = XEN_PT_UNASSIGNED_PIRQ;
-    Error *err = NULL;
 
     /* register real device */
     XEN_PT_LOG(d, "Assigning real physical device %02x:%02x.%d"
@@ -783,10 +783,9 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
     xen_host_pci_device_get(&s->real_device,
                             s->hostaddr.domain, s->hostaddr.bus,
                             s->hostaddr.slot, s->hostaddr.function,
-                            &err);
-    if (err) {
-        error_append_hint(&err, "Failed to \"open\" the real pci device");
-        error_propagate(errp, err);
+                            errp);
+    if (*errp) {
+        error_append_hint(errp, "Failed to \"open\" the real pci device");
         return;
     }
 
@@ -813,11 +812,10 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
             return;
         }
 
-        xen_pt_setup_vga(s, &s->real_device, &err);
-        if (err) {
-            error_append_hint(&err, "Setup VGA BIOS of passthrough"
-                    " GFX failed");
-            error_propagate(errp, err);
+        xen_pt_setup_vga(s, &s->real_device, errp);
+        if (*errp) {
+            error_append_hint(errp, "Setup VGA BIOS of passthrough"
+                              " GFX failed");
             xen_host_pci_device_put(&s->real_device);
             return;
         }
@@ -830,10 +828,9 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
     xen_pt_register_regions(s, &cmd);
 
     /* reinitialize each config register to be emulated */
-    xen_pt_config_init(s, &err);
-    if (err) {
-        error_append_hint(&err, "PCI Config space initialisation failed");
-        error_propagate(errp, err);
+    xen_pt_config_init(s, errp);
+    if (*errp) {
+        error_append_hint(errp, "PCI Config space initialisation failed");
         rc = -1;
         goto err_out;
     }
diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c
index 31ec5add1d..af3fbd1bfb 100644
--- a/hw/xen/xen_pt_config_init.c
+++ b/hw/xen/xen_pt_config_init.c
@@ -2008,8 +2008,8 @@ static void xen_pt_config_reg_init(XenPCIPassthroughState *s,
 
 void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     int i, rc;
-    Error *err = NULL;
 
     QLIST_INIT(&s->reg_grps);
 
@@ -2052,10 +2052,9 @@ void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp)
                                                   reg_grp_offset,
                                                   &reg_grp_entry->size);
             if (rc < 0) {
-                error_setg(&err, "Failed to initialize %d/%zu, type = 0x%x,"
+                error_setg(errp, "Failed to initialize %d/%zu, type = 0x%x,"
                            " rc: %d", i, ARRAY_SIZE(xen_pt_emu_reg_grps),
                            xen_pt_emu_reg_grps[i].grp_type, rc);
-                error_propagate(errp, err);
                 xen_pt_config_delete(s);
                 return;
             }
@@ -2068,13 +2067,14 @@ void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp)
 
                 /* initialize capability register */
                 for (j = 0; regs->size != 0; j++, regs++) {
-                    xen_pt_config_reg_init(s, reg_grp_entry, regs, &err);
-                    if (err) {
-                        error_append_hint(&err, "Failed to init register %d"
-                                " offsets 0x%x in grp_type = 0x%x (%d/%zu)", j,
-                                regs->offset, xen_pt_emu_reg_grps[i].grp_type,
-                                i, ARRAY_SIZE(xen_pt_emu_reg_grps));
-                        error_propagate(errp, err);
+                    xen_pt_config_reg_init(s, reg_grp_entry, regs, errp);
+                    if (*errp) {
+                        error_append_hint(errp, "Failed to init register %d"
+                                          " offsets 0x%x in grp_type = 0x%x (%d/%zu)",
+                                          j,
+                                          regs->offset,
+                                          xen_pt_emu_reg_grps[i].grp_type,
+                                          i, ARRAY_SIZE(xen_pt_emu_reg_grps));
                         xen_pt_config_delete(s);
                         return;
                     }
-- 
2.21.0



^ permalink raw reply related	[flat|nested] 67+ messages in thread

* [Xen-devel] [PATCH v9 10/10] xen: introduce ERRP_AUTO_PROPAGATE
@ 2020-03-12  8:59   ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-12  8:59 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant, armbru,
	Greg Kurz, vsementsov, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz

If we want to add some info to errp (by error_prepend() or
error_append_hint()), we must use the ERRP_AUTO_PROPAGATE macro.
Otherwise, this info will not be added when errp == &error_fatal
(the program will exit prior to the error_append_hint() or
error_prepend() call).  Fix such cases.

If we want to check error after errp-function call, we need to
introduce local_err and then propagate it to errp. Instead, use
ERRP_AUTO_PROPAGATE macro, benefits are:
1. No need of explicit error_propagate call
2. No need of explicit local_err variable: use errp directly
3. ERRP_AUTO_PROPAGATE leaves errp as is if it's not NULL or
   &error_fatal, this means that we don't break error_abort
   (we'll abort on error_set, not on error_propagate)

This commit is generated by command

    sed -n '/^X86 Xen CPUs$/,/^$/{s/^F: //p}' MAINTAINERS | \
    xargs git ls-files | grep '\.[hc]$' | \
    xargs spatch \
        --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
        --macro-file scripts/cocci-macro-file.h \
        --in-place --no-show-diff --max-width 80

Reported-by: Kevin Wolf <kwolf@redhat.com>
Reported-by: Greg Kurz <groug@kaod.org>
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Paul Durrant <paul@xen.org>
---
 hw/block/dataplane/xen-block.c |  17 ++---
 hw/block/xen-block.c           | 125 ++++++++++++++-------------------
 hw/pci-host/xen_igd_pt.c       |   7 +-
 hw/xen/xen-backend.c           |   7 +-
 hw/xen/xen-bus.c               |  92 ++++++++++--------------
 hw/xen/xen-host-pci-device.c   |  27 ++++---
 hw/xen/xen_pt.c                |  25 +++----
 hw/xen/xen_pt_config_init.c    |  20 +++---
 8 files changed, 138 insertions(+), 182 deletions(-)

diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c
index 288a87a814..3a8469fe87 100644
--- a/hw/block/dataplane/xen-block.c
+++ b/hw/block/dataplane/xen-block.c
@@ -739,8 +739,8 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
                                unsigned int protocol,
                                Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenDevice *xendev = dataplane->xendev;
-    Error *local_err = NULL;
     unsigned int ring_size;
     unsigned int i;
 
@@ -776,9 +776,8 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
     }
 
     xen_device_set_max_grant_refs(xendev, dataplane->nr_ring_ref,
-                                  &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+                                  errp);
+    if (*errp) {
         goto stop;
     }
 
@@ -786,9 +785,8 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
                                               dataplane->ring_ref,
                                               dataplane->nr_ring_ref,
                                               PROT_READ | PROT_WRITE,
-                                              &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+                                              errp);
+    if (*errp) {
         goto stop;
     }
 
@@ -821,9 +819,8 @@ void xen_block_dataplane_start(XenBlockDataPlane *dataplane,
     dataplane->event_channel =
         xen_device_bind_event_channel(xendev, event_channel,
                                       xen_block_dataplane_event, dataplane,
-                                      &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+                                      errp);
+    if (*errp) {
         goto stop;
     }
 
diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c
index 3885464513..5d4c94181c 100644
--- a/hw/block/xen-block.c
+++ b/hw/block/xen-block.c
@@ -195,6 +195,7 @@ static const BlockDevOps xen_block_dev_ops = {
 
 static void xen_block_realize(XenDevice *xendev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
     XenBlockDeviceClass *blockdev_class =
         XEN_BLOCK_DEVICE_GET_CLASS(xendev);
@@ -202,7 +203,6 @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
     XenBlockVdev *vdev = &blockdev->props.vdev;
     BlockConf *conf = &blockdev->props.conf;
     BlockBackend *blk = conf->blk;
-    Error *local_err = NULL;
 
     if (vdev->type == XEN_BLOCK_VDEV_TYPE_INVALID) {
         error_setg(errp, "vdev property not set");
@@ -212,9 +212,8 @@ static void xen_block_realize(XenDevice *xendev, Error **errp)
     trace_xen_block_realize(type, vdev->disk, vdev->partition);
 
     if (blockdev_class->realize) {
-        blockdev_class->realize(blockdev, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
+        blockdev_class->realize(blockdev, errp);
+        if (*errp) {
             return;
         }
     }
@@ -284,8 +283,8 @@ static void xen_block_frontend_changed(XenDevice *xendev,
                                        enum xenbus_state frontend_state,
                                        Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     enum xenbus_state backend_state = xen_device_backend_get_state(xendev);
-    Error *local_err = NULL;
 
     switch (frontend_state) {
     case XenbusStateInitialised:
@@ -294,15 +293,13 @@ static void xen_block_frontend_changed(XenDevice *xendev,
             break;
         }
 
-        xen_block_disconnect(xendev, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
+        xen_block_disconnect(xendev, errp);
+        if (*errp) {
             break;
         }
 
-        xen_block_connect(xendev, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
+        xen_block_connect(xendev, errp);
+        if (*errp) {
             break;
         }
 
@@ -315,9 +312,8 @@ static void xen_block_frontend_changed(XenDevice *xendev,
 
     case XenbusStateClosed:
     case XenbusStateUnknown:
-        xen_block_disconnect(xendev, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
+        xen_block_disconnect(xendev, errp);
+        if (*errp) {
             break;
         }
 
@@ -404,10 +400,10 @@ static int vbd_name_to_disk(const char *name, const char **endp,
 static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name,
                                void *opaque, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     XenBlockVdev *vdev = qdev_get_prop_ptr(dev, prop);
-    Error *local_err = NULL;
     char *str, *p;
     const char *end;
 
@@ -416,9 +412,8 @@ static void xen_block_set_vdev(Object *obj, Visitor *v, const char *name,
         return;
     }
 
-    visit_type_str(v, name, &str, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    visit_type_str(v, name, &str, errp);
+    if (*errp) {
         return;
     }
 
@@ -672,9 +667,9 @@ static void xen_block_blockdev_del(const char *node_name, Error **errp)
 static char *xen_block_blockdev_add(const char *id, QDict *qdict,
                                     Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     const char *driver = qdict_get_try_str(qdict, "driver");
     BlockdevOptions *options = NULL;
-    Error *local_err = NULL;
     char *node_name;
     Visitor *v;
 
@@ -689,18 +684,16 @@ static char *xen_block_blockdev_add(const char *id, QDict *qdict,
     trace_xen_block_blockdev_add(node_name);
 
     v = qobject_input_visitor_new(QOBJECT(qdict));
-    visit_type_BlockdevOptions(v, NULL, &options, &local_err);
+    visit_type_BlockdevOptions(v, NULL, &options, errp);
     visit_free(v);
 
-    if (local_err) {
-        error_propagate(errp, local_err);
+    if (*errp) {
         goto fail;
     }
 
-    qmp_blockdev_add(options, &local_err);
+    qmp_blockdev_add(options, errp);
 
-    if (local_err) {
-        error_propagate(errp, local_err);
+    if (*errp) {
         goto fail;
     }
 
@@ -719,14 +712,12 @@ fail:
 
 static void xen_block_drive_destroy(XenBlockDrive *drive, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     char *node_name = drive->node_name;
 
     if (node_name) {
-        Error *local_err = NULL;
-
-        xen_block_blockdev_del(node_name, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
+        xen_block_blockdev_del(node_name, errp);
+        if (*errp) {
             return;
         }
         g_free(node_name);
@@ -740,6 +731,7 @@ static XenBlockDrive *xen_block_drive_create(const char *id,
                                              const char *device_type,
                                              QDict *opts, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     const char *params = qdict_get_try_str(opts, "params");
     const char *mode = qdict_get_try_str(opts, "mode");
     const char *direct_io_safe = qdict_get_try_str(opts, "direct-io-safe");
@@ -747,7 +739,6 @@ static XenBlockDrive *xen_block_drive_create(const char *id,
     char *driver = NULL;
     char *filename = NULL;
     XenBlockDrive *drive = NULL;
-    Error *local_err = NULL;
     QDict *file_layer;
     QDict *driver_layer;
 
@@ -826,13 +817,12 @@ static XenBlockDrive *xen_block_drive_create(const char *id,
 
     g_assert(!drive->node_name);
     drive->node_name = xen_block_blockdev_add(drive->id, driver_layer,
-                                              &local_err);
+                                              errp);
 
     qobject_unref(driver_layer);
 
 done:
-    if (local_err) {
-        error_propagate(errp, local_err);
+    if (*errp) {
         xen_block_drive_destroy(drive, NULL);
         return NULL;
     }
@@ -857,8 +847,8 @@ static void xen_block_iothread_destroy(XenBlockIOThread *iothread,
 static XenBlockIOThread *xen_block_iothread_create(const char *id,
                                                    Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenBlockIOThread *iothread = g_new(XenBlockIOThread, 1);
-    Error *local_err = NULL;
     QDict *opts;
     QObject *ret_data;
 
@@ -867,13 +857,11 @@ static XenBlockIOThread *xen_block_iothread_create(const char *id,
     opts = qdict_new();
     qdict_put_str(opts, "qom-type", TYPE_IOTHREAD);
     qdict_put_str(opts, "id", id);
-    qmp_object_add(opts, &ret_data, &local_err);
+    qmp_object_add(opts, &ret_data, errp);
     qobject_unref(opts);
     qobject_unref(ret_data);
 
-    if (local_err) {
-        error_propagate(errp, local_err);
-
+    if (*errp) {
         g_free(iothread->id);
         g_free(iothread);
         return NULL;
@@ -885,6 +873,7 @@ static XenBlockIOThread *xen_block_iothread_create(const char *id,
 static void xen_block_device_create(XenBackendInstance *backend,
                                     QDict *opts, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenBus *xenbus = xen_backend_get_bus(backend);
     const char *name = xen_backend_get_name(backend);
     unsigned long number;
@@ -892,7 +881,6 @@ static void xen_block_device_create(XenBackendInstance *backend,
     XenBlockDrive *drive = NULL;
     XenBlockIOThread *iothread = NULL;
     XenDevice *xendev = NULL;
-    Error *local_err = NULL;
     const char *type;
     XenBlockDevice *blockdev;
 
@@ -924,52 +912,48 @@ static void xen_block_device_create(XenBackendInstance *backend,
         goto fail;
     }
 
-    drive = xen_block_drive_create(vdev, device_type, opts, &local_err);
+    drive = xen_block_drive_create(vdev, device_type, opts, errp);
     if (!drive) {
-        error_propagate_prepend(errp, local_err, "failed to create drive: ");
+        error_prepend(errp, "failed to create drive: ");
         goto fail;
     }
 
-    iothread = xen_block_iothread_create(vdev, &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to create iothread: ");
+    iothread = xen_block_iothread_create(vdev, errp);
+    if (*errp) {
+        error_prepend(errp, "failed to create iothread: ");
         goto fail;
     }
 
     xendev = XEN_DEVICE(qdev_create(BUS(xenbus), type));
     blockdev = XEN_BLOCK_DEVICE(xendev);
 
-    object_property_set_str(OBJECT(xendev), vdev, "vdev", &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err, "failed to set 'vdev': ");
+    object_property_set_str(OBJECT(xendev), vdev, "vdev", errp);
+    if (*errp) {
+        error_prepend(errp, "failed to set 'vdev': ");
         goto fail;
     }
 
     object_property_set_str(OBJECT(xendev),
                             xen_block_drive_get_node_name(drive), "drive",
-                            &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err, "failed to set 'drive': ");
+                            errp);
+    if (*errp) {
+        error_prepend(errp, "failed to set 'drive': ");
         goto fail;
     }
 
     object_property_set_str(OBJECT(xendev), iothread->id, "iothread",
-                            &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to set 'iothread': ");
+                            errp);
+    if (*errp) {
+        error_prepend(errp, "failed to set 'iothread': ");
         goto fail;
     }
 
     blockdev->iothread = iothread;
     blockdev->drive = drive;
 
-    object_property_set_bool(OBJECT(xendev), true, "realized", &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "realization of device %s failed: ",
-                                type);
+    object_property_set_bool(OBJECT(xendev), true, "realized", errp);
+    if (*errp) {
+        error_prepend(errp, "realization of device %s failed: ", type);
         goto fail;
     }
 
@@ -993,6 +977,7 @@ fail:
 static void xen_block_device_destroy(XenBackendInstance *backend,
                                      Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenDevice *xendev = xen_backend_get_device(backend);
     XenBlockDevice *blockdev = XEN_BLOCK_DEVICE(xendev);
     XenBlockVdev *vdev = &blockdev->props.vdev;
@@ -1004,23 +989,17 @@ static void xen_block_device_destroy(XenBackendInstance *backend,
     object_unparent(OBJECT(xendev));
 
     if (iothread) {
-        Error *local_err = NULL;
-
-        xen_block_iothread_destroy(iothread, &local_err);
-        if (local_err) {
-            error_propagate_prepend(errp, local_err,
-                                "failed to destroy iothread: ");
+        xen_block_iothread_destroy(iothread, errp);
+        if (*errp) {
+            error_prepend(errp, "failed to destroy iothread: ");
             return;
         }
     }
 
     if (drive) {
-        Error *local_err = NULL;
-
-        xen_block_drive_destroy(drive, &local_err);
-        if (local_err) {
-            error_propagate_prepend(errp, local_err,
-                                "failed to destroy drive: ");
+        xen_block_drive_destroy(drive, errp);
+        if (*errp) {
+            error_prepend(errp, "failed to destroy drive: ");
         }
     }
 }
diff --git a/hw/pci-host/xen_igd_pt.c b/hw/pci-host/xen_igd_pt.c
index efcc9347ff..29ade9ca25 100644
--- a/hw/pci-host/xen_igd_pt.c
+++ b/hw/pci-host/xen_igd_pt.c
@@ -79,17 +79,16 @@ static void host_pci_config_read(int pos, int len, uint32_t *val, Error **errp)
 
 static void igd_pt_i440fx_realize(PCIDevice *pci_dev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     uint32_t val = 0;
     size_t i;
     int pos, len;
-    Error *local_err = NULL;
 
     for (i = 0; i < ARRAY_SIZE(igd_host_bridge_infos); i++) {
         pos = igd_host_bridge_infos[i].offset;
         len = igd_host_bridge_infos[i].len;
-        host_pci_config_read(pos, len, &val, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
+        host_pci_config_read(pos, len, &val, errp);
+        if (*errp) {
             return;
         }
         pci_default_write_config(pci_dev, pos, val, len);
diff --git a/hw/xen/xen-backend.c b/hw/xen/xen-backend.c
index da065f81b7..1cc0694053 100644
--- a/hw/xen/xen-backend.c
+++ b/hw/xen/xen-backend.c
@@ -98,9 +98,9 @@ static void xen_backend_list_remove(XenBackendInstance *backend)
 void xen_backend_device_create(XenBus *xenbus, const char *type,
                                const char *name, QDict *opts, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     const XenBackendImpl *impl = xen_backend_table_lookup(type);
     XenBackendInstance *backend;
-    Error *local_error = NULL;
 
     if (!impl) {
         return;
@@ -110,9 +110,8 @@ void xen_backend_device_create(XenBus *xenbus, const char *type,
     backend->xenbus = xenbus;
     backend->name = g_strdup(name);
 
-    impl->create(backend, opts, &local_error);
-    if (local_error) {
-        error_propagate(errp, local_error);
+    impl->create(backend, opts, errp);
+    if (*errp) {
         g_free(backend->name);
         g_free(backend);
         return;
diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c
index 18237b34ea..97259c964b 100644
--- a/hw/xen/xen-bus.c
+++ b/hw/xen/xen-bus.c
@@ -53,9 +53,9 @@ static char *xen_device_get_frontend_path(XenDevice *xendev)
 
 static void xen_device_unplug(XenDevice *xendev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     const char *type = object_get_typename(OBJECT(xendev));
-    Error *local_err = NULL;
     xs_transaction_t tid;
 
     trace_xen_device_unplug(type, xendev->name);
@@ -69,14 +69,14 @@ again:
     }
 
     xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "online",
-                   &local_err, "%u", 0);
-    if (local_err) {
+                   errp, "%u", 0);
+    if (*errp) {
         goto abort;
     }
 
     xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "state",
-                   &local_err, "%u", XenbusStateClosing);
-    if (local_err) {
+                   errp, "%u", XenbusStateClosing);
+    if (*errp) {
         goto abort;
     }
 
@@ -96,7 +96,6 @@ abort:
      * from ending the transaction.
      */
     xs_transaction_end(xenbus->xsh, tid, true);
-    error_propagate(errp, local_err);
 }
 
 static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent)
@@ -205,15 +204,13 @@ static XenWatch *watch_list_add(XenWatchList *watch_list, const char *node,
                                 const char *key, XenWatchHandler handler,
                                 void *opaque, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenWatch *watch = new_watch(node, key, handler, opaque);
-    Error *local_err = NULL;
 
     notifier_list_add(&watch_list->notifiers, &watch->notifier);
 
-    xs_node_watch(watch_list->xsh, node, key, watch->token, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
-
+    xs_node_watch(watch_list->xsh, node, key, watch->token, errp);
+    if (*errp) {
         notifier_remove(&watch->notifier);
         free_watch(watch);
 
@@ -255,11 +252,11 @@ static void xen_bus_backend_create(XenBus *xenbus, const char *type,
                                    const char *name, char *path,
                                    Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     xs_transaction_t tid;
     char **key;
     QDict *opts;
     unsigned int i, n;
-    Error *local_err = NULL;
 
     trace_xen_bus_backend_create(type, path);
 
@@ -314,13 +311,11 @@ again:
         return;
     }
 
-    xen_backend_device_create(xenbus, type, name, opts, &local_err);
+    xen_backend_device_create(xenbus, type, name, opts, errp);
     qobject_unref(opts);
 
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to create '%s' device '%s': ",
-                                type, name);
+    if (*errp) {
+        error_prepend(errp, "failed to create '%s' device '%s': ", type, name);
     }
 }
 
@@ -692,9 +687,9 @@ static void xen_device_remove_watch(XenDevice *xendev, XenWatch *watch,
 
 static void xen_device_backend_create(XenDevice *xendev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     struct xs_permissions perms[2];
-    Error *local_err = NULL;
 
     xendev->backend_path = xen_device_get_backend_path(xendev);
 
@@ -706,30 +701,27 @@ static void xen_device_backend_create(XenDevice *xendev, Error **errp)
     g_assert(xenbus->xsh);
 
     xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms,
-                   ARRAY_SIZE(perms), &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to create backend: ");
+                   ARRAY_SIZE(perms), errp);
+    if (*errp) {
+        error_prepend(errp, "failed to create backend: ");
         return;
     }
 
     xendev->backend_state_watch =
         xen_device_add_watch(xendev, xendev->backend_path,
                              "state", xen_device_backend_changed,
-                             &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to watch backend state: ");
+                             errp);
+    if (*errp) {
+        error_prepend(errp, "failed to watch backend state: ");
         return;
     }
 
     xendev->backend_online_watch =
         xen_device_add_watch(xendev, xendev->backend_path,
                              "online", xen_device_backend_changed,
-                             &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to watch backend online: ");
+                             errp);
+    if (*errp) {
+        error_prepend(errp, "failed to watch backend online: ");
         return;
     }
 }
@@ -866,9 +858,9 @@ static bool xen_device_frontend_exists(XenDevice *xendev)
 
 static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     struct xs_permissions perms[2];
-    Error *local_err = NULL;
 
     xendev->frontend_path = xen_device_get_frontend_path(xendev);
 
@@ -885,20 +877,18 @@ static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
         g_assert(xenbus->xsh);
 
         xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms,
-                       ARRAY_SIZE(perms), &local_err);
-        if (local_err) {
-            error_propagate_prepend(errp, local_err,
-                                    "failed to create frontend: ");
+                       ARRAY_SIZE(perms), errp);
+        if (*errp) {
+            error_prepend(errp, "failed to create frontend: ");
             return;
         }
     }
 
     xendev->frontend_state_watch =
         xen_device_add_watch(xendev, xendev->frontend_path, "state",
-                             xen_device_frontend_changed, &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to watch frontend state: ");
+                             xen_device_frontend_changed, errp);
+    if (*errp) {
+        error_prepend(errp, "failed to watch frontend state: ");
     }
 }
 
@@ -1247,11 +1237,11 @@ static void xen_device_exit(Notifier *n, void *data)
 
 static void xen_device_realize(DeviceState *dev, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenDevice *xendev = XEN_DEVICE(dev);
     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
     const char *type = object_get_typename(OBJECT(xendev));
-    Error *local_err = NULL;
 
     if (xendev->frontend_id == DOMID_INVALID) {
         xendev->frontend_id = xen_domid;
@@ -1267,10 +1257,9 @@ static void xen_device_realize(DeviceState *dev, Error **errp)
         goto unrealize;
     }
 
-    xendev->name = xendev_class->get_name(xendev, &local_err);
-    if (local_err) {
-        error_propagate_prepend(errp, local_err,
-                                "failed to get device name: ");
+    xendev->name = xendev_class->get_name(xendev, errp);
+    if (*errp) {
+        error_prepend(errp, "failed to get device name: ");
         goto unrealize;
     }
 
@@ -1293,22 +1282,19 @@ static void xen_device_realize(DeviceState *dev, Error **errp)
     xendev->feature_grant_copy =
         (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0);
 
-    xen_device_backend_create(xendev, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    xen_device_backend_create(xendev, errp);
+    if (*errp) {
         goto unrealize;
     }
 
-    xen_device_frontend_create(xendev, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    xen_device_frontend_create(xendev, errp);
+    if (*errp) {
         goto unrealize;
     }
 
     if (xendev_class->realize) {
-        xendev_class->realize(xendev, &local_err);
-        if (local_err) {
-            error_propagate(errp, local_err);
+        xendev_class->realize(xendev, errp);
+        if (*errp) {
             goto unrealize;
         }
     }
diff --git a/hw/xen/xen-host-pci-device.c b/hw/xen/xen-host-pci-device.c
index 1b44dcafaf..02379c341c 100644
--- a/hw/xen/xen-host-pci-device.c
+++ b/hw/xen/xen-host-pci-device.c
@@ -333,8 +333,8 @@ void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
                              uint8_t bus, uint8_t dev, uint8_t func,
                              Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     unsigned int v;
-    Error *err = NULL;
 
     d->config_fd = -1;
     d->domain = domain;
@@ -342,36 +342,36 @@ void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
     d->dev = dev;
     d->func = func;
 
-    xen_host_pci_config_open(d, &err);
-    if (err) {
+    xen_host_pci_config_open(d, errp);
+    if (*errp) {
         goto error;
     }
 
-    xen_host_pci_get_resource(d, &err);
-    if (err) {
+    xen_host_pci_get_resource(d, errp);
+    if (*errp) {
         goto error;
     }
 
-    xen_host_pci_get_hex_value(d, "vendor", &v, &err);
-    if (err) {
+    xen_host_pci_get_hex_value(d, "vendor", &v, errp);
+    if (*errp) {
         goto error;
     }
     d->vendor_id = v;
 
-    xen_host_pci_get_hex_value(d, "device", &v, &err);
-    if (err) {
+    xen_host_pci_get_hex_value(d, "device", &v, errp);
+    if (*errp) {
         goto error;
     }
     d->device_id = v;
 
-    xen_host_pci_get_dec_value(d, "irq", &v, &err);
-    if (err) {
+    xen_host_pci_get_dec_value(d, "irq", &v, errp);
+    if (*errp) {
         goto error;
     }
     d->irq = v;
 
-    xen_host_pci_get_hex_value(d, "class", &v, &err);
-    if (err) {
+    xen_host_pci_get_hex_value(d, "class", &v, errp);
+    if (*errp) {
         goto error;
     }
     d->class_code = v;
@@ -381,7 +381,6 @@ void xen_host_pci_device_get(XenHostPCIDevice *d, uint16_t domain,
     return;
 
 error:
-    error_propagate(errp, err);
 
     if (d->config_fd >= 0) {
         close(d->config_fd);
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
index b91082cb8b..f57b81588e 100644
--- a/hw/xen/xen_pt.c
+++ b/hw/xen/xen_pt.c
@@ -767,12 +767,12 @@ static void xen_pt_destroy(PCIDevice *d) {
 
 static void xen_pt_realize(PCIDevice *d, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     XenPCIPassthroughState *s = XEN_PT_DEVICE(d);
     int i, rc = 0;
     uint8_t machine_irq = 0, scratch;
     uint16_t cmd = 0;
     int pirq = XEN_PT_UNASSIGNED_PIRQ;
-    Error *err = NULL;
 
     /* register real device */
     XEN_PT_LOG(d, "Assigning real physical device %02x:%02x.%d"
@@ -783,10 +783,9 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
     xen_host_pci_device_get(&s->real_device,
                             s->hostaddr.domain, s->hostaddr.bus,
                             s->hostaddr.slot, s->hostaddr.function,
-                            &err);
-    if (err) {
-        error_append_hint(&err, "Failed to \"open\" the real pci device");
-        error_propagate(errp, err);
+                            errp);
+    if (*errp) {
+        error_append_hint(errp, "Failed to \"open\" the real pci device");
         return;
     }
 
@@ -813,11 +812,10 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
             return;
         }
 
-        xen_pt_setup_vga(s, &s->real_device, &err);
-        if (err) {
-            error_append_hint(&err, "Setup VGA BIOS of passthrough"
-                    " GFX failed");
-            error_propagate(errp, err);
+        xen_pt_setup_vga(s, &s->real_device, errp);
+        if (*errp) {
+            error_append_hint(errp, "Setup VGA BIOS of passthrough"
+                              " GFX failed");
             xen_host_pci_device_put(&s->real_device);
             return;
         }
@@ -830,10 +828,9 @@ static void xen_pt_realize(PCIDevice *d, Error **errp)
     xen_pt_register_regions(s, &cmd);
 
     /* reinitialize each config register to be emulated */
-    xen_pt_config_init(s, &err);
-    if (err) {
-        error_append_hint(&err, "PCI Config space initialisation failed");
-        error_propagate(errp, err);
+    xen_pt_config_init(s, errp);
+    if (*errp) {
+        error_append_hint(errp, "PCI Config space initialisation failed");
         rc = -1;
         goto err_out;
     }
diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c
index 31ec5add1d..af3fbd1bfb 100644
--- a/hw/xen/xen_pt_config_init.c
+++ b/hw/xen/xen_pt_config_init.c
@@ -2008,8 +2008,8 @@ static void xen_pt_config_reg_init(XenPCIPassthroughState *s,
 
 void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp)
 {
+    ERRP_AUTO_PROPAGATE();
     int i, rc;
-    Error *err = NULL;
 
     QLIST_INIT(&s->reg_grps);
 
@@ -2052,10 +2052,9 @@ void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp)
                                                   reg_grp_offset,
                                                   &reg_grp_entry->size);
             if (rc < 0) {
-                error_setg(&err, "Failed to initialize %d/%zu, type = 0x%x,"
+                error_setg(errp, "Failed to initialize %d/%zu, type = 0x%x,"
                            " rc: %d", i, ARRAY_SIZE(xen_pt_emu_reg_grps),
                            xen_pt_emu_reg_grps[i].grp_type, rc);
-                error_propagate(errp, err);
                 xen_pt_config_delete(s);
                 return;
             }
@@ -2068,13 +2067,14 @@ void xen_pt_config_init(XenPCIPassthroughState *s, Error **errp)
 
                 /* initialize capability register */
                 for (j = 0; regs->size != 0; j++, regs++) {
-                    xen_pt_config_reg_init(s, reg_grp_entry, regs, &err);
-                    if (err) {
-                        error_append_hint(&err, "Failed to init register %d"
-                                " offsets 0x%x in grp_type = 0x%x (%d/%zu)", j,
-                                regs->offset, xen_pt_emu_reg_grps[i].grp_type,
-                                i, ARRAY_SIZE(xen_pt_emu_reg_grps));
-                        error_propagate(errp, err);
+                    xen_pt_config_reg_init(s, reg_grp_entry, regs, errp);
+                    if (*errp) {
+                        error_append_hint(errp, "Failed to init register %d"
+                                          " offsets 0x%x in grp_type = 0x%x (%d/%zu)",
+                                          j,
+                                          regs->offset,
+                                          xen_pt_emu_reg_grps[i].grp_type,
+                                          i, ARRAY_SIZE(xen_pt_emu_reg_grps));
                         xen_pt_config_delete(s);
                         return;
                     }
-- 
2.21.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 00/10] error: auto propagated local_err part I
  2020-03-12  8:59 ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-12 14:24   ` Markus Armbruster
  -1 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-12 14:24 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> v9
> 01: A lot of rewordings [thanks to Eric]
>     Still, keep all r-b marks, assuming that they are mostly about macro definition
> 02: significant changes are:
>     1. Do not match double propagation pattern in ERRP_AUTO_PROPAGATE-adding rule
>     2. Introduce errp->____->errp scheme to match only functions matched by rule1
>        in rules inherited from rule1
>     3. Add rules to warn about unusual patterns
>
>     Also, add line to MAINTAINERS to keep error related coccinelle scripts under
>     Error section.
> 07: add Christian's r-b
> 09: add Eric's r-b
> 10: a bit of context in xen_block_iothread_create  and qmp_object_add()
>     signature are changed. Patch change is obvious, so I keep Paul's r-b
>
> v9 is available at
>  https://src.openvz.org/scm/~vsementsov/qemu.git #tag up-auto-local-err-partI-v9

Did you forget to push the tag?

> v8 is available at
>  https://src.openvz.org/scm/~vsementsov/qemu.git #tag up-auto-local-err-partI-v8
[...]



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 00/10] error: auto propagated local_err part I
@ 2020-03-12 14:24   ` Markus Armbruster
  0 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-12 14:24 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> v9
> 01: A lot of rewordings [thanks to Eric]
>     Still, keep all r-b marks, assuming that they are mostly about macro definition
> 02: significant changes are:
>     1. Do not match double propagation pattern in ERRP_AUTO_PROPAGATE-adding rule
>     2. Introduce errp->____->errp scheme to match only functions matched by rule1
>        in rules inherited from rule1
>     3. Add rules to warn about unusual patterns
>
>     Also, add line to MAINTAINERS to keep error related coccinelle scripts under
>     Error section.
> 07: add Christian's r-b
> 09: add Eric's r-b
> 10: a bit of context in xen_block_iothread_create  and qmp_object_add()
>     signature are changed. Patch change is obvious, so I keep Paul's r-b
>
> v9 is available at
>  https://src.openvz.org/scm/~vsementsov/qemu.git #tag up-auto-local-err-partI-v9

Did you forget to push the tag?

> v8 is available at
>  https://src.openvz.org/scm/~vsementsov/qemu.git #tag up-auto-local-err-partI-v8
[...]


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-12  8:59   ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-12 16:36     ` Markus Armbruster
  -1 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-12 16:36 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	armbru, Stefan Berger

I may have a second look tomorrow with fresher eyes, but let's get this
out now as is.

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
> does corresponding changes in code (look for details in
> include/qapi/error.h)
>
> Usage example:
> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>  --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>  --max-width 80 FILES...
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> ---
>
> Cc: Eric Blake <eblake@redhat.com>
> Cc: Kevin Wolf <kwolf@redhat.com>
> Cc: Max Reitz <mreitz@redhat.com>
> Cc: Greg Kurz <groug@kaod.org>
> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
> Cc: Stefano Stabellini <sstabellini@kernel.org>
> Cc: Anthony Perard <anthony.perard@citrix.com>
> Cc: Paul Durrant <paul@xen.org>
> Cc: Stefan Hajnoczi <stefanha@redhat.com>
> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Stefan Berger <stefanb@linux.ibm.com>
> Cc: Markus Armbruster <armbru@redhat.com>
> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
> Cc: qemu-devel@nongnu.org
> Cc: qemu-block@nongnu.org
> Cc: xen-devel@lists.xenproject.org
>
>  scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>  include/qapi/error.h                          |   3 +
>  MAINTAINERS                                   |   1 +
>  3 files changed, 331 insertions(+)
>  create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>
> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
> new file mode 100644
> index 0000000000..7dac2dcfa4
> --- /dev/null
> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
> @@ -0,0 +1,327 @@
> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
> +//
> +// Copyright (c) 2020 Virtuozzo International GmbH.
> +//
> +// This program is free software; you can redistribute it and/or
> +// modify it under the terms of the GNU General Public License as
> +// published by the Free Software Foundation; either version 2 of the
> +// License, or (at your option) any later version.
> +//
> +// This program is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +// GNU General Public License for more details.
> +//
> +// You should have received a copy of the GNU General Public License
> +// along with this program.  If not, see
> +// <http://www.gnu.org/licenses/>.
> +//
> +// Usage example:
> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
> +//  --macro-file scripts/cocci-macro-file.h --in-place \
> +//  --no-show-diff --max-width 80 FILES...
> +//
> +// Note: --max-width 80 is needed because coccinelle default is less
> +// than 80, and without this parameter coccinelle may reindent some
> +// lines which fit into 80 characters but not to coccinelle default,
> +// which in turn produces extra patch hunks for no reason.

This is about unwanted reformatting of parameter lists due to the ___
chaining hack.  --max-width 80 makes that less likely, but not
impossible.

We can search for unwanted reformatting of parameter lists.  I think
grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
tree, I get one false positive (not a parameter list), and one hit:

    @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
         }
     }

    -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
    +void object_apply_global_props(Object *obj, const GPtrArray *props,
    +                               Error **errp)
     {
    +    ERRP_AUTO_PROPAGATE();
         int i;

         if (!props) {

Reformatting, but not unwanted.

The --max-width 80 hack is good enough for me.

It does result in slightly long transformed lines, e.g. this one in
replication.c:

    @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
             s->mode = REPLICATION_MODE_PRIMARY;
             top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
             if (top_id) {
    -            error_setg(&local_err, "The primary side does not support option top-id");
    +            error_setg(errp, "The primary side does not support option top-id");
                 goto fail;
             }
         } else if (!strcmp(mode, "secondary")) {

v8 did break this line (that's how I found it).  However, v9 still
shortens the line, just not below the target.  All your + lines look
quite unlikely to lengthen lines.  Let's not worry about this.

> +// Switch unusual Error ** parameter names to errp
> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
> +//
> +// Disable optional_qualifier to skip functions with
> +// "Error *const *errp" parameter.
> +//
> +// Skip functions with "assert(_errp && *_errp)" statement, because
> +// that signals unusual semantics, and the parameter name may well
> +// serve a purpose. (like nbd_iter_channel_error()).
> +//
> +// Skip util/error.c to not touch, for example, error_propagate() and
> +// error_propagate_prepend().
> +@ depends on !(file in "util/error.c") disable optional_qualifier@
> +identifier fn;
> +identifier _errp != errp;
> +@@
> +
> + fn(...,
> +-   Error **_errp
> ++   Error **errp
> +    ,...)
> + {
> +(
> +     ... when != assert(_errp && *_errp)
> +&
> +     <...
> +-    _errp
> ++    errp
> +     ...>
> +)
> + }
> +
> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
> +// necessary
> +//
> +// Note, that without "when any" the final "..." does not mach
> +// something matched by previous pattern, i.e. the rule will not match
> +// double error_prepend in control flow like in
> +// vfio_set_irq_signaling().
> +//
> +// Note, "exists" says that we want apply rule even if it matches not
> +// on all possible control flows (otherwise, it will not match
> +// standard pattern when error_propagate() call is in if branch).
> +@ disable optional_qualifier exists@
> +identifier fn, local_err;
> +symbol errp;
> +@@
> +
> + fn(..., Error **errp, ...)
> + {
> ++   ERRP_AUTO_PROPAGATE();
> +    ...  when != ERRP_AUTO_PROPAGATE();
> +(
> +(
> +    error_append_hint(errp, ...);
> +|
> +    error_prepend(errp, ...);
> +|
> +    error_vprepend(errp, ...);
> +)
> +    ... when any
> +|
> +    Error *local_err = NULL;
> +    ...
> +(
> +    error_propagate_prepend(errp, local_err, ...);
> +|
> +    error_propagate(errp, local_err);
> +)
> +    ...
> +)
> + }
> +
> +
> +// Match functions with propagation of local error to errp.
> +// We want to refer these functions in several following rules, but I
> +// don't know a proper way to inherit a function, not just its name
> +// (to not match another functions with same name in following rules).
> +// Not-proper way is as follows: rename errp parameter in functions
> +// header and match it in following rules. Rename it back after all
> +// transformations.
> +//
> +// The simplest case of propagation scheme is single definition of
> +// local_err with at most one error_propagate_prepend or
> +// error_propagate on each control-flow. Still, we want to match more
> +// complex schemes too. We'll warn them with help of further rules.

I think what we actually want is to examine instances of this pattern to
figure out whether and how we want to transform them.  Perhaps:

    // The common case is a single definition of local_err with at most one
    // error_propagate_prepend() or error_propagate() on each control-flow
    // path. Instances of this case we convert with this script. Functions
    // with multiple definitions or propagates we want to examine
    // manually. Later rules emit warnings to guide us to them.

> +@rule1 disable optional_qualifier exists@
> +identifier fn, local_err;
> +symbol errp;
> +@@
> +
> + fn(..., Error **
> +-    errp
> ++    ____
> +    , ...)
> + {
> +     ...
> +     Error *local_err = NULL;
> +     ...
> +(
> +     error_propagate_prepend(errp, local_err, ...);
> +|
> +     error_propagate(errp, local_err);
> +)
> +     ...
> + }
> +
> +
> +// Warn several Error * definitions.
> +@check1 disable optional_qualifier exists@
> +identifier fn = rule1.fn, local_err, local_err2;

Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
particular reason for the difference?

With the ___ chaining hack, I doubt we still need "= rule1.fn" or
"rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
everywhere, then apply the script to the complete tree, I get the same
result.

> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     ...
> +     Error *local_err = NULL;
> +     ... when any
> +     Error *local_err2 = NULL;
> +     ... when any
> + }
> +
> +@ script:python @
> +fn << check1.fn;
> +@@
> +
> +print('Warning: function {} has several definitions of '
> +      'Error * local variable'.format(fn))
> +
> +// Warn several propagations in control flow.
> +@check2 disable optional_qualifier exists@
> +identifier fn = rule1.fn;
> +symbol errp;
> +position p1, p2;
> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     ...
> +(
> +     error_propagate_prepend(errp, ...);@p1
> +|
> +     error_propagate(errp, ...);@p1
> +)
> +     ...
> +(
> +     error_propagate_prepend(errp, ...);@p2
> +|
> +     error_propagate(errp, ...);@p2
> +)
> +     ... when any
> + }
> +

Hmm, we don't catch the example I used in review of v8:

    extern foo(int, Error **);
    extern bar(int, Error **);

    void frob(Error **errp)
    {
        Error *local_err = NULL;
        int arg;

        foo(arg, errp);
        bar(arg, &local_err);
        error_propagate(errp, local_err);
        bar(arg + 1, &local_err);
        error_propagate(errp, local_err);
    }

I believe this is because rule1 does not match here.

If I change the rule as follows, it catches the example:

    @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '

     // Warn several propagations in control flow.
     @check2 disable optional_qualifier exists@
    -identifier fn = rule1.fn;
    -symbol errp;
    +identifier fn, _errp;
     position p1, p2;
     @@

    - fn(..., Error ** ____, ...)
    + fn(..., Error **_errp, ...)
      {
          ...
     (
    -     error_propagate_prepend(errp, ...);@p1
    +     error_propagate_prepend(_errp, ...);@p1
     |
    -     error_propagate(errp, ...);@p1
    +     error_propagate(_errp, ...);@p1
     )
          ...
     (
    -     error_propagate_prepend(errp, ...);@p2
    +     error_propagate_prepend(_errp, ...);@p2
     |
    -     error_propagate(errp, ...);@p2
    +     error_propagate(_errp, ...);@p2
     )
          ... when any
      }

To my mild surprise, it still doesn't find anything in our tree.

Should we decouple the previous rule from rule1, too?  I tested the
following on the whole tree:

    @@ -136,10 +136,10 @@ symbol errp;

     // Warn several Error * definitions.
     @check1 disable optional_qualifier exists@
    -identifier fn = rule1.fn, local_err, local_err2;
    +identifier fn, _errp, local_err, local_err2;
     @@

    - fn(..., Error ** ____, ...)
    + fn(..., Error **_errp, ...)
      {
          ...
          Error *local_err = NULL;

Warnings remain unchanged.

> +@ script:python @
> +fn << check2.fn;
> +p1 << check2.p1;
> +p2 << check2.p2;
> +@@
> +
> +print('Warning: function {} propagates to errp several times in '
> +      'one control flow: at {}:{} and then at {}:{}'.format(
> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> +
> +// Convert special case with goto separately.
> +// I tried merging this into the following rule the obvious way, but
> +// it made Coccinelle hang on block.c
> +//
> +// Note interesting thing: if we don't do it here, and try to fixup
> +// "out: }" things later after all transformations (the rule will be
> +// the same, just without error_propagate() call), coccinelle fails to
> +// match this "out: }".
> +@ disable optional_qualifier@
> +identifier rule1.fn, rule1.local_err, out;

As explained above, I doubt the need for rule1.fn.  We do need
rule1.local_err to avoid unwanted transformations.  More of the same
below.

> +symbol errp;
> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     <...
> +-    goto out;
> ++    return;
> +     ...>
> +- out:
> +-    error_propagate(errp, local_err);
> + }
> +
> +// Convert most of local_err related stuff.
> +//
> +// Note, that we update everything related to matched by rule1
> +// function name and local_err name. We may match something not
> +// related to the pattern matched by rule1. For example, local_err may
> +// be defined with the same name in different blocks inside one
> +// function, and in one block follow the propagation pattern and in
> +// other block doesn't. Or we may have several functions with the same
> +// name (for different configurations).
> +//
> +// Note also that errp-cleaning functions
> +//   error_free_errp
> +//   error_report_errp
> +//   error_reportf_errp
> +//   warn_report_errp
> +//   warn_reportf_errp
> +// are not yet implemented. They must call corresponding Error* -
> +// freeing function and then set *errp to NULL, to avoid further
> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
> +// For example, error_free_errp may look like this:
> +//
> +//    void error_free_errp(Error **errp)
> +//    {
> +//        error_free(*errp);
> +//        *errp = NULL;
> +//    }
> +@ disable optional_qualifier exists@
> +identifier rule1.fn, rule1.local_err;
> +expression list args;
> +symbol errp;
> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     <...
> +(
> +-    Error *local_err = NULL;
> +|
> +
> +// Convert error clearing functions
> +(
> +-    error_free(local_err);
> ++    error_free_errp(errp);
> +|
> +-    error_report_err(local_err);
> ++    error_report_errp(errp);
> +|
> +-    error_reportf_err(local_err, args);
> ++    error_reportf_errp(errp, args);
> +|
> +-    warn_report_err(local_err);
> ++    warn_report_errp(errp);
> +|
> +-    warn_reportf_err(local_err, args);
> ++    warn_reportf_errp(errp, args);
> +)
> +?-    local_err = NULL;
> +
> +|
> +-    error_propagate_prepend(errp, local_err, args);
> ++    error_prepend(errp, args);
> +|
> +-    error_propagate(errp, local_err);
> +|
> +-    &local_err
> ++    errp
> +)
> +     ...>
> + }
> +
> +// Convert remaining local_err usage. For example, different kinds of
> +// error checking in if conditionals. We can't merge this into
> +// previous hunk, as this conflicts with other substitutions in it (at
> +// least with "- local_err = NULL").
> +@ disable optional_qualifier@
> +identifier rule1.fn, rule1.local_err;
> +symbol errp;
> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     <...
> +-    local_err
> ++    *errp
> +     ...>
> + }
> +
> +// Always use the same pattern for checking error
> +@ disable optional_qualifier@
> +identifier rule1.fn;
> +symbol errp;
> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     <...
> +-    *errp != NULL
> ++    *errp
> +     ...>
> + }
> +
> +// Revert temporary ___ identifier.
> +@ disable optional_qualifier@
> +identifier rule1.fn;
> +@@
> +
> + fn(..., Error **
> +-   ____
> ++   errp
> +    , ...)
> + {
> +     ...
> + }
> diff --git a/include/qapi/error.h b/include/qapi/error.h
> index 30140d9bfe..56c133520d 100644
> --- a/include/qapi/error.h
> +++ b/include/qapi/error.h
> @@ -214,6 +214,9 @@
>   *         }
>   *         ...
>   *     }
> + *
> + * For mass-conversion use script
> + *   scripts/coccinelle/auto-propagated-errp.cocci
>   */
>  
>  #ifndef ERROR_H
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 857f969aa1..047f1b9714 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>  F: qapi/error.json
>  F: util/error.c
>  F: util/qemu-error.c
> +F: scripts/coccinelle/*err*.cocci
>  
>  GDB stub
>  M: Alex Bennée <alex.bennee@linaro.org>



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-12 16:36     ` Markus Armbruster
  0 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-12 16:36 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	armbru, Stefan Berger

I may have a second look tomorrow with fresher eyes, but let's get this
out now as is.

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
> does corresponding changes in code (look for details in
> include/qapi/error.h)
>
> Usage example:
> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>  --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>  --max-width 80 FILES...
>
> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
> ---
>
> Cc: Eric Blake <eblake@redhat.com>
> Cc: Kevin Wolf <kwolf@redhat.com>
> Cc: Max Reitz <mreitz@redhat.com>
> Cc: Greg Kurz <groug@kaod.org>
> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
> Cc: Stefano Stabellini <sstabellini@kernel.org>
> Cc: Anthony Perard <anthony.perard@citrix.com>
> Cc: Paul Durrant <paul@xen.org>
> Cc: Stefan Hajnoczi <stefanha@redhat.com>
> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
> Cc: Laszlo Ersek <lersek@redhat.com>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Stefan Berger <stefanb@linux.ibm.com>
> Cc: Markus Armbruster <armbru@redhat.com>
> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
> Cc: qemu-devel@nongnu.org
> Cc: qemu-block@nongnu.org
> Cc: xen-devel@lists.xenproject.org
>
>  scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>  include/qapi/error.h                          |   3 +
>  MAINTAINERS                                   |   1 +
>  3 files changed, 331 insertions(+)
>  create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>
> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
> new file mode 100644
> index 0000000000..7dac2dcfa4
> --- /dev/null
> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
> @@ -0,0 +1,327 @@
> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
> +//
> +// Copyright (c) 2020 Virtuozzo International GmbH.
> +//
> +// This program is free software; you can redistribute it and/or
> +// modify it under the terms of the GNU General Public License as
> +// published by the Free Software Foundation; either version 2 of the
> +// License, or (at your option) any later version.
> +//
> +// This program is distributed in the hope that it will be useful,
> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +// GNU General Public License for more details.
> +//
> +// You should have received a copy of the GNU General Public License
> +// along with this program.  If not, see
> +// <http://www.gnu.org/licenses/>.
> +//
> +// Usage example:
> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
> +//  --macro-file scripts/cocci-macro-file.h --in-place \
> +//  --no-show-diff --max-width 80 FILES...
> +//
> +// Note: --max-width 80 is needed because coccinelle default is less
> +// than 80, and without this parameter coccinelle may reindent some
> +// lines which fit into 80 characters but not to coccinelle default,
> +// which in turn produces extra patch hunks for no reason.

This is about unwanted reformatting of parameter lists due to the ___
chaining hack.  --max-width 80 makes that less likely, but not
impossible.

We can search for unwanted reformatting of parameter lists.  I think
grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
tree, I get one false positive (not a parameter list), and one hit:

    @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
         }
     }

    -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
    +void object_apply_global_props(Object *obj, const GPtrArray *props,
    +                               Error **errp)
     {
    +    ERRP_AUTO_PROPAGATE();
         int i;

         if (!props) {

Reformatting, but not unwanted.

The --max-width 80 hack is good enough for me.

It does result in slightly long transformed lines, e.g. this one in
replication.c:

    @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
             s->mode = REPLICATION_MODE_PRIMARY;
             top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
             if (top_id) {
    -            error_setg(&local_err, "The primary side does not support option top-id");
    +            error_setg(errp, "The primary side does not support option top-id");
                 goto fail;
             }
         } else if (!strcmp(mode, "secondary")) {

v8 did break this line (that's how I found it).  However, v9 still
shortens the line, just not below the target.  All your + lines look
quite unlikely to lengthen lines.  Let's not worry about this.

> +// Switch unusual Error ** parameter names to errp
> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
> +//
> +// Disable optional_qualifier to skip functions with
> +// "Error *const *errp" parameter.
> +//
> +// Skip functions with "assert(_errp && *_errp)" statement, because
> +// that signals unusual semantics, and the parameter name may well
> +// serve a purpose. (like nbd_iter_channel_error()).
> +//
> +// Skip util/error.c to not touch, for example, error_propagate() and
> +// error_propagate_prepend().
> +@ depends on !(file in "util/error.c") disable optional_qualifier@
> +identifier fn;
> +identifier _errp != errp;
> +@@
> +
> + fn(...,
> +-   Error **_errp
> ++   Error **errp
> +    ,...)
> + {
> +(
> +     ... when != assert(_errp && *_errp)
> +&
> +     <...
> +-    _errp
> ++    errp
> +     ...>
> +)
> + }
> +
> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
> +// necessary
> +//
> +// Note, that without "when any" the final "..." does not mach
> +// something matched by previous pattern, i.e. the rule will not match
> +// double error_prepend in control flow like in
> +// vfio_set_irq_signaling().
> +//
> +// Note, "exists" says that we want apply rule even if it matches not
> +// on all possible control flows (otherwise, it will not match
> +// standard pattern when error_propagate() call is in if branch).
> +@ disable optional_qualifier exists@
> +identifier fn, local_err;
> +symbol errp;
> +@@
> +
> + fn(..., Error **errp, ...)
> + {
> ++   ERRP_AUTO_PROPAGATE();
> +    ...  when != ERRP_AUTO_PROPAGATE();
> +(
> +(
> +    error_append_hint(errp, ...);
> +|
> +    error_prepend(errp, ...);
> +|
> +    error_vprepend(errp, ...);
> +)
> +    ... when any
> +|
> +    Error *local_err = NULL;
> +    ...
> +(
> +    error_propagate_prepend(errp, local_err, ...);
> +|
> +    error_propagate(errp, local_err);
> +)
> +    ...
> +)
> + }
> +
> +
> +// Match functions with propagation of local error to errp.
> +// We want to refer these functions in several following rules, but I
> +// don't know a proper way to inherit a function, not just its name
> +// (to not match another functions with same name in following rules).
> +// Not-proper way is as follows: rename errp parameter in functions
> +// header and match it in following rules. Rename it back after all
> +// transformations.
> +//
> +// The simplest case of propagation scheme is single definition of
> +// local_err with at most one error_propagate_prepend or
> +// error_propagate on each control-flow. Still, we want to match more
> +// complex schemes too. We'll warn them with help of further rules.

I think what we actually want is to examine instances of this pattern to
figure out whether and how we want to transform them.  Perhaps:

    // The common case is a single definition of local_err with at most one
    // error_propagate_prepend() or error_propagate() on each control-flow
    // path. Instances of this case we convert with this script. Functions
    // with multiple definitions or propagates we want to examine
    // manually. Later rules emit warnings to guide us to them.

> +@rule1 disable optional_qualifier exists@
> +identifier fn, local_err;
> +symbol errp;
> +@@
> +
> + fn(..., Error **
> +-    errp
> ++    ____
> +    , ...)
> + {
> +     ...
> +     Error *local_err = NULL;
> +     ...
> +(
> +     error_propagate_prepend(errp, local_err, ...);
> +|
> +     error_propagate(errp, local_err);
> +)
> +     ...
> + }
> +
> +
> +// Warn several Error * definitions.
> +@check1 disable optional_qualifier exists@
> +identifier fn = rule1.fn, local_err, local_err2;

Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
particular reason for the difference?

With the ___ chaining hack, I doubt we still need "= rule1.fn" or
"rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
everywhere, then apply the script to the complete tree, I get the same
result.

> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     ...
> +     Error *local_err = NULL;
> +     ... when any
> +     Error *local_err2 = NULL;
> +     ... when any
> + }
> +
> +@ script:python @
> +fn << check1.fn;
> +@@
> +
> +print('Warning: function {} has several definitions of '
> +      'Error * local variable'.format(fn))
> +
> +// Warn several propagations in control flow.
> +@check2 disable optional_qualifier exists@
> +identifier fn = rule1.fn;
> +symbol errp;
> +position p1, p2;
> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     ...
> +(
> +     error_propagate_prepend(errp, ...);@p1
> +|
> +     error_propagate(errp, ...);@p1
> +)
> +     ...
> +(
> +     error_propagate_prepend(errp, ...);@p2
> +|
> +     error_propagate(errp, ...);@p2
> +)
> +     ... when any
> + }
> +

Hmm, we don't catch the example I used in review of v8:

    extern foo(int, Error **);
    extern bar(int, Error **);

    void frob(Error **errp)
    {
        Error *local_err = NULL;
        int arg;

        foo(arg, errp);
        bar(arg, &local_err);
        error_propagate(errp, local_err);
        bar(arg + 1, &local_err);
        error_propagate(errp, local_err);
    }

I believe this is because rule1 does not match here.

If I change the rule as follows, it catches the example:

    @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '

     // Warn several propagations in control flow.
     @check2 disable optional_qualifier exists@
    -identifier fn = rule1.fn;
    -symbol errp;
    +identifier fn, _errp;
     position p1, p2;
     @@

    - fn(..., Error ** ____, ...)
    + fn(..., Error **_errp, ...)
      {
          ...
     (
    -     error_propagate_prepend(errp, ...);@p1
    +     error_propagate_prepend(_errp, ...);@p1
     |
    -     error_propagate(errp, ...);@p1
    +     error_propagate(_errp, ...);@p1
     )
          ...
     (
    -     error_propagate_prepend(errp, ...);@p2
    +     error_propagate_prepend(_errp, ...);@p2
     |
    -     error_propagate(errp, ...);@p2
    +     error_propagate(_errp, ...);@p2
     )
          ... when any
      }

To my mild surprise, it still doesn't find anything in our tree.

Should we decouple the previous rule from rule1, too?  I tested the
following on the whole tree:

    @@ -136,10 +136,10 @@ symbol errp;

     // Warn several Error * definitions.
     @check1 disable optional_qualifier exists@
    -identifier fn = rule1.fn, local_err, local_err2;
    +identifier fn, _errp, local_err, local_err2;
     @@

    - fn(..., Error ** ____, ...)
    + fn(..., Error **_errp, ...)
      {
          ...
          Error *local_err = NULL;

Warnings remain unchanged.

> +@ script:python @
> +fn << check2.fn;
> +p1 << check2.p1;
> +p2 << check2.p2;
> +@@
> +
> +print('Warning: function {} propagates to errp several times in '
> +      'one control flow: at {}:{} and then at {}:{}'.format(
> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> +
> +// Convert special case with goto separately.
> +// I tried merging this into the following rule the obvious way, but
> +// it made Coccinelle hang on block.c
> +//
> +// Note interesting thing: if we don't do it here, and try to fixup
> +// "out: }" things later after all transformations (the rule will be
> +// the same, just without error_propagate() call), coccinelle fails to
> +// match this "out: }".
> +@ disable optional_qualifier@
> +identifier rule1.fn, rule1.local_err, out;

As explained above, I doubt the need for rule1.fn.  We do need
rule1.local_err to avoid unwanted transformations.  More of the same
below.

> +symbol errp;
> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     <...
> +-    goto out;
> ++    return;
> +     ...>
> +- out:
> +-    error_propagate(errp, local_err);
> + }
> +
> +// Convert most of local_err related stuff.
> +//
> +// Note, that we update everything related to matched by rule1
> +// function name and local_err name. We may match something not
> +// related to the pattern matched by rule1. For example, local_err may
> +// be defined with the same name in different blocks inside one
> +// function, and in one block follow the propagation pattern and in
> +// other block doesn't. Or we may have several functions with the same
> +// name (for different configurations).
> +//
> +// Note also that errp-cleaning functions
> +//   error_free_errp
> +//   error_report_errp
> +//   error_reportf_errp
> +//   warn_report_errp
> +//   warn_reportf_errp
> +// are not yet implemented. They must call corresponding Error* -
> +// freeing function and then set *errp to NULL, to avoid further
> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
> +// For example, error_free_errp may look like this:
> +//
> +//    void error_free_errp(Error **errp)
> +//    {
> +//        error_free(*errp);
> +//        *errp = NULL;
> +//    }
> +@ disable optional_qualifier exists@
> +identifier rule1.fn, rule1.local_err;
> +expression list args;
> +symbol errp;
> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     <...
> +(
> +-    Error *local_err = NULL;
> +|
> +
> +// Convert error clearing functions
> +(
> +-    error_free(local_err);
> ++    error_free_errp(errp);
> +|
> +-    error_report_err(local_err);
> ++    error_report_errp(errp);
> +|
> +-    error_reportf_err(local_err, args);
> ++    error_reportf_errp(errp, args);
> +|
> +-    warn_report_err(local_err);
> ++    warn_report_errp(errp);
> +|
> +-    warn_reportf_err(local_err, args);
> ++    warn_reportf_errp(errp, args);
> +)
> +?-    local_err = NULL;
> +
> +|
> +-    error_propagate_prepend(errp, local_err, args);
> ++    error_prepend(errp, args);
> +|
> +-    error_propagate(errp, local_err);
> +|
> +-    &local_err
> ++    errp
> +)
> +     ...>
> + }
> +
> +// Convert remaining local_err usage. For example, different kinds of
> +// error checking in if conditionals. We can't merge this into
> +// previous hunk, as this conflicts with other substitutions in it (at
> +// least with "- local_err = NULL").
> +@ disable optional_qualifier@
> +identifier rule1.fn, rule1.local_err;
> +symbol errp;
> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     <...
> +-    local_err
> ++    *errp
> +     ...>
> + }
> +
> +// Always use the same pattern for checking error
> +@ disable optional_qualifier@
> +identifier rule1.fn;
> +symbol errp;
> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     <...
> +-    *errp != NULL
> ++    *errp
> +     ...>
> + }
> +
> +// Revert temporary ___ identifier.
> +@ disable optional_qualifier@
> +identifier rule1.fn;
> +@@
> +
> + fn(..., Error **
> +-   ____
> ++   errp
> +    , ...)
> + {
> +     ...
> + }
> diff --git a/include/qapi/error.h b/include/qapi/error.h
> index 30140d9bfe..56c133520d 100644
> --- a/include/qapi/error.h
> +++ b/include/qapi/error.h
> @@ -214,6 +214,9 @@
>   *         }
>   *         ...
>   *     }
> + *
> + * For mass-conversion use script
> + *   scripts/coccinelle/auto-propagated-errp.cocci
>   */
>  
>  #ifndef ERROR_H
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 857f969aa1..047f1b9714 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>  F: qapi/error.json
>  F: util/error.c
>  F: util/qemu-error.c
> +F: scripts/coccinelle/*err*.cocci
>  
>  GDB stub
>  M: Alex Bennée <alex.bennee@linaro.org>


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-12 16:36     ` [Xen-devel] " Markus Armbruster
@ 2020-03-13  6:38       ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-13  6:38 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

12.03.2020 19:36, Markus Armbruster wrote:
> I may have a second look tomorrow with fresher eyes, but let's get this
> out now as is.
> 
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>> does corresponding changes in code (look for details in
>> include/qapi/error.h)
>>
>> Usage example:
>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>   --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>   --max-width 80 FILES...
>>
>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>> ---
>>
>> Cc: Eric Blake <eblake@redhat.com>
>> Cc: Kevin Wolf <kwolf@redhat.com>
>> Cc: Max Reitz <mreitz@redhat.com>
>> Cc: Greg Kurz <groug@kaod.org>
>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>> Cc: Anthony Perard <anthony.perard@citrix.com>
>> Cc: Paul Durrant <paul@xen.org>
>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>> Cc: Markus Armbruster <armbru@redhat.com>
>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>> Cc: qemu-devel@nongnu.org
>> Cc: qemu-block@nongnu.org
>> Cc: xen-devel@lists.xenproject.org
>>
>>   scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>   include/qapi/error.h                          |   3 +
>>   MAINTAINERS                                   |   1 +
>>   3 files changed, 331 insertions(+)
>>   create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>
>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>> new file mode 100644
>> index 0000000000..7dac2dcfa4
>> --- /dev/null
>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>> @@ -0,0 +1,327 @@
>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>> +//
>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>> +//
>> +// This program is free software; you can redistribute it and/or
>> +// modify it under the terms of the GNU General Public License as
>> +// published by the Free Software Foundation; either version 2 of the
>> +// License, or (at your option) any later version.
>> +//
>> +// This program is distributed in the hope that it will be useful,
>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +// GNU General Public License for more details.
>> +//
>> +// You should have received a copy of the GNU General Public License
>> +// along with this program.  If not, see
>> +// <http://www.gnu.org/licenses/>.
>> +//
>> +// Usage example:
>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>> +//  --no-show-diff --max-width 80 FILES...
>> +//
>> +// Note: --max-width 80 is needed because coccinelle default is less
>> +// than 80, and without this parameter coccinelle may reindent some
>> +// lines which fit into 80 characters but not to coccinelle default,
>> +// which in turn produces extra patch hunks for no reason.
> 
> This is about unwanted reformatting of parameter lists due to the ___
> chaining hack.  --max-width 80 makes that less likely, but not
> impossible.
> 
> We can search for unwanted reformatting of parameter lists.  I think
> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
> tree, I get one false positive (not a parameter list), and one hit:
> 
>      @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>           }
>       }
> 
>      -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>      +void object_apply_global_props(Object *obj, const GPtrArray *props,
>      +                               Error **errp)
>       {
>      +    ERRP_AUTO_PROPAGATE();
>           int i;
> 
>           if (!props) {
> 
> Reformatting, but not unwanted.

Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
ERRP_AUTO_PROPAGATE addition even for non-automatic patch.

> 
> The --max-width 80 hack is good enough for me.
> 
> It does result in slightly long transformed lines, e.g. this one in
> replication.c:
> 
>      @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>               s->mode = REPLICATION_MODE_PRIMARY;
>               top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>               if (top_id) {
>      -            error_setg(&local_err, "The primary side does not support option top-id");
>      +            error_setg(errp, "The primary side does not support option top-id");
>                   goto fail;
>               }
>           } else if (!strcmp(mode, "secondary")) {
> 
> v8 did break this line (that's how I found it).  However, v9 still
> shortens the line, just not below the target.  All your + lines look
> quite unlikely to lengthen lines.  Let's not worry about this.
> 
>> +// Switch unusual Error ** parameter names to errp
>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>> +//
>> +// Disable optional_qualifier to skip functions with
>> +// "Error *const *errp" parameter.
>> +//
>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>> +// that signals unusual semantics, and the parameter name may well
>> +// serve a purpose. (like nbd_iter_channel_error()).
>> +//
>> +// Skip util/error.c to not touch, for example, error_propagate() and
>> +// error_propagate_prepend().
>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>> +identifier fn;
>> +identifier _errp != errp;
>> +@@
>> +
>> + fn(...,
>> +-   Error **_errp
>> ++   Error **errp
>> +    ,...)
>> + {
>> +(
>> +     ... when != assert(_errp && *_errp)
>> +&
>> +     <...
>> +-    _errp
>> ++    errp
>> +     ...>
>> +)
>> + }
>> +
>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>> +// necessary
>> +//
>> +// Note, that without "when any" the final "..." does not mach
>> +// something matched by previous pattern, i.e. the rule will not match
>> +// double error_prepend in control flow like in
>> +// vfio_set_irq_signaling().
>> +//
>> +// Note, "exists" says that we want apply rule even if it matches not
>> +// on all possible control flows (otherwise, it will not match
>> +// standard pattern when error_propagate() call is in if branch).
>> +@ disable optional_qualifier exists@
>> +identifier fn, local_err;
>> +symbol errp;
>> +@@
>> +
>> + fn(..., Error **errp, ...)
>> + {
>> ++   ERRP_AUTO_PROPAGATE();
>> +    ...  when != ERRP_AUTO_PROPAGATE();
>> +(
>> +(
>> +    error_append_hint(errp, ...);
>> +|
>> +    error_prepend(errp, ...);
>> +|
>> +    error_vprepend(errp, ...);
>> +)
>> +    ... when any
>> +|
>> +    Error *local_err = NULL;
>> +    ...
>> +(
>> +    error_propagate_prepend(errp, local_err, ...);
>> +|
>> +    error_propagate(errp, local_err);
>> +)
>> +    ...
>> +)
>> + }
>> +
>> +
>> +// Match functions with propagation of local error to errp.
>> +// We want to refer these functions in several following rules, but I
>> +// don't know a proper way to inherit a function, not just its name
>> +// (to not match another functions with same name in following rules).
>> +// Not-proper way is as follows: rename errp parameter in functions
>> +// header and match it in following rules. Rename it back after all
>> +// transformations.
>> +//
>> +// The simplest case of propagation scheme is single definition of
>> +// local_err with at most one error_propagate_prepend or
>> +// error_propagate on each control-flow. Still, we want to match more
>> +// complex schemes too. We'll warn them with help of further rules.
> 
> I think what we actually want is to examine instances of this pattern to
> figure out whether and how we want to transform them.  Perhaps:
> 
>      // The common case is a single definition of local_err with at most one
>      // error_propagate_prepend() or error_propagate() on each control-flow
>      // path. Instances of this case we convert with this script. Functions

For me, sounds a bit like "other things we don't convert".
Actually we convert other things too.

>      // with multiple definitions or propagates we want to examine
>      // manually. Later rules emit warnings to guide us to them.
> 
>> +@rule1 disable optional_qualifier exists@
>> +identifier fn, local_err;
>> +symbol errp;
>> +@@
>> +
>> + fn(..., Error **
>> +-    errp
>> ++    ____
>> +    , ...)
>> + {
>> +     ...
>> +     Error *local_err = NULL;
>> +     ...
>> +(
>> +     error_propagate_prepend(errp, local_err, ...);
>> +|
>> +     error_propagate(errp, local_err);
>> +)
>> +     ...
>> + }
>> +
>> +
>> +// Warn several Error * definitions.
>> +@check1 disable optional_qualifier exists@
>> +identifier fn = rule1.fn, local_err, local_err2;
> 
> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
> particular reason for the difference?

I didn't find other way to ref check1.fn in next python rule. It just don't
work if I write here just rule1.fn.

> 
> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
> everywhere, then apply the script to the complete tree, I get the same
> result.

I think, it's more efficient to reuse names from previous rules. I think it should
work faster (more information, less extra matching).

> 
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     ...
>> +     Error *local_err = NULL;
>> +     ... when any
>> +     Error *local_err2 = NULL;
>> +     ... when any
>> + }
>> +
>> +@ script:python @
>> +fn << check1.fn;
>> +@@
>> +
>> +print('Warning: function {} has several definitions of '
>> +      'Error * local variable'.format(fn))
>> +
>> +// Warn several propagations in control flow.
>> +@check2 disable optional_qualifier exists@
>> +identifier fn = rule1.fn;
>> +symbol errp;
>> +position p1, p2;
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     ...
>> +(
>> +     error_propagate_prepend(errp, ...);@p1
>> +|
>> +     error_propagate(errp, ...);@p1
>> +)
>> +     ...
>> +(
>> +     error_propagate_prepend(errp, ...);@p2
>> +|
>> +     error_propagate(errp, ...);@p2
>> +)
>> +     ... when any
>> + }
>> +
> 
> Hmm, we don't catch the example I used in review of v8:
> 
>      extern foo(int, Error **);
>      extern bar(int, Error **);
> 
>      void frob(Error **errp)
>      {
>          Error *local_err = NULL;
>          int arg;
> 
>          foo(arg, errp);
>          bar(arg, &local_err);
>          error_propagate(errp, local_err);
>          bar(arg + 1, &local_err);
>          error_propagate(errp, local_err);
>      }
> 
> I believe this is because rule1 does not match here.

Yes, rule1 wants at least one code flow with non-doubled propagation.

> 
> If I change the rule as follows, it catches the example:
> 
>      @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
> 
>       // Warn several propagations in control flow.
>       @check2 disable optional_qualifier exists@
>      -identifier fn = rule1.fn;
>      -symbol errp;
>      +identifier fn, _errp;
>       position p1, p2;
>       @@
> 
>      - fn(..., Error ** ____, ...)
>      + fn(..., Error **_errp, ...)
>        {
>            ...
>       (
>      -     error_propagate_prepend(errp, ...);@p1
>      +     error_propagate_prepend(_errp, ...);@p1
>       |
>      -     error_propagate(errp, ...);@p1
>      +     error_propagate(_errp, ...);@p1
>       )
>            ...
>       (
>      -     error_propagate_prepend(errp, ...);@p2
>      +     error_propagate_prepend(_errp, ...);@p2
>       |
>      -     error_propagate(errp, ...);@p2
>      +     error_propagate(_errp, ...);@p2
>       )
>            ... when any
>        }
> 
> To my mild surprise, it still doesn't find anything in our tree.
> 
> Should we decouple the previous rule from rule1, too?  I tested the
> following on the whole tree:

I don't think so. Why to check what we are not going to convert? If we want
to check side things, it's better to do it in other coccinelle script..

> 
>      @@ -136,10 +136,10 @@ symbol errp;
> 
>       // Warn several Error * definitions.
>       @check1 disable optional_qualifier exists@
>      -identifier fn = rule1.fn, local_err, local_err2;
>      +identifier fn, _errp, local_err, local_err2;
>       @@
> 
>      - fn(..., Error ** ____, ...)
>      + fn(..., Error **_errp, ...)
>        {
>            ...
>            Error *local_err = NULL;
> 
> Warnings remain unchanged.
> 
>> +@ script:python @
>> +fn << check2.fn;
>> +p1 << check2.p1;
>> +p2 << check2.p2;
>> +@@
>> +
>> +print('Warning: function {} propagates to errp several times in '
>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>> +
>> +// Convert special case with goto separately.
>> +// I tried merging this into the following rule the obvious way, but
>> +// it made Coccinelle hang on block.c
>> +//
>> +// Note interesting thing: if we don't do it here, and try to fixup
>> +// "out: }" things later after all transformations (the rule will be
>> +// the same, just without error_propagate() call), coccinelle fails to
>> +// match this "out: }".
>> +@ disable optional_qualifier@
>> +identifier rule1.fn, rule1.local_err, out;
> 
> As explained above, I doubt the need for rule1.fn.  We do need
> rule1.local_err to avoid unwanted transformations.  More of the same
> below.

Logically, I want to inherit from rule1. So why not to stress it by inheriting
fn variable? It's just a correct thing to do.
And I hope it helps coccinelle to work more efficiently.

> 
>> +symbol errp;
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     <...
>> +-    goto out;
>> ++    return;
>> +     ...>
>> +- out:
>> +-    error_propagate(errp, local_err);
>> + }
>> +
>> +// Convert most of local_err related stuff.
>> +//
>> +// Note, that we update everything related to matched by rule1
>> +// function name and local_err name. We may match something not
>> +// related to the pattern matched by rule1. For example, local_err may
>> +// be defined with the same name in different blocks inside one
>> +// function, and in one block follow the propagation pattern and in
>> +// other block doesn't. Or we may have several functions with the same
>> +// name (for different configurations).
>> +//
>> +// Note also that errp-cleaning functions
>> +//   error_free_errp
>> +//   error_report_errp
>> +//   error_reportf_errp
>> +//   warn_report_errp
>> +//   warn_reportf_errp
>> +// are not yet implemented. They must call corresponding Error* -
>> +// freeing function and then set *errp to NULL, to avoid further
>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>> +// For example, error_free_errp may look like this:
>> +//
>> +//    void error_free_errp(Error **errp)
>> +//    {
>> +//        error_free(*errp);
>> +//        *errp = NULL;
>> +//    }
>> +@ disable optional_qualifier exists@
>> +identifier rule1.fn, rule1.local_err;
>> +expression list args;
>> +symbol errp;
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     <...
>> +(
>> +-    Error *local_err = NULL;
>> +|
>> +
>> +// Convert error clearing functions
>> +(
>> +-    error_free(local_err);
>> ++    error_free_errp(errp);
>> +|
>> +-    error_report_err(local_err);
>> ++    error_report_errp(errp);
>> +|
>> +-    error_reportf_err(local_err, args);
>> ++    error_reportf_errp(errp, args);
>> +|
>> +-    warn_report_err(local_err);
>> ++    warn_report_errp(errp);
>> +|
>> +-    warn_reportf_err(local_err, args);
>> ++    warn_reportf_errp(errp, args);
>> +)
>> +?-    local_err = NULL;
>> +
>> +|
>> +-    error_propagate_prepend(errp, local_err, args);
>> ++    error_prepend(errp, args);
>> +|
>> +-    error_propagate(errp, local_err);
>> +|
>> +-    &local_err
>> ++    errp
>> +)
>> +     ...>
>> + }
>> +
>> +// Convert remaining local_err usage. For example, different kinds of
>> +// error checking in if conditionals. We can't merge this into
>> +// previous hunk, as this conflicts with other substitutions in it (at
>> +// least with "- local_err = NULL").
>> +@ disable optional_qualifier@
>> +identifier rule1.fn, rule1.local_err;
>> +symbol errp;
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     <...
>> +-    local_err
>> ++    *errp
>> +     ...>
>> + }
>> +
>> +// Always use the same pattern for checking error
>> +@ disable optional_qualifier@
>> +identifier rule1.fn;
>> +symbol errp;
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     <...
>> +-    *errp != NULL
>> ++    *errp
>> +     ...>
>> + }
>> +
>> +// Revert temporary ___ identifier.
>> +@ disable optional_qualifier@
>> +identifier rule1.fn;
>> +@@
>> +
>> + fn(..., Error **
>> +-   ____
>> ++   errp
>> +    , ...)
>> + {
>> +     ...
>> + }
>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>> index 30140d9bfe..56c133520d 100644
>> --- a/include/qapi/error.h
>> +++ b/include/qapi/error.h
>> @@ -214,6 +214,9 @@
>>    *         }
>>    *         ...
>>    *     }
>> + *
>> + * For mass-conversion use script
>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>    */
>>   
>>   #ifndef ERROR_H
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 857f969aa1..047f1b9714 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>   F: qapi/error.json
>>   F: util/error.c
>>   F: util/qemu-error.c
>> +F: scripts/coccinelle/*err*.cocci
>>   
>>   GDB stub
>>   M: Alex Bennée <alex.bennee@linaro.org>
> 


-- 
Best regards,
Vladimir


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-13  6:38       ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-13  6:38 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

12.03.2020 19:36, Markus Armbruster wrote:
> I may have a second look tomorrow with fresher eyes, but let's get this
> out now as is.
> 
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>> does corresponding changes in code (look for details in
>> include/qapi/error.h)
>>
>> Usage example:
>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>   --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>   --max-width 80 FILES...
>>
>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>> ---
>>
>> Cc: Eric Blake <eblake@redhat.com>
>> Cc: Kevin Wolf <kwolf@redhat.com>
>> Cc: Max Reitz <mreitz@redhat.com>
>> Cc: Greg Kurz <groug@kaod.org>
>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>> Cc: Anthony Perard <anthony.perard@citrix.com>
>> Cc: Paul Durrant <paul@xen.org>
>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>> Cc: Laszlo Ersek <lersek@redhat.com>
>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>> Cc: Markus Armbruster <armbru@redhat.com>
>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>> Cc: qemu-devel@nongnu.org
>> Cc: qemu-block@nongnu.org
>> Cc: xen-devel@lists.xenproject.org
>>
>>   scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>   include/qapi/error.h                          |   3 +
>>   MAINTAINERS                                   |   1 +
>>   3 files changed, 331 insertions(+)
>>   create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>
>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>> new file mode 100644
>> index 0000000000..7dac2dcfa4
>> --- /dev/null
>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>> @@ -0,0 +1,327 @@
>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>> +//
>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>> +//
>> +// This program is free software; you can redistribute it and/or
>> +// modify it under the terms of the GNU General Public License as
>> +// published by the Free Software Foundation; either version 2 of the
>> +// License, or (at your option) any later version.
>> +//
>> +// This program is distributed in the hope that it will be useful,
>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +// GNU General Public License for more details.
>> +//
>> +// You should have received a copy of the GNU General Public License
>> +// along with this program.  If not, see
>> +// <http://www.gnu.org/licenses/>.
>> +//
>> +// Usage example:
>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>> +//  --no-show-diff --max-width 80 FILES...
>> +//
>> +// Note: --max-width 80 is needed because coccinelle default is less
>> +// than 80, and without this parameter coccinelle may reindent some
>> +// lines which fit into 80 characters but not to coccinelle default,
>> +// which in turn produces extra patch hunks for no reason.
> 
> This is about unwanted reformatting of parameter lists due to the ___
> chaining hack.  --max-width 80 makes that less likely, but not
> impossible.
> 
> We can search for unwanted reformatting of parameter lists.  I think
> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
> tree, I get one false positive (not a parameter list), and one hit:
> 
>      @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>           }
>       }
> 
>      -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>      +void object_apply_global_props(Object *obj, const GPtrArray *props,
>      +                               Error **errp)
>       {
>      +    ERRP_AUTO_PROPAGATE();
>           int i;
> 
>           if (!props) {
> 
> Reformatting, but not unwanted.

Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
ERRP_AUTO_PROPAGATE addition even for non-automatic patch.

> 
> The --max-width 80 hack is good enough for me.
> 
> It does result in slightly long transformed lines, e.g. this one in
> replication.c:
> 
>      @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>               s->mode = REPLICATION_MODE_PRIMARY;
>               top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>               if (top_id) {
>      -            error_setg(&local_err, "The primary side does not support option top-id");
>      +            error_setg(errp, "The primary side does not support option top-id");
>                   goto fail;
>               }
>           } else if (!strcmp(mode, "secondary")) {
> 
> v8 did break this line (that's how I found it).  However, v9 still
> shortens the line, just not below the target.  All your + lines look
> quite unlikely to lengthen lines.  Let's not worry about this.
> 
>> +// Switch unusual Error ** parameter names to errp
>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>> +//
>> +// Disable optional_qualifier to skip functions with
>> +// "Error *const *errp" parameter.
>> +//
>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>> +// that signals unusual semantics, and the parameter name may well
>> +// serve a purpose. (like nbd_iter_channel_error()).
>> +//
>> +// Skip util/error.c to not touch, for example, error_propagate() and
>> +// error_propagate_prepend().
>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>> +identifier fn;
>> +identifier _errp != errp;
>> +@@
>> +
>> + fn(...,
>> +-   Error **_errp
>> ++   Error **errp
>> +    ,...)
>> + {
>> +(
>> +     ... when != assert(_errp && *_errp)
>> +&
>> +     <...
>> +-    _errp
>> ++    errp
>> +     ...>
>> +)
>> + }
>> +
>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>> +// necessary
>> +//
>> +// Note, that without "when any" the final "..." does not mach
>> +// something matched by previous pattern, i.e. the rule will not match
>> +// double error_prepend in control flow like in
>> +// vfio_set_irq_signaling().
>> +//
>> +// Note, "exists" says that we want apply rule even if it matches not
>> +// on all possible control flows (otherwise, it will not match
>> +// standard pattern when error_propagate() call is in if branch).
>> +@ disable optional_qualifier exists@
>> +identifier fn, local_err;
>> +symbol errp;
>> +@@
>> +
>> + fn(..., Error **errp, ...)
>> + {
>> ++   ERRP_AUTO_PROPAGATE();
>> +    ...  when != ERRP_AUTO_PROPAGATE();
>> +(
>> +(
>> +    error_append_hint(errp, ...);
>> +|
>> +    error_prepend(errp, ...);
>> +|
>> +    error_vprepend(errp, ...);
>> +)
>> +    ... when any
>> +|
>> +    Error *local_err = NULL;
>> +    ...
>> +(
>> +    error_propagate_prepend(errp, local_err, ...);
>> +|
>> +    error_propagate(errp, local_err);
>> +)
>> +    ...
>> +)
>> + }
>> +
>> +
>> +// Match functions with propagation of local error to errp.
>> +// We want to refer these functions in several following rules, but I
>> +// don't know a proper way to inherit a function, not just its name
>> +// (to not match another functions with same name in following rules).
>> +// Not-proper way is as follows: rename errp parameter in functions
>> +// header and match it in following rules. Rename it back after all
>> +// transformations.
>> +//
>> +// The simplest case of propagation scheme is single definition of
>> +// local_err with at most one error_propagate_prepend or
>> +// error_propagate on each control-flow. Still, we want to match more
>> +// complex schemes too. We'll warn them with help of further rules.
> 
> I think what we actually want is to examine instances of this pattern to
> figure out whether and how we want to transform them.  Perhaps:
> 
>      // The common case is a single definition of local_err with at most one
>      // error_propagate_prepend() or error_propagate() on each control-flow
>      // path. Instances of this case we convert with this script. Functions

For me, sounds a bit like "other things we don't convert".
Actually we convert other things too.

>      // with multiple definitions or propagates we want to examine
>      // manually. Later rules emit warnings to guide us to them.
> 
>> +@rule1 disable optional_qualifier exists@
>> +identifier fn, local_err;
>> +symbol errp;
>> +@@
>> +
>> + fn(..., Error **
>> +-    errp
>> ++    ____
>> +    , ...)
>> + {
>> +     ...
>> +     Error *local_err = NULL;
>> +     ...
>> +(
>> +     error_propagate_prepend(errp, local_err, ...);
>> +|
>> +     error_propagate(errp, local_err);
>> +)
>> +     ...
>> + }
>> +
>> +
>> +// Warn several Error * definitions.
>> +@check1 disable optional_qualifier exists@
>> +identifier fn = rule1.fn, local_err, local_err2;
> 
> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
> particular reason for the difference?

I didn't find other way to ref check1.fn in next python rule. It just don't
work if I write here just rule1.fn.

> 
> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
> everywhere, then apply the script to the complete tree, I get the same
> result.

I think, it's more efficient to reuse names from previous rules. I think it should
work faster (more information, less extra matching).

> 
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     ...
>> +     Error *local_err = NULL;
>> +     ... when any
>> +     Error *local_err2 = NULL;
>> +     ... when any
>> + }
>> +
>> +@ script:python @
>> +fn << check1.fn;
>> +@@
>> +
>> +print('Warning: function {} has several definitions of '
>> +      'Error * local variable'.format(fn))
>> +
>> +// Warn several propagations in control flow.
>> +@check2 disable optional_qualifier exists@
>> +identifier fn = rule1.fn;
>> +symbol errp;
>> +position p1, p2;
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     ...
>> +(
>> +     error_propagate_prepend(errp, ...);@p1
>> +|
>> +     error_propagate(errp, ...);@p1
>> +)
>> +     ...
>> +(
>> +     error_propagate_prepend(errp, ...);@p2
>> +|
>> +     error_propagate(errp, ...);@p2
>> +)
>> +     ... when any
>> + }
>> +
> 
> Hmm, we don't catch the example I used in review of v8:
> 
>      extern foo(int, Error **);
>      extern bar(int, Error **);
> 
>      void frob(Error **errp)
>      {
>          Error *local_err = NULL;
>          int arg;
> 
>          foo(arg, errp);
>          bar(arg, &local_err);
>          error_propagate(errp, local_err);
>          bar(arg + 1, &local_err);
>          error_propagate(errp, local_err);
>      }
> 
> I believe this is because rule1 does not match here.

Yes, rule1 wants at least one code flow with non-doubled propagation.

> 
> If I change the rule as follows, it catches the example:
> 
>      @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
> 
>       // Warn several propagations in control flow.
>       @check2 disable optional_qualifier exists@
>      -identifier fn = rule1.fn;
>      -symbol errp;
>      +identifier fn, _errp;
>       position p1, p2;
>       @@
> 
>      - fn(..., Error ** ____, ...)
>      + fn(..., Error **_errp, ...)
>        {
>            ...
>       (
>      -     error_propagate_prepend(errp, ...);@p1
>      +     error_propagate_prepend(_errp, ...);@p1
>       |
>      -     error_propagate(errp, ...);@p1
>      +     error_propagate(_errp, ...);@p1
>       )
>            ...
>       (
>      -     error_propagate_prepend(errp, ...);@p2
>      +     error_propagate_prepend(_errp, ...);@p2
>       |
>      -     error_propagate(errp, ...);@p2
>      +     error_propagate(_errp, ...);@p2
>       )
>            ... when any
>        }
> 
> To my mild surprise, it still doesn't find anything in our tree.
> 
> Should we decouple the previous rule from rule1, too?  I tested the
> following on the whole tree:

I don't think so. Why to check what we are not going to convert? If we want
to check side things, it's better to do it in other coccinelle script..

> 
>      @@ -136,10 +136,10 @@ symbol errp;
> 
>       // Warn several Error * definitions.
>       @check1 disable optional_qualifier exists@
>      -identifier fn = rule1.fn, local_err, local_err2;
>      +identifier fn, _errp, local_err, local_err2;
>       @@
> 
>      - fn(..., Error ** ____, ...)
>      + fn(..., Error **_errp, ...)
>        {
>            ...
>            Error *local_err = NULL;
> 
> Warnings remain unchanged.
> 
>> +@ script:python @
>> +fn << check2.fn;
>> +p1 << check2.p1;
>> +p2 << check2.p2;
>> +@@
>> +
>> +print('Warning: function {} propagates to errp several times in '
>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>> +
>> +// Convert special case with goto separately.
>> +// I tried merging this into the following rule the obvious way, but
>> +// it made Coccinelle hang on block.c
>> +//
>> +// Note interesting thing: if we don't do it here, and try to fixup
>> +// "out: }" things later after all transformations (the rule will be
>> +// the same, just without error_propagate() call), coccinelle fails to
>> +// match this "out: }".
>> +@ disable optional_qualifier@
>> +identifier rule1.fn, rule1.local_err, out;
> 
> As explained above, I doubt the need for rule1.fn.  We do need
> rule1.local_err to avoid unwanted transformations.  More of the same
> below.

Logically, I want to inherit from rule1. So why not to stress it by inheriting
fn variable? It's just a correct thing to do.
And I hope it helps coccinelle to work more efficiently.

> 
>> +symbol errp;
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     <...
>> +-    goto out;
>> ++    return;
>> +     ...>
>> +- out:
>> +-    error_propagate(errp, local_err);
>> + }
>> +
>> +// Convert most of local_err related stuff.
>> +//
>> +// Note, that we update everything related to matched by rule1
>> +// function name and local_err name. We may match something not
>> +// related to the pattern matched by rule1. For example, local_err may
>> +// be defined with the same name in different blocks inside one
>> +// function, and in one block follow the propagation pattern and in
>> +// other block doesn't. Or we may have several functions with the same
>> +// name (for different configurations).
>> +//
>> +// Note also that errp-cleaning functions
>> +//   error_free_errp
>> +//   error_report_errp
>> +//   error_reportf_errp
>> +//   warn_report_errp
>> +//   warn_reportf_errp
>> +// are not yet implemented. They must call corresponding Error* -
>> +// freeing function and then set *errp to NULL, to avoid further
>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>> +// For example, error_free_errp may look like this:
>> +//
>> +//    void error_free_errp(Error **errp)
>> +//    {
>> +//        error_free(*errp);
>> +//        *errp = NULL;
>> +//    }
>> +@ disable optional_qualifier exists@
>> +identifier rule1.fn, rule1.local_err;
>> +expression list args;
>> +symbol errp;
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     <...
>> +(
>> +-    Error *local_err = NULL;
>> +|
>> +
>> +// Convert error clearing functions
>> +(
>> +-    error_free(local_err);
>> ++    error_free_errp(errp);
>> +|
>> +-    error_report_err(local_err);
>> ++    error_report_errp(errp);
>> +|
>> +-    error_reportf_err(local_err, args);
>> ++    error_reportf_errp(errp, args);
>> +|
>> +-    warn_report_err(local_err);
>> ++    warn_report_errp(errp);
>> +|
>> +-    warn_reportf_err(local_err, args);
>> ++    warn_reportf_errp(errp, args);
>> +)
>> +?-    local_err = NULL;
>> +
>> +|
>> +-    error_propagate_prepend(errp, local_err, args);
>> ++    error_prepend(errp, args);
>> +|
>> +-    error_propagate(errp, local_err);
>> +|
>> +-    &local_err
>> ++    errp
>> +)
>> +     ...>
>> + }
>> +
>> +// Convert remaining local_err usage. For example, different kinds of
>> +// error checking in if conditionals. We can't merge this into
>> +// previous hunk, as this conflicts with other substitutions in it (at
>> +// least with "- local_err = NULL").
>> +@ disable optional_qualifier@
>> +identifier rule1.fn, rule1.local_err;
>> +symbol errp;
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     <...
>> +-    local_err
>> ++    *errp
>> +     ...>
>> + }
>> +
>> +// Always use the same pattern for checking error
>> +@ disable optional_qualifier@
>> +identifier rule1.fn;
>> +symbol errp;
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     <...
>> +-    *errp != NULL
>> ++    *errp
>> +     ...>
>> + }
>> +
>> +// Revert temporary ___ identifier.
>> +@ disable optional_qualifier@
>> +identifier rule1.fn;
>> +@@
>> +
>> + fn(..., Error **
>> +-   ____
>> ++   errp
>> +    , ...)
>> + {
>> +     ...
>> + }
>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>> index 30140d9bfe..56c133520d 100644
>> --- a/include/qapi/error.h
>> +++ b/include/qapi/error.h
>> @@ -214,6 +214,9 @@
>>    *         }
>>    *         ...
>>    *     }
>> + *
>> + * For mass-conversion use script
>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>    */
>>   
>>   #ifndef ERROR_H
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 857f969aa1..047f1b9714 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>   F: qapi/error.json
>>   F: util/error.c
>>   F: util/qemu-error.c
>> +F: scripts/coccinelle/*err*.cocci
>>   
>>   GDB stub
>>   M: Alex Bennée <alex.bennee@linaro.org>
> 


-- 
Best regards,
Vladimir

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 00/10] error: auto propagated local_err part I
  2020-03-12 14:24   ` [Xen-devel] " Markus Armbruster
@ 2020-03-13  6:40     ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-13  6:40 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

12.03.2020 17:24, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> v9
>> 01: A lot of rewordings [thanks to Eric]
>>      Still, keep all r-b marks, assuming that they are mostly about macro definition
>> 02: significant changes are:
>>      1. Do not match double propagation pattern in ERRP_AUTO_PROPAGATE-adding rule
>>      2. Introduce errp->____->errp scheme to match only functions matched by rule1
>>         in rules inherited from rule1
>>      3. Add rules to warn about unusual patterns
>>
>>      Also, add line to MAINTAINERS to keep error related coccinelle scripts under
>>      Error section.
>> 07: add Christian's r-b
>> 09: add Eric's r-b
>> 10: a bit of context in xen_block_iothread_create  and qmp_object_add()
>>      signature are changed. Patch change is obvious, so I keep Paul's r-b
>>
>> v9 is available at
>>   https://src.openvz.org/scm/~vsementsov/qemu.git #tag up-auto-local-err-partI-v9
> 
> Did you forget to push the tag?

Seems I've pushed it to wrong remote. Done now.

> 
>> v8 is available at
>>   https://src.openvz.org/scm/~vsementsov/qemu.git #tag up-auto-local-err-partI-v8
> [...]
> 


-- 
Best regards,
Vladimir


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 00/10] error: auto propagated local_err part I
@ 2020-03-13  6:40     ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-13  6:40 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

12.03.2020 17:24, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> v9
>> 01: A lot of rewordings [thanks to Eric]
>>      Still, keep all r-b marks, assuming that they are mostly about macro definition
>> 02: significant changes are:
>>      1. Do not match double propagation pattern in ERRP_AUTO_PROPAGATE-adding rule
>>      2. Introduce errp->____->errp scheme to match only functions matched by rule1
>>         in rules inherited from rule1
>>      3. Add rules to warn about unusual patterns
>>
>>      Also, add line to MAINTAINERS to keep error related coccinelle scripts under
>>      Error section.
>> 07: add Christian's r-b
>> 09: add Eric's r-b
>> 10: a bit of context in xen_block_iothread_create  and qmp_object_add()
>>      signature are changed. Patch change is obvious, so I keep Paul's r-b
>>
>> v9 is available at
>>   https://src.openvz.org/scm/~vsementsov/qemu.git #tag up-auto-local-err-partI-v9
> 
> Did you forget to push the tag?

Seems I've pushed it to wrong remote. Done now.

> 
>> v8 is available at
>>   https://src.openvz.org/scm/~vsementsov/qemu.git #tag up-auto-local-err-partI-v8
> [...]
> 


-- 
Best regards,
Vladimir

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-12  8:59   ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-13  7:50     ` Markus Armbruster
  -1 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-13  7:50 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

[...]
> +// Warn several Error * definitions.
> +@check1 disable optional_qualifier exists@
> +identifier fn = rule1.fn, local_err, local_err2;
> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     ...
> +     Error *local_err = NULL;
> +     ... when any
> +     Error *local_err2 = NULL;
> +     ... when any
> + }
> +
> +@ script:python @
> +fn << check1.fn;
> +@@
> +
> +print('Warning: function {} has several definitions of '
> +      'Error * local variable'.format(fn))

Printing the positions like you do in the next rule is useful when
examining these warnings.

> +
> +// Warn several propagations in control flow.
> +@check2 disable optional_qualifier exists@
> +identifier fn = rule1.fn;
> +symbol errp;
> +position p1, p2;
> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     ...
> +(
> +     error_propagate_prepend(errp, ...);@p1
> +|
> +     error_propagate(errp, ...);@p1
> +)
> +     ...
> +(
> +     error_propagate_prepend(errp, ...);@p2
> +|
> +     error_propagate(errp, ...);@p2
> +)
> +     ... when any
> + }
> +
> +@ script:python @
> +fn << check2.fn;
> +p1 << check2.p1;
> +p2 << check2.p2;
> +@@
> +
> +print('Warning: function {} propagates to errp several times in '
> +      'one control flow: at {}:{} and then at {}:{}'.format(
> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
[...]



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-13  7:50     ` Markus Armbruster
  0 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-13  7:50 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

[...]
> +// Warn several Error * definitions.
> +@check1 disable optional_qualifier exists@
> +identifier fn = rule1.fn, local_err, local_err2;
> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     ...
> +     Error *local_err = NULL;
> +     ... when any
> +     Error *local_err2 = NULL;
> +     ... when any
> + }
> +
> +@ script:python @
> +fn << check1.fn;
> +@@
> +
> +print('Warning: function {} has several definitions of '
> +      'Error * local variable'.format(fn))

Printing the positions like you do in the next rule is useful when
examining these warnings.

> +
> +// Warn several propagations in control flow.
> +@check2 disable optional_qualifier exists@
> +identifier fn = rule1.fn;
> +symbol errp;
> +position p1, p2;
> +@@
> +
> + fn(..., Error ** ____, ...)
> + {
> +     ...
> +(
> +     error_propagate_prepend(errp, ...);@p1
> +|
> +     error_propagate(errp, ...);@p1
> +)
> +     ...
> +(
> +     error_propagate_prepend(errp, ...);@p2
> +|
> +     error_propagate(errp, ...);@p2
> +)
> +     ... when any
> + }
> +
> +@ script:python @
> +fn << check2.fn;
> +p1 << check2.p1;
> +p2 << check2.p2;
> +@@
> +
> +print('Warning: function {} propagates to errp several times in '
> +      'one control flow: at {}:{} and then at {}:{}'.format(
> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
[...]


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-13  7:50     ` [Xen-devel] " Markus Armbruster
@ 2020-03-13  8:06       ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-13  8:06 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

13.03.2020 10:50, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
> [...]
>> +// Warn several Error * definitions.
>> +@check1 disable optional_qualifier exists@
>> +identifier fn = rule1.fn, local_err, local_err2;
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     ...
>> +     Error *local_err = NULL;
>> +     ... when any
>> +     Error *local_err2 = NULL;
>> +     ... when any
>> + }
>> +
>> +@ script:python @
>> +fn << check1.fn;
>> +@@
>> +
>> +print('Warning: function {} has several definitions of '
>> +      'Error * local variable'.format(fn))
> 
> Printing the positions like you do in the next rule is useful when
> examining these warnings.

I decided that searching for Error * definition is simple, and better for
user to search all definitions by hand (may be more than too).

But understanding control flows is more complex thing and better to help
user with line positions.

But if you want, we can add them of course. Note, that for some reasons some
times coccinelle instead of original filename prints something like /tmp/...original-name...
so it don't look nice and may be a bit misleading.

> 
>> +
>> +// Warn several propagations in control flow.
>> +@check2 disable optional_qualifier exists@
>> +identifier fn = rule1.fn;
>> +symbol errp;
>> +position p1, p2;
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     ...
>> +(
>> +     error_propagate_prepend(errp, ...);@p1
>> +|
>> +     error_propagate(errp, ...);@p1
>> +)
>> +     ...
>> +(
>> +     error_propagate_prepend(errp, ...);@p2
>> +|
>> +     error_propagate(errp, ...);@p2
>> +)
>> +     ... when any
>> + }
>> +
>> +@ script:python @
>> +fn << check2.fn;
>> +p1 << check2.p1;
>> +p2 << check2.p2;
>> +@@
>> +
>> +print('Warning: function {} propagates to errp several times in '
>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> [...]
> 


-- 
Best regards,
Vladimir


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-13  8:06       ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-13  8:06 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

13.03.2020 10:50, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
> [...]
>> +// Warn several Error * definitions.
>> +@check1 disable optional_qualifier exists@
>> +identifier fn = rule1.fn, local_err, local_err2;
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     ...
>> +     Error *local_err = NULL;
>> +     ... when any
>> +     Error *local_err2 = NULL;
>> +     ... when any
>> + }
>> +
>> +@ script:python @
>> +fn << check1.fn;
>> +@@
>> +
>> +print('Warning: function {} has several definitions of '
>> +      'Error * local variable'.format(fn))
> 
> Printing the positions like you do in the next rule is useful when
> examining these warnings.

I decided that searching for Error * definition is simple, and better for
user to search all definitions by hand (may be more than too).

But understanding control flows is more complex thing and better to help
user with line positions.

But if you want, we can add them of course. Note, that for some reasons some
times coccinelle instead of original filename prints something like /tmp/...original-name...
so it don't look nice and may be a bit misleading.

> 
>> +
>> +// Warn several propagations in control flow.
>> +@check2 disable optional_qualifier exists@
>> +identifier fn = rule1.fn;
>> +symbol errp;
>> +position p1, p2;
>> +@@
>> +
>> + fn(..., Error ** ____, ...)
>> + {
>> +     ...
>> +(
>> +     error_propagate_prepend(errp, ...);@p1
>> +|
>> +     error_propagate(errp, ...);@p1
>> +)
>> +     ...
>> +(
>> +     error_propagate_prepend(errp, ...);@p2
>> +|
>> +     error_propagate(errp, ...);@p2
>> +)
>> +     ... when any
>> + }
>> +
>> +@ script:python @
>> +fn << check2.fn;
>> +p1 << check2.p1;
>> +p2 << check2.p2;
>> +@@
>> +
>> +print('Warning: function {} propagates to errp several times in '
>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> [...]
> 


-- 
Best regards,
Vladimir

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-12  8:59   ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-13 14:58     ` Markus Armbruster
  -1 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-13 14:58 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	armbru, Stefan Berger

I tried this script on the whole tree.  Observations:

* $ git-diff --shortstat \*.[ch]
   333 files changed, 3480 insertions(+), 4586 deletions(-)

* Twelve functions have "several definitions of Error * local variable".

  Eight declare such a variable within a loop.  Reported because
  Coccinelle matches along control flow, not just along text.  Ignore.

  Remaining four:

  * ivshmem_common_realize()

    Two variables (messed up in commit fe44dc91807), should be replaced
    by one.

  * qmp_query_cpu_model_expansion() two times

    Three declarations in separate blocks; two should be replaced by
    &error_abort, one moved to the function block.

  * xen_block_device_destroy()

    Two declarations in seperate blocks; should be replaced by a single
    one.

  Separate manual cleanup patches, ideally applied before running
  Coccinelle to keep Coccinelle's changes as simple and safe as
  possible.  I'll post patches.  Only the one for
  xen_block_device_destroy() affects by this series.

* No function "propagates to errp several times"

  I tested the rule does detect this as advertized by feeding it an
  obvious example.  We're good.

* ERRP_AUTO_PROPAGATE() inserted 744 times, always right at the
  beginning of a function.

* As far as I can tell, all changed functions have ERRP_AUTO_PROPAGATE()
  inserted.  Good.

* Almost 1100 error propagations dropped:error_propagate() removed,
  error_propagate_prepend() replaced by just error_prepend().

* Four error_propagate() are transformed.  Two instances each in
  aspeed_soc_ast2600_realize() and aspeed_soc_realize().  Pattern:

     {
    +    ERRP_AUTO_PROPAGATE();
         ...
    -    Error *err = NULL, *local_err = NULL;
    +    Error *local_err = NULL;
         ...

             object_property_set_T(..., 
    -                              &err);
    +                              errp);
             object_property_set_T(...,
                                   &local_err);
    -        error_propagate(&err, local_err);
    -        if (err) {
    -            error_propagate(errp, err);
    +        error_propagate(errp, local_err);
    +        if (*errp) {
                 return;
             }

  This is what error.h calls "Receive and accumulate multiple errors
  (first one wins)".

  Result:

        ERRP_AUTO_PROPAGATE();
        ...
        Error *local_err = NULL;
        ...

            object_property_set_T(..., errp);
            object_property_set_T(..., &local_err);
            error_propagate(errp, local_err);
            if (*errp) {
                return;
            }

  Could be done without the accumulation:

        ERRP_AUTO_PROPAGATE();
        ...

            object_property_set_T(..., errp);
            if (*errp) {
                return;
            }
            object_property_set_T(..., errp);
            if (*errp) {
                return;
            }

  I find this a bit easier to understand.  Matter of taste.  If we want
  to change to this, do it manually and separately.  I'd do it on top.

* Some 90 propagations remain.

  Some of them could use cleanup, e.g. file_memory_backend_set_pmem(),
  css_clear_io_interrupt().  Out of scope for this series.

  Some move errors around in unusual ways, e.g. in block/nbd.c.  Could
  use review.  Out of scope for this series.

  I spotted three that should be transformed, but aren't:

  - qcrypto_block_luks_store_key()

    I believe g_autoptr() confuses Coccinelle.  Undermines all our
    Coccinelle use, not just this patch.  I think we need to update
    scripts/cocci-macro-file.h for it.

  - armsse_realize()

    Something in this huge function confuses Coccinelle, but I don't
    know what exactly.  If I delete most of it, the error_propagate()
    transforms okay.  If I delete less, Coccinelle hangs.

  - apply_cpu_model()

    Gets transformed fine if I remove the #ifndef CONFIG_USER_ONLY.  I
    have no idea why the #if spooks Coccinelle here, but not elsewhere.

  None of these three affects this series.  No need to hold it back for
  further investigation.

* 30 error_free() and two warn_reportf_err() are transformed.  Patterns:

    -    error_free(local_err);
    -    local_err = NULL;
    +    error_free_errp(errp);

  and

    -    error_free(local_err);
    +    error_free_errp(errp);

  and

    -    warn_report_err(local_err);
    -    local_err = NULL;
    +    warn_report_errp(errp);

  Good.

* Many error_free(), error_reportf_err() and warn_reportf_err() remain.
  None of them have an argument of the form *errp.  Such arguments would
  have to be reviewed for possible interference with
  ERRP_AUTO_PROPAGATE().

* Almost 700 Error *err = NULL removed.  Almost 600 remain.

* Error usage in rdma.c is questionable / wrong.  Out of scope for this
  series.

As far as I can tell, your Coccinelle script is working as intended,
except for three missed error propagations noted above.  We can proceed
with this series regardless, if we want.  I'd prefer to integrate my
forthcoming cleanup to xen_block_device_destroy(), though.



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-13 14:58     ` Markus Armbruster
  0 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-13 14:58 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	armbru, Stefan Berger

I tried this script on the whole tree.  Observations:

* $ git-diff --shortstat \*.[ch]
   333 files changed, 3480 insertions(+), 4586 deletions(-)

* Twelve functions have "several definitions of Error * local variable".

  Eight declare such a variable within a loop.  Reported because
  Coccinelle matches along control flow, not just along text.  Ignore.

  Remaining four:

  * ivshmem_common_realize()

    Two variables (messed up in commit fe44dc91807), should be replaced
    by one.

  * qmp_query_cpu_model_expansion() two times

    Three declarations in separate blocks; two should be replaced by
    &error_abort, one moved to the function block.

  * xen_block_device_destroy()

    Two declarations in seperate blocks; should be replaced by a single
    one.

  Separate manual cleanup patches, ideally applied before running
  Coccinelle to keep Coccinelle's changes as simple and safe as
  possible.  I'll post patches.  Only the one for
  xen_block_device_destroy() affects by this series.

* No function "propagates to errp several times"

  I tested the rule does detect this as advertized by feeding it an
  obvious example.  We're good.

* ERRP_AUTO_PROPAGATE() inserted 744 times, always right at the
  beginning of a function.

* As far as I can tell, all changed functions have ERRP_AUTO_PROPAGATE()
  inserted.  Good.

* Almost 1100 error propagations dropped:error_propagate() removed,
  error_propagate_prepend() replaced by just error_prepend().

* Four error_propagate() are transformed.  Two instances each in
  aspeed_soc_ast2600_realize() and aspeed_soc_realize().  Pattern:

     {
    +    ERRP_AUTO_PROPAGATE();
         ...
    -    Error *err = NULL, *local_err = NULL;
    +    Error *local_err = NULL;
         ...

             object_property_set_T(..., 
    -                              &err);
    +                              errp);
             object_property_set_T(...,
                                   &local_err);
    -        error_propagate(&err, local_err);
    -        if (err) {
    -            error_propagate(errp, err);
    +        error_propagate(errp, local_err);
    +        if (*errp) {
                 return;
             }

  This is what error.h calls "Receive and accumulate multiple errors
  (first one wins)".

  Result:

        ERRP_AUTO_PROPAGATE();
        ...
        Error *local_err = NULL;
        ...

            object_property_set_T(..., errp);
            object_property_set_T(..., &local_err);
            error_propagate(errp, local_err);
            if (*errp) {
                return;
            }

  Could be done without the accumulation:

        ERRP_AUTO_PROPAGATE();
        ...

            object_property_set_T(..., errp);
            if (*errp) {
                return;
            }
            object_property_set_T(..., errp);
            if (*errp) {
                return;
            }

  I find this a bit easier to understand.  Matter of taste.  If we want
  to change to this, do it manually and separately.  I'd do it on top.

* Some 90 propagations remain.

  Some of them could use cleanup, e.g. file_memory_backend_set_pmem(),
  css_clear_io_interrupt().  Out of scope for this series.

  Some move errors around in unusual ways, e.g. in block/nbd.c.  Could
  use review.  Out of scope for this series.

  I spotted three that should be transformed, but aren't:

  - qcrypto_block_luks_store_key()

    I believe g_autoptr() confuses Coccinelle.  Undermines all our
    Coccinelle use, not just this patch.  I think we need to update
    scripts/cocci-macro-file.h for it.

  - armsse_realize()

    Something in this huge function confuses Coccinelle, but I don't
    know what exactly.  If I delete most of it, the error_propagate()
    transforms okay.  If I delete less, Coccinelle hangs.

  - apply_cpu_model()

    Gets transformed fine if I remove the #ifndef CONFIG_USER_ONLY.  I
    have no idea why the #if spooks Coccinelle here, but not elsewhere.

  None of these three affects this series.  No need to hold it back for
  further investigation.

* 30 error_free() and two warn_reportf_err() are transformed.  Patterns:

    -    error_free(local_err);
    -    local_err = NULL;
    +    error_free_errp(errp);

  and

    -    error_free(local_err);
    +    error_free_errp(errp);

  and

    -    warn_report_err(local_err);
    -    local_err = NULL;
    +    warn_report_errp(errp);

  Good.

* Many error_free(), error_reportf_err() and warn_reportf_err() remain.
  None of them have an argument of the form *errp.  Such arguments would
  have to be reviewed for possible interference with
  ERRP_AUTO_PROPAGATE().

* Almost 700 Error *err = NULL removed.  Almost 600 remain.

* Error usage in rdma.c is questionable / wrong.  Out of scope for this
  series.

As far as I can tell, your Coccinelle script is working as intended,
except for three missed error propagations noted above.  We can proceed
with this series regardless, if we want.  I'd prefer to integrate my
forthcoming cleanup to xen_block_device_destroy(), though.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-13 14:58     ` [Xen-devel] " Markus Armbruster
@ 2020-03-13 15:22       ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-13 15:22 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

13.03.2020 17:58, Markus Armbruster wrote:
> I tried this script on the whole tree.  Observations:
> 
> * $ git-diff --shortstat \*.[ch]
>     333 files changed, 3480 insertions(+), 4586 deletions(-)
> 
> * Twelve functions have "several definitions of Error * local variable".
> 
>    Eight declare such a variable within a loop.  Reported because
>    Coccinelle matches along control flow, not just along text.  Ignore.
> 
>    Remaining four:
> 
>    * ivshmem_common_realize()
> 
>      Two variables (messed up in commit fe44dc91807), should be replaced
>      by one.
> 
>    * qmp_query_cpu_model_expansion() two times
> 
>      Three declarations in separate blocks; two should be replaced by
>      &error_abort, one moved to the function block.
> 
>    * xen_block_device_destroy()
> 
>      Two declarations in seperate blocks; should be replaced by a single
>      one.
> 
>    Separate manual cleanup patches, ideally applied before running
>    Coccinelle to keep Coccinelle's changes as simple and safe as
>    possible.  I'll post patches.  Only the one for
>    xen_block_device_destroy() affects by this series.
> 
> * No function "propagates to errp several times"
> 
>    I tested the rule does detect this as advertized by feeding it an
>    obvious example.  We're good.
> 
> * ERRP_AUTO_PROPAGATE() inserted 744 times, always right at the
>    beginning of a function.
> 
> * As far as I can tell, all changed functions have ERRP_AUTO_PROPAGATE()
>    inserted.  Good.
> 
> * Almost 1100 error propagations dropped:error_propagate() removed,
>    error_propagate_prepend() replaced by just error_prepend().
> 
> * Four error_propagate() are transformed.  Two instances each in
>    aspeed_soc_ast2600_realize() and aspeed_soc_realize().  Pattern:
> 
>       {
>      +    ERRP_AUTO_PROPAGATE();
>           ...
>      -    Error *err = NULL, *local_err = NULL;
>      +    Error *local_err = NULL;
>           ...
> 
>               object_property_set_T(...,
>      -                              &err);
>      +                              errp);
>               object_property_set_T(...,
>                                     &local_err);
>      -        error_propagate(&err, local_err);
>      -        if (err) {
>      -            error_propagate(errp, err);
>      +        error_propagate(errp, local_err);
>      +        if (*errp) {
>                   return;
>               }
> 
>    This is what error.h calls "Receive and accumulate multiple errors
>    (first one wins)".
> 
>    Result:
> 
>          ERRP_AUTO_PROPAGATE();
>          ...
>          Error *local_err = NULL;
>          ...
> 
>              object_property_set_T(..., errp);
>              object_property_set_T(..., &local_err);
>              error_propagate(errp, local_err);
>              if (*errp) {
>                  return;
>              }
> 
>    Could be done without the accumulation:
> 
>          ERRP_AUTO_PROPAGATE();
>          ...
> 
>              object_property_set_T(..., errp);
>              if (*errp) {
>                  return;
>              }
>              object_property_set_T(..., errp);
>              if (*errp) {
>                  return;
>              }
> 
>    I find this a bit easier to understand.  Matter of taste.  If we want
>    to change to this, do it manually and separately.  I'd do it on top.
> 
> * Some 90 propagations remain.
> 
>    Some of them could use cleanup, e.g. file_memory_backend_set_pmem(),
>    css_clear_io_interrupt().  Out of scope for this series.
> 
>    Some move errors around in unusual ways, e.g. in block/nbd.c.  Could
>    use review.  Out of scope for this series.
> 
>    I spotted three that should be transformed, but aren't:
> 
>    - qcrypto_block_luks_store_key()
> 
>      I believe g_autoptr() confuses Coccinelle.  Undermines all our
>      Coccinelle use, not just this patch.  I think we need to update
>      scripts/cocci-macro-file.h for it.
> 
>    - armsse_realize()
> 
>      Something in this huge function confuses Coccinelle, but I don't
>      know what exactly.  If I delete most of it, the error_propagate()
>      transforms okay.  If I delete less, Coccinelle hangs.
> 
>    - apply_cpu_model()
> 
>      Gets transformed fine if I remove the #ifndef CONFIG_USER_ONLY.  I
>      have no idea why the #if spooks Coccinelle here, but not elsewhere.
> 
>    None of these three affects this series.  No need to hold it back for
>    further investigation.
> 
> * 30 error_free() and two warn_reportf_err() are transformed.  Patterns:
> 
>      -    error_free(local_err);
>      -    local_err = NULL;
>      +    error_free_errp(errp);
> 
>    and
> 
>      -    error_free(local_err);
>      +    error_free_errp(errp);
> 
>    and
> 
>      -    warn_report_err(local_err);
>      -    local_err = NULL;
>      +    warn_report_errp(errp);
> 
>    Good.
> 
> * Many error_free(), error_reportf_err() and warn_reportf_err() remain.
>    None of them have an argument of the form *errp.  Such arguments would
>    have to be reviewed for possible interference with
>    ERRP_AUTO_PROPAGATE().
> 
> * Almost 700 Error *err = NULL removed.  Almost 600 remain.
> 
> * Error usage in rdma.c is questionable / wrong.  Out of scope for this
>    series.
> 
> As far as I can tell, your Coccinelle script is working as intended,
> except for three missed error propagations noted above.  We can proceed
> with this series regardless, if we want.  I'd prefer to integrate my
> forthcoming cleanup to xen_block_device_destroy(), though.
> 

Great investigation!!!

I'm for proceeding as is, or with your cleanup for xen_block_device_destroy().
Still, script converts xen_block_device_destroy correctly anyway, resulting code
will be the same and we are OK without cleanup as well.

-- 
Best regards,
Vladimir


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-13 15:22       ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-13 15:22 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, Michael Roth, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

13.03.2020 17:58, Markus Armbruster wrote:
> I tried this script on the whole tree.  Observations:
> 
> * $ git-diff --shortstat \*.[ch]
>     333 files changed, 3480 insertions(+), 4586 deletions(-)
> 
> * Twelve functions have "several definitions of Error * local variable".
> 
>    Eight declare such a variable within a loop.  Reported because
>    Coccinelle matches along control flow, not just along text.  Ignore.
> 
>    Remaining four:
> 
>    * ivshmem_common_realize()
> 
>      Two variables (messed up in commit fe44dc91807), should be replaced
>      by one.
> 
>    * qmp_query_cpu_model_expansion() two times
> 
>      Three declarations in separate blocks; two should be replaced by
>      &error_abort, one moved to the function block.
> 
>    * xen_block_device_destroy()
> 
>      Two declarations in seperate blocks; should be replaced by a single
>      one.
> 
>    Separate manual cleanup patches, ideally applied before running
>    Coccinelle to keep Coccinelle's changes as simple and safe as
>    possible.  I'll post patches.  Only the one for
>    xen_block_device_destroy() affects by this series.
> 
> * No function "propagates to errp several times"
> 
>    I tested the rule does detect this as advertized by feeding it an
>    obvious example.  We're good.
> 
> * ERRP_AUTO_PROPAGATE() inserted 744 times, always right at the
>    beginning of a function.
> 
> * As far as I can tell, all changed functions have ERRP_AUTO_PROPAGATE()
>    inserted.  Good.
> 
> * Almost 1100 error propagations dropped:error_propagate() removed,
>    error_propagate_prepend() replaced by just error_prepend().
> 
> * Four error_propagate() are transformed.  Two instances each in
>    aspeed_soc_ast2600_realize() and aspeed_soc_realize().  Pattern:
> 
>       {
>      +    ERRP_AUTO_PROPAGATE();
>           ...
>      -    Error *err = NULL, *local_err = NULL;
>      +    Error *local_err = NULL;
>           ...
> 
>               object_property_set_T(...,
>      -                              &err);
>      +                              errp);
>               object_property_set_T(...,
>                                     &local_err);
>      -        error_propagate(&err, local_err);
>      -        if (err) {
>      -            error_propagate(errp, err);
>      +        error_propagate(errp, local_err);
>      +        if (*errp) {
>                   return;
>               }
> 
>    This is what error.h calls "Receive and accumulate multiple errors
>    (first one wins)".
> 
>    Result:
> 
>          ERRP_AUTO_PROPAGATE();
>          ...
>          Error *local_err = NULL;
>          ...
> 
>              object_property_set_T(..., errp);
>              object_property_set_T(..., &local_err);
>              error_propagate(errp, local_err);
>              if (*errp) {
>                  return;
>              }
> 
>    Could be done without the accumulation:
> 
>          ERRP_AUTO_PROPAGATE();
>          ...
> 
>              object_property_set_T(..., errp);
>              if (*errp) {
>                  return;
>              }
>              object_property_set_T(..., errp);
>              if (*errp) {
>                  return;
>              }
> 
>    I find this a bit easier to understand.  Matter of taste.  If we want
>    to change to this, do it manually and separately.  I'd do it on top.
> 
> * Some 90 propagations remain.
> 
>    Some of them could use cleanup, e.g. file_memory_backend_set_pmem(),
>    css_clear_io_interrupt().  Out of scope for this series.
> 
>    Some move errors around in unusual ways, e.g. in block/nbd.c.  Could
>    use review.  Out of scope for this series.
> 
>    I spotted three that should be transformed, but aren't:
> 
>    - qcrypto_block_luks_store_key()
> 
>      I believe g_autoptr() confuses Coccinelle.  Undermines all our
>      Coccinelle use, not just this patch.  I think we need to update
>      scripts/cocci-macro-file.h for it.
> 
>    - armsse_realize()
> 
>      Something in this huge function confuses Coccinelle, but I don't
>      know what exactly.  If I delete most of it, the error_propagate()
>      transforms okay.  If I delete less, Coccinelle hangs.
> 
>    - apply_cpu_model()
> 
>      Gets transformed fine if I remove the #ifndef CONFIG_USER_ONLY.  I
>      have no idea why the #if spooks Coccinelle here, but not elsewhere.
> 
>    None of these three affects this series.  No need to hold it back for
>    further investigation.
> 
> * 30 error_free() and two warn_reportf_err() are transformed.  Patterns:
> 
>      -    error_free(local_err);
>      -    local_err = NULL;
>      +    error_free_errp(errp);
> 
>    and
> 
>      -    error_free(local_err);
>      +    error_free_errp(errp);
> 
>    and
> 
>      -    warn_report_err(local_err);
>      -    local_err = NULL;
>      +    warn_report_errp(errp);
> 
>    Good.
> 
> * Many error_free(), error_reportf_err() and warn_reportf_err() remain.
>    None of them have an argument of the form *errp.  Such arguments would
>    have to be reviewed for possible interference with
>    ERRP_AUTO_PROPAGATE().
> 
> * Almost 700 Error *err = NULL removed.  Almost 600 remain.
> 
> * Error usage in rdma.c is questionable / wrong.  Out of scope for this
>    series.
> 
> As far as I can tell, your Coccinelle script is working as intended,
> except for three missed error propagations noted above.  We can proceed
> with this series regardless, if we want.  I'd prefer to integrate my
> forthcoming cleanup to xen_block_device_destroy(), though.
> 

Great investigation!!!

I'm for proceeding as is, or with your cleanup for xen_block_device_destroy().
Still, script converts xen_block_device_destroy correctly anyway, resulting code
will be the same and we are OK without cleanup as well.

-- 
Best regards,
Vladimir

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-13  8:06       ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-13 15:34         ` Markus Armbruster
  -1 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-13 15:34 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 13.03.2020 10:50, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>
>> [...]
>>> +// Warn several Error * definitions.
>>> +@check1 disable optional_qualifier exists@
>>> +identifier fn = rule1.fn, local_err, local_err2;
>>> +@@
>>> +
>>> + fn(..., Error ** ____, ...)
>>> + {
>>> +     ...
>>> +     Error *local_err = NULL;
>>> +     ... when any
>>> +     Error *local_err2 = NULL;
>>> +     ... when any
>>> + }
>>> +
>>> +@ script:python @
>>> +fn << check1.fn;
>>> +@@
>>> +
>>> +print('Warning: function {} has several definitions of '
>>> +      'Error * local variable'.format(fn))
>>
>> Printing the positions like you do in the next rule is useful when
>> examining these warnings.
>
> I decided that searching for Error * definition is simple, and better for
> user to search all definitions by hand (may be more than too).
>
> But understanding control flows is more complex thing and better to help
> user with line positions.
>
> But if you want, we can add them of course. Note, that for some reasons some
> times coccinelle instead of original filename prints something like /tmp/...original-name...
> so it don't look nice and may be a bit misleading.

I noticed when I actually tried mu idea %-}



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-13 15:34         ` Markus Armbruster
  0 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-13 15:34 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 13.03.2020 10:50, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>
>> [...]
>>> +// Warn several Error * definitions.
>>> +@check1 disable optional_qualifier exists@
>>> +identifier fn = rule1.fn, local_err, local_err2;
>>> +@@
>>> +
>>> + fn(..., Error ** ____, ...)
>>> + {
>>> +     ...
>>> +     Error *local_err = NULL;
>>> +     ... when any
>>> +     Error *local_err2 = NULL;
>>> +     ... when any
>>> + }
>>> +
>>> +@ script:python @
>>> +fn << check1.fn;
>>> +@@
>>> +
>>> +print('Warning: function {} has several definitions of '
>>> +      'Error * local variable'.format(fn))
>>
>> Printing the positions like you do in the next rule is useful when
>> examining these warnings.
>
> I decided that searching for Error * definition is simple, and better for
> user to search all definitions by hand (may be more than too).
>
> But understanding control flows is more complex thing and better to help
> user with line positions.
>
> But if you want, we can add them of course. Note, that for some reasons some
> times coccinelle instead of original filename prints something like /tmp/...original-name...
> so it don't look nice and may be a bit misleading.

I noticed when I actually tried mu idea %-}


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-13  6:38       ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-13 15:42         ` Markus Armbruster
  -1 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-13 15:42 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 12.03.2020 19:36, Markus Armbruster wrote:
>> I may have a second look tomorrow with fresher eyes, but let's get this
>> out now as is.
>>
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>
>>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>>> does corresponding changes in code (look for details in
>>> include/qapi/error.h)
>>>
>>> Usage example:
>>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>   --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>>   --max-width 80 FILES...
>>>
>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>> ---
>>>
>>> Cc: Eric Blake <eblake@redhat.com>
>>> Cc: Kevin Wolf <kwolf@redhat.com>
>>> Cc: Max Reitz <mreitz@redhat.com>
>>> Cc: Greg Kurz <groug@kaod.org>
>>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>> Cc: Paul Durrant <paul@xen.org>
>>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>>> Cc: Markus Armbruster <armbru@redhat.com>
>>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>>> Cc: qemu-devel@nongnu.org
>>> Cc: qemu-block@nongnu.org
>>> Cc: xen-devel@lists.xenproject.org
>>>
>>>   scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>>   include/qapi/error.h                          |   3 +
>>>   MAINTAINERS                                   |   1 +
>>>   3 files changed, 331 insertions(+)
>>>   create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>>
>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>> new file mode 100644
>>> index 0000000000..7dac2dcfa4
>>> --- /dev/null
>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>> @@ -0,0 +1,327 @@
>>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>> +//
>>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>>> +//
>>> +// This program is free software; you can redistribute it and/or
>>> +// modify it under the terms of the GNU General Public License as
>>> +// published by the Free Software Foundation; either version 2 of the
>>> +// License, or (at your option) any later version.
>>> +//
>>> +// This program is distributed in the hope that it will be useful,
>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> +// GNU General Public License for more details.
>>> +//
>>> +// You should have received a copy of the GNU General Public License
>>> +// along with this program.  If not, see
>>> +// <http://www.gnu.org/licenses/>.
>>> +//
>>> +// Usage example:
>>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>>> +//  --no-show-diff --max-width 80 FILES...
>>> +//
>>> +// Note: --max-width 80 is needed because coccinelle default is less
>>> +// than 80, and without this parameter coccinelle may reindent some
>>> +// lines which fit into 80 characters but not to coccinelle default,
>>> +// which in turn produces extra patch hunks for no reason.
>>
>> This is about unwanted reformatting of parameter lists due to the ___
>> chaining hack.  --max-width 80 makes that less likely, but not
>> impossible.
>>
>> We can search for unwanted reformatting of parameter lists.  I think
>> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
>> tree, I get one false positive (not a parameter list), and one hit:
>>
>>      @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>>           }
>>       }
>>
>>      -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>>      +void object_apply_global_props(Object *obj, const GPtrArray *props,
>>      +                               Error **errp)
>>       {
>>      +    ERRP_AUTO_PROPAGATE();
>>           int i;
>>
>>           if (!props) {
>>
>> Reformatting, but not unwanted.
>
> Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
> ERRP_AUTO_PROPAGATE addition even for non-automatic patch.

Agree.

>>
>> The --max-width 80 hack is good enough for me.
>>
>> It does result in slightly long transformed lines, e.g. this one in
>> replication.c:
>>
>>      @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>>               s->mode = REPLICATION_MODE_PRIMARY;
>>               top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>>               if (top_id) {
>>      -            error_setg(&local_err, "The primary side does not support option top-id");
>>      +            error_setg(errp, "The primary side does not support option top-id");
>>                   goto fail;
>>               }
>>           } else if (!strcmp(mode, "secondary")) {
>>
>> v8 did break this line (that's how I found it).  However, v9 still
>> shortens the line, just not below the target.  All your + lines look
>> quite unlikely to lengthen lines.  Let's not worry about this.
>>
>>> +// Switch unusual Error ** parameter names to errp
>>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>>> +//
>>> +// Disable optional_qualifier to skip functions with
>>> +// "Error *const *errp" parameter.
>>> +//
>>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>>> +// that signals unusual semantics, and the parameter name may well
>>> +// serve a purpose. (like nbd_iter_channel_error()).
>>> +//
>>> +// Skip util/error.c to not touch, for example, error_propagate() and
>>> +// error_propagate_prepend().
>>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>>> +identifier fn;
>>> +identifier _errp != errp;
>>> +@@
>>> +
>>> + fn(...,
>>> +-   Error **_errp
>>> ++   Error **errp
>>> +    ,...)
>>> + {
>>> +(
>>> +     ... when != assert(_errp && *_errp)
>>> +&
>>> +     <...
>>> +-    _errp
>>> ++    errp
>>> +     ...>
>>> +)
>>> + }
>>> +
>>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>> +// necessary
>>> +//
>>> +// Note, that without "when any" the final "..." does not mach
>>> +// something matched by previous pattern, i.e. the rule will not match
>>> +// double error_prepend in control flow like in
>>> +// vfio_set_irq_signaling().
>>> +//
>>> +// Note, "exists" says that we want apply rule even if it matches not
>>> +// on all possible control flows (otherwise, it will not match
>>> +// standard pattern when error_propagate() call is in if branch).
>>> +@ disable optional_qualifier exists@
>>> +identifier fn, local_err;
>>> +symbol errp;
>>> +@@
>>> +
>>> + fn(..., Error **errp, ...)
>>> + {
>>> ++   ERRP_AUTO_PROPAGATE();
>>> +    ...  when != ERRP_AUTO_PROPAGATE();
>>> +(
>>> +(
>>> +    error_append_hint(errp, ...);
>>> +|
>>> +    error_prepend(errp, ...);
>>> +|
>>> +    error_vprepend(errp, ...);
>>> +)
>>> +    ... when any
>>> +|
>>> +    Error *local_err = NULL;
>>> +    ...
>>> +(
>>> +    error_propagate_prepend(errp, local_err, ...);
>>> +|
>>> +    error_propagate(errp, local_err);
>>> +)
>>> +    ...
>>> +)
>>> + }
>>> +
>>> +
>>> +// Match functions with propagation of local error to errp.
>>> +// We want to refer these functions in several following rules, but I
>>> +// don't know a proper way to inherit a function, not just its name
>>> +// (to not match another functions with same name in following rules).
>>> +// Not-proper way is as follows: rename errp parameter in functions
>>> +// header and match it in following rules. Rename it back after all
>>> +// transformations.
>>> +//
>>> +// The simplest case of propagation scheme is single definition of
>>> +// local_err with at most one error_propagate_prepend or
>>> +// error_propagate on each control-flow. Still, we want to match more
>>> +// complex schemes too. We'll warn them with help of further rules.
>>
>> I think what we actually want is to examine instances of this pattern to
>> figure out whether and how we want to transform them.  Perhaps:
>>
>>      // The common case is a single definition of local_err with at most one
>>      // error_propagate_prepend() or error_propagate() on each control-flow
>>      // path. Instances of this case we convert with this script. Functions
>
> For me, sounds a bit like "other things we don't convert".
> Actually we convert other things too.

What other patterns of error propagation do we convert?

>>      // with multiple definitions or propagates we want to examine
>>      // manually. Later rules emit warnings to guide us to them.
>>
>>> +@rule1 disable optional_qualifier exists@
>>> +identifier fn, local_err;
>>> +symbol errp;
>>> +@@
>>> +
>>> + fn(..., Error **
>>> +-    errp
>>> ++    ____
>>> +    , ...)
>>> + {
>>> +     ...
>>> +     Error *local_err = NULL;
>>> +     ...
>>> +(
>>> +     error_propagate_prepend(errp, local_err, ...);
>>> +|
>>> +     error_propagate(errp, local_err);
>>> +)
>>> +     ...
>>> + }
>>> +
>>> +
>>> +// Warn several Error * definitions.
>>> +@check1 disable optional_qualifier exists@
>>> +identifier fn = rule1.fn, local_err, local_err2;
>>
>> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
>> particular reason for the difference?
>
> I didn't find other way to ref check1.fn in next python rule. It just don't
> work if I write here just rule1.fn.
>
>>
>> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
>> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
>> everywhere, then apply the script to the complete tree, I get the same
>> result.
>
> I think, it's more efficient to reuse names from previous rules. I think it should
> work faster (more information, less extra matching).

Nope.  With my hacked up script (patch appended) Coccinelle is actually
*faster* for the .[ch] touched by this series: with your unmodified
script, it takes a bit over 12s on my box, with mine around 7s.  Output
is identical.

Never guess performance, always measure it :)

Two notes on my script:

* Unlike yours, it recognizes double-propagation in my test case.
  Discussed below.

* Its "several definitions of" warning includes positions.  That turned
  out to be useless, but I've been too lazy to take that out again.

>>
>>> +@@
>>> +
>>> + fn(..., Error ** ____, ...)
>>> + {
>>> +     ...
>>> +     Error *local_err = NULL;
>>> +     ... when any
>>> +     Error *local_err2 = NULL;
>>> +     ... when any
>>> + }
>>> +
>>> +@ script:python @
>>> +fn << check1.fn;
>>> +@@
>>> +
>>> +print('Warning: function {} has several definitions of '
>>> +      'Error * local variable'.format(fn))
>>> +
>>> +// Warn several propagations in control flow.
>>> +@check2 disable optional_qualifier exists@
>>> +identifier fn = rule1.fn;
>>> +symbol errp;
>>> +position p1, p2;
>>> +@@
>>> +
>>> + fn(..., Error ** ____, ...)
>>> + {
>>> +     ...
>>> +(
>>> +     error_propagate_prepend(errp, ...);@p1
>>> +|
>>> +     error_propagate(errp, ...);@p1
>>> +)
>>> +     ...
>>> +(
>>> +     error_propagate_prepend(errp, ...);@p2
>>> +|
>>> +     error_propagate(errp, ...);@p2
>>> +)
>>> +     ... when any
>>> + }
>>> +
>>
>> Hmm, we don't catch the example I used in review of v8:
>>
>>      extern foo(int, Error **);
>>      extern bar(int, Error **);
>>
>>      void frob(Error **errp)
>>      {
>>          Error *local_err = NULL;
>>          int arg;
>>
>>          foo(arg, errp);
>>          bar(arg, &local_err);
>>          error_propagate(errp, local_err);
>>          bar(arg + 1, &local_err);
>>          error_propagate(errp, local_err);
>>      }
>>
>> I believe this is because rule1 does not match here.
>
> Yes, rule1 wants at least one code flow with non-doubled propagation.
>
>>
>> If I change the rule as follows, it catches the example:
>>
>>      @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
>>
>>       // Warn several propagations in control flow.
>>       @check2 disable optional_qualifier exists@
>>      -identifier fn = rule1.fn;
>>      -symbol errp;
>>      +identifier fn, _errp;
>>       position p1, p2;
>>       @@
>>
>>      - fn(..., Error ** ____, ...)
>>      + fn(..., Error **_errp, ...)
>>        {
>>            ...
>>       (
>>      -     error_propagate_prepend(errp, ...);@p1
>>      +     error_propagate_prepend(_errp, ...);@p1
>>       |
>>      -     error_propagate(errp, ...);@p1
>>      +     error_propagate(_errp, ...);@p1
>>       )
>>            ...
>>       (
>>      -     error_propagate_prepend(errp, ...);@p2
>>      +     error_propagate_prepend(_errp, ...);@p2
>>       |
>>      -     error_propagate(errp, ...);@p2
>>      +     error_propagate(_errp, ...);@p2
>>       )
>>            ... when any
>>        }
>>
>> To my mild surprise, it still doesn't find anything in our tree.
>>
>> Should we decouple the previous rule from rule1, too?  I tested the
>> following on the whole tree:
>
> I don't think so. Why to check what we are not going to convert? If we want
> to check side things, it's better to do it in other coccinelle script..

Misunderstanding?  The rules are still chained together via the ___
hack, just not via function name, because that's unreliable and
redundant.

>>
>>      @@ -136,10 +136,10 @@ symbol errp;
>>
>>       // Warn several Error * definitions.
>>       @check1 disable optional_qualifier exists@
>>      -identifier fn = rule1.fn, local_err, local_err2;
>>      +identifier fn, _errp, local_err, local_err2;
>>       @@
>>
>>      - fn(..., Error ** ____, ...)
>>      + fn(..., Error **_errp, ...)
>>        {
>>            ...
>>            Error *local_err = NULL;
>>
>> Warnings remain unchanged.
>>
>>> +@ script:python @
>>> +fn << check2.fn;
>>> +p1 << check2.p1;
>>> +p2 << check2.p2;
>>> +@@
>>> +
>>> +print('Warning: function {} propagates to errp several times in '
>>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>> +
>>> +// Convert special case with goto separately.
>>> +// I tried merging this into the following rule the obvious way, but
>>> +// it made Coccinelle hang on block.c
>>> +//
>>> +// Note interesting thing: if we don't do it here, and try to fixup
>>> +// "out: }" things later after all transformations (the rule will be
>>> +// the same, just without error_propagate() call), coccinelle fails to
>>> +// match this "out: }".
>>> +@ disable optional_qualifier@
>>> +identifier rule1.fn, rule1.local_err, out;
>>
>> As explained above, I doubt the need for rule1.fn.  We do need
>> rule1.local_err to avoid unwanted transformations.  More of the same
>> below.
>
> Logically, I want to inherit from rule1. So why not to stress it by inheriting
> fn variable? It's just a correct thing to do.
> And I hope it helps coccinelle to work more efficiently.
>
>>
>>> +symbol errp;
>>> +@@
>>> +
>>> + fn(..., Error ** ____, ...)
>>> + {
>>> +     <...
>>> +-    goto out;
>>> ++    return;
>>> +     ...>
>>> +- out:
>>> +-    error_propagate(errp, local_err);
>>> + }
>>> +
>>> +// Convert most of local_err related stuff.
>>> +//
>>> +// Note, that we update everything related to matched by rule1
>>> +// function name and local_err name. We may match something not
>>> +// related to the pattern matched by rule1. For example, local_err may
>>> +// be defined with the same name in different blocks inside one
>>> +// function, and in one block follow the propagation pattern and in
>>> +// other block doesn't. Or we may have several functions with the same
>>> +// name (for different configurations).
>>> +//
>>> +// Note also that errp-cleaning functions
>>> +//   error_free_errp
>>> +//   error_report_errp
>>> +//   error_reportf_errp
>>> +//   warn_report_errp
>>> +//   warn_reportf_errp
>>> +// are not yet implemented. They must call corresponding Error* -
>>> +// freeing function and then set *errp to NULL, to avoid further
>>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>> +// For example, error_free_errp may look like this:
>>> +//
>>> +//    void error_free_errp(Error **errp)
>>> +//    {
>>> +//        error_free(*errp);
>>> +//        *errp = NULL;
>>> +//    }
>>> +@ disable optional_qualifier exists@
>>> +identifier rule1.fn, rule1.local_err;
>>> +expression list args;
>>> +symbol errp;
>>> +@@
>>> +
>>> + fn(..., Error ** ____, ...)
>>> + {
>>> +     <...
>>> +(
>>> +-    Error *local_err = NULL;
>>> +|
>>> +
>>> +// Convert error clearing functions
>>> +(
>>> +-    error_free(local_err);
>>> ++    error_free_errp(errp);
>>> +|
>>> +-    error_report_err(local_err);
>>> ++    error_report_errp(errp);
>>> +|
>>> +-    error_reportf_err(local_err, args);
>>> ++    error_reportf_errp(errp, args);
>>> +|
>>> +-    warn_report_err(local_err);
>>> ++    warn_report_errp(errp);
>>> +|
>>> +-    warn_reportf_err(local_err, args);
>>> ++    warn_reportf_errp(errp, args);
>>> +)
>>> +?-    local_err = NULL;
>>> +
>>> +|
>>> +-    error_propagate_prepend(errp, local_err, args);
>>> ++    error_prepend(errp, args);
>>> +|
>>> +-    error_propagate(errp, local_err);
>>> +|
>>> +-    &local_err
>>> ++    errp
>>> +)
>>> +     ...>
>>> + }
>>> +
>>> +// Convert remaining local_err usage. For example, different kinds of
>>> +// error checking in if conditionals. We can't merge this into
>>> +// previous hunk, as this conflicts with other substitutions in it (at
>>> +// least with "- local_err = NULL").
>>> +@ disable optional_qualifier@
>>> +identifier rule1.fn, rule1.local_err;
>>> +symbol errp;
>>> +@@
>>> +
>>> + fn(..., Error ** ____, ...)
>>> + {
>>> +     <...
>>> +-    local_err
>>> ++    *errp
>>> +     ...>
>>> + }
>>> +
>>> +// Always use the same pattern for checking error
>>> +@ disable optional_qualifier@
>>> +identifier rule1.fn;
>>> +symbol errp;
>>> +@@
>>> +
>>> + fn(..., Error ** ____, ...)
>>> + {
>>> +     <...
>>> +-    *errp != NULL
>>> ++    *errp
>>> +     ...>
>>> + }
>>> +
>>> +// Revert temporary ___ identifier.
>>> +@ disable optional_qualifier@
>>> +identifier rule1.fn;
>>> +@@
>>> +
>>> + fn(..., Error **
>>> +-   ____
>>> ++   errp
>>> +    , ...)
>>> + {
>>> +     ...
>>> + }
>>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>>> index 30140d9bfe..56c133520d 100644
>>> --- a/include/qapi/error.h
>>> +++ b/include/qapi/error.h
>>> @@ -214,6 +214,9 @@
>>>    *         }
>>>    *         ...
>>>    *     }
>>> + *
>>> + * For mass-conversion use script
>>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>>    */
>>>     #ifndef ERROR_H
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 857f969aa1..047f1b9714 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>>   F: qapi/error.json
>>>   F: util/error.c
>>>   F: util/qemu-error.c
>>> +F: scripts/coccinelle/*err*.cocci
>>>     GDB stub
>>>   M: Alex Bennée <alex.bennee@linaro.org>
>>


From 42a08c529024337d1b859839c9ce7f797f784555 Mon Sep 17 00:00:00 2001
From: Markus Armbruster <armbru@redhat.com>
Date: Fri, 13 Mar 2020 14:27:57 +0100
Subject: [PATCH] fixup! scripts: Coccinelle script to use
 ERRP_AUTO_PROPAGATE()

---
 scripts/coccinelle/auto-propagated-errp.cocci | 37 ++++++++++---------
 1 file changed, 20 insertions(+), 17 deletions(-)

diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
index 7dac2dcfa4..43b0b0e63b 100644
--- a/scripts/coccinelle/auto-propagated-errp.cocci
+++ b/scripts/coccinelle/auto-propagated-errp.cocci
@@ -136,45 +136,48 @@ symbol errp;
 
 // Warn several Error * definitions.
 @check1 disable optional_qualifier exists@
-identifier fn = rule1.fn, local_err, local_err2;
+identifier fn, _errp, local_err, local_err2;
+position p1, p2;
 @@
 
- fn(..., Error ** ____, ...)
+ fn(..., Error **_errp, ...)
  {
      ...
-     Error *local_err = NULL;
+     Error *local_err = NULL;@p1
      ... when any
-     Error *local_err2 = NULL;
+     Error *local_err2 = NULL;@p2
      ... when any
  }
 
 @ script:python @
 fn << check1.fn;
+p1 << check1.p1;
+p2 << check1.p2;
 @@
 
 print('Warning: function {} has several definitions of '
-      'Error * local variable'.format(fn))
+      'Error * local variable: at {}:{} and then at {}:{}'.format(
+          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
 
 // Warn several propagations in control flow.
 @check2 disable optional_qualifier exists@
-identifier fn = rule1.fn;
-symbol errp;
+identifier fn, _errp;
 position p1, p2;
 @@
 
- fn(..., Error ** ____, ...)
+ fn(..., Error **_errp, ...)
  {
      ...
 (
-     error_propagate_prepend(errp, ...);@p1
+     error_propagate_prepend(_errp, ...);@p1
 |
-     error_propagate(errp, ...);@p1
+     error_propagate(_errp, ...);@p1
 )
      ...
 (
-     error_propagate_prepend(errp, ...);@p2
+     error_propagate_prepend(_errp, ...);@p2
 |
-     error_propagate(errp, ...);@p2
+     error_propagate(_errp, ...);@p2
 )
      ... when any
  }
@@ -198,7 +201,7 @@ print('Warning: function {} propagates to errp several times in '
 // the same, just without error_propagate() call), coccinelle fails to
 // match this "out: }".
 @ disable optional_qualifier@
-identifier rule1.fn, rule1.local_err, out;
+identifier fn, rule1.local_err, out;
 symbol errp;
 @@
 
@@ -239,7 +242,7 @@ symbol errp;
 //        *errp = NULL;
 //    }
 @ disable optional_qualifier exists@
-identifier rule1.fn, rule1.local_err;
+identifier fn, rule1.local_err;
 expression list args;
 symbol errp;
 @@
@@ -287,7 +290,7 @@ symbol errp;
 // previous hunk, as this conflicts with other substitutions in it (at
 // least with "- local_err = NULL").
 @ disable optional_qualifier@
-identifier rule1.fn, rule1.local_err;
+identifier fn, rule1.local_err;
 symbol errp;
 @@
 
@@ -301,7 +304,7 @@ symbol errp;
 
 // Always use the same pattern for checking error
 @ disable optional_qualifier@
-identifier rule1.fn;
+identifier fn;
 symbol errp;
 @@
 
@@ -315,7 +318,7 @@ symbol errp;
 
 // Revert temporary ___ identifier.
 @ disable optional_qualifier@
-identifier rule1.fn;
+identifier fn;
 @@
 
  fn(..., Error **
-- 
2.21.1



^ permalink raw reply related	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-13 15:42         ` Markus Armbruster
  0 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-13 15:42 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 12.03.2020 19:36, Markus Armbruster wrote:
>> I may have a second look tomorrow with fresher eyes, but let's get this
>> out now as is.
>>
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>
>>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>>> does corresponding changes in code (look for details in
>>> include/qapi/error.h)
>>>
>>> Usage example:
>>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>   --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>>   --max-width 80 FILES...
>>>
>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>> ---
>>>
>>> Cc: Eric Blake <eblake@redhat.com>
>>> Cc: Kevin Wolf <kwolf@redhat.com>
>>> Cc: Max Reitz <mreitz@redhat.com>
>>> Cc: Greg Kurz <groug@kaod.org>
>>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>> Cc: Paul Durrant <paul@xen.org>
>>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>>> Cc: Markus Armbruster <armbru@redhat.com>
>>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>>> Cc: qemu-devel@nongnu.org
>>> Cc: qemu-block@nongnu.org
>>> Cc: xen-devel@lists.xenproject.org
>>>
>>>   scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>>   include/qapi/error.h                          |   3 +
>>>   MAINTAINERS                                   |   1 +
>>>   3 files changed, 331 insertions(+)
>>>   create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>>
>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>> new file mode 100644
>>> index 0000000000..7dac2dcfa4
>>> --- /dev/null
>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>> @@ -0,0 +1,327 @@
>>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>> +//
>>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>>> +//
>>> +// This program is free software; you can redistribute it and/or
>>> +// modify it under the terms of the GNU General Public License as
>>> +// published by the Free Software Foundation; either version 2 of the
>>> +// License, or (at your option) any later version.
>>> +//
>>> +// This program is distributed in the hope that it will be useful,
>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> +// GNU General Public License for more details.
>>> +//
>>> +// You should have received a copy of the GNU General Public License
>>> +// along with this program.  If not, see
>>> +// <http://www.gnu.org/licenses/>.
>>> +//
>>> +// Usage example:
>>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>>> +//  --no-show-diff --max-width 80 FILES...
>>> +//
>>> +// Note: --max-width 80 is needed because coccinelle default is less
>>> +// than 80, and without this parameter coccinelle may reindent some
>>> +// lines which fit into 80 characters but not to coccinelle default,
>>> +// which in turn produces extra patch hunks for no reason.
>>
>> This is about unwanted reformatting of parameter lists due to the ___
>> chaining hack.  --max-width 80 makes that less likely, but not
>> impossible.
>>
>> We can search for unwanted reformatting of parameter lists.  I think
>> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
>> tree, I get one false positive (not a parameter list), and one hit:
>>
>>      @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>>           }
>>       }
>>
>>      -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>>      +void object_apply_global_props(Object *obj, const GPtrArray *props,
>>      +                               Error **errp)
>>       {
>>      +    ERRP_AUTO_PROPAGATE();
>>           int i;
>>
>>           if (!props) {
>>
>> Reformatting, but not unwanted.
>
> Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
> ERRP_AUTO_PROPAGATE addition even for non-automatic patch.

Agree.

>>
>> The --max-width 80 hack is good enough for me.
>>
>> It does result in slightly long transformed lines, e.g. this one in
>> replication.c:
>>
>>      @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>>               s->mode = REPLICATION_MODE_PRIMARY;
>>               top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>>               if (top_id) {
>>      -            error_setg(&local_err, "The primary side does not support option top-id");
>>      +            error_setg(errp, "The primary side does not support option top-id");
>>                   goto fail;
>>               }
>>           } else if (!strcmp(mode, "secondary")) {
>>
>> v8 did break this line (that's how I found it).  However, v9 still
>> shortens the line, just not below the target.  All your + lines look
>> quite unlikely to lengthen lines.  Let's not worry about this.
>>
>>> +// Switch unusual Error ** parameter names to errp
>>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>>> +//
>>> +// Disable optional_qualifier to skip functions with
>>> +// "Error *const *errp" parameter.
>>> +//
>>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>>> +// that signals unusual semantics, and the parameter name may well
>>> +// serve a purpose. (like nbd_iter_channel_error()).
>>> +//
>>> +// Skip util/error.c to not touch, for example, error_propagate() and
>>> +// error_propagate_prepend().
>>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>>> +identifier fn;
>>> +identifier _errp != errp;
>>> +@@
>>> +
>>> + fn(...,
>>> +-   Error **_errp
>>> ++   Error **errp
>>> +    ,...)
>>> + {
>>> +(
>>> +     ... when != assert(_errp && *_errp)
>>> +&
>>> +     <...
>>> +-    _errp
>>> ++    errp
>>> +     ...>
>>> +)
>>> + }
>>> +
>>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>> +// necessary
>>> +//
>>> +// Note, that without "when any" the final "..." does not mach
>>> +// something matched by previous pattern, i.e. the rule will not match
>>> +// double error_prepend in control flow like in
>>> +// vfio_set_irq_signaling().
>>> +//
>>> +// Note, "exists" says that we want apply rule even if it matches not
>>> +// on all possible control flows (otherwise, it will not match
>>> +// standard pattern when error_propagate() call is in if branch).
>>> +@ disable optional_qualifier exists@
>>> +identifier fn, local_err;
>>> +symbol errp;
>>> +@@
>>> +
>>> + fn(..., Error **errp, ...)
>>> + {
>>> ++   ERRP_AUTO_PROPAGATE();
>>> +    ...  when != ERRP_AUTO_PROPAGATE();
>>> +(
>>> +(
>>> +    error_append_hint(errp, ...);
>>> +|
>>> +    error_prepend(errp, ...);
>>> +|
>>> +    error_vprepend(errp, ...);
>>> +)
>>> +    ... when any
>>> +|
>>> +    Error *local_err = NULL;
>>> +    ...
>>> +(
>>> +    error_propagate_prepend(errp, local_err, ...);
>>> +|
>>> +    error_propagate(errp, local_err);
>>> +)
>>> +    ...
>>> +)
>>> + }
>>> +
>>> +
>>> +// Match functions with propagation of local error to errp.
>>> +// We want to refer these functions in several following rules, but I
>>> +// don't know a proper way to inherit a function, not just its name
>>> +// (to not match another functions with same name in following rules).
>>> +// Not-proper way is as follows: rename errp parameter in functions
>>> +// header and match it in following rules. Rename it back after all
>>> +// transformations.
>>> +//
>>> +// The simplest case of propagation scheme is single definition of
>>> +// local_err with at most one error_propagate_prepend or
>>> +// error_propagate on each control-flow. Still, we want to match more
>>> +// complex schemes too. We'll warn them with help of further rules.
>>
>> I think what we actually want is to examine instances of this pattern to
>> figure out whether and how we want to transform them.  Perhaps:
>>
>>      // The common case is a single definition of local_err with at most one
>>      // error_propagate_prepend() or error_propagate() on each control-flow
>>      // path. Instances of this case we convert with this script. Functions
>
> For me, sounds a bit like "other things we don't convert".
> Actually we convert other things too.

What other patterns of error propagation do we convert?

>>      // with multiple definitions or propagates we want to examine
>>      // manually. Later rules emit warnings to guide us to them.
>>
>>> +@rule1 disable optional_qualifier exists@
>>> +identifier fn, local_err;
>>> +symbol errp;
>>> +@@
>>> +
>>> + fn(..., Error **
>>> +-    errp
>>> ++    ____
>>> +    , ...)
>>> + {
>>> +     ...
>>> +     Error *local_err = NULL;
>>> +     ...
>>> +(
>>> +     error_propagate_prepend(errp, local_err, ...);
>>> +|
>>> +     error_propagate(errp, local_err);
>>> +)
>>> +     ...
>>> + }
>>> +
>>> +
>>> +// Warn several Error * definitions.
>>> +@check1 disable optional_qualifier exists@
>>> +identifier fn = rule1.fn, local_err, local_err2;
>>
>> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
>> particular reason for the difference?
>
> I didn't find other way to ref check1.fn in next python rule. It just don't
> work if I write here just rule1.fn.
>
>>
>> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
>> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
>> everywhere, then apply the script to the complete tree, I get the same
>> result.
>
> I think, it's more efficient to reuse names from previous rules. I think it should
> work faster (more information, less extra matching).

Nope.  With my hacked up script (patch appended) Coccinelle is actually
*faster* for the .[ch] touched by this series: with your unmodified
script, it takes a bit over 12s on my box, with mine around 7s.  Output
is identical.

Never guess performance, always measure it :)

Two notes on my script:

* Unlike yours, it recognizes double-propagation in my test case.
  Discussed below.

* Its "several definitions of" warning includes positions.  That turned
  out to be useless, but I've been too lazy to take that out again.

>>
>>> +@@
>>> +
>>> + fn(..., Error ** ____, ...)
>>> + {
>>> +     ...
>>> +     Error *local_err = NULL;
>>> +     ... when any
>>> +     Error *local_err2 = NULL;
>>> +     ... when any
>>> + }
>>> +
>>> +@ script:python @
>>> +fn << check1.fn;
>>> +@@
>>> +
>>> +print('Warning: function {} has several definitions of '
>>> +      'Error * local variable'.format(fn))
>>> +
>>> +// Warn several propagations in control flow.
>>> +@check2 disable optional_qualifier exists@
>>> +identifier fn = rule1.fn;
>>> +symbol errp;
>>> +position p1, p2;
>>> +@@
>>> +
>>> + fn(..., Error ** ____, ...)
>>> + {
>>> +     ...
>>> +(
>>> +     error_propagate_prepend(errp, ...);@p1
>>> +|
>>> +     error_propagate(errp, ...);@p1
>>> +)
>>> +     ...
>>> +(
>>> +     error_propagate_prepend(errp, ...);@p2
>>> +|
>>> +     error_propagate(errp, ...);@p2
>>> +)
>>> +     ... when any
>>> + }
>>> +
>>
>> Hmm, we don't catch the example I used in review of v8:
>>
>>      extern foo(int, Error **);
>>      extern bar(int, Error **);
>>
>>      void frob(Error **errp)
>>      {
>>          Error *local_err = NULL;
>>          int arg;
>>
>>          foo(arg, errp);
>>          bar(arg, &local_err);
>>          error_propagate(errp, local_err);
>>          bar(arg + 1, &local_err);
>>          error_propagate(errp, local_err);
>>      }
>>
>> I believe this is because rule1 does not match here.
>
> Yes, rule1 wants at least one code flow with non-doubled propagation.
>
>>
>> If I change the rule as follows, it catches the example:
>>
>>      @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
>>
>>       // Warn several propagations in control flow.
>>       @check2 disable optional_qualifier exists@
>>      -identifier fn = rule1.fn;
>>      -symbol errp;
>>      +identifier fn, _errp;
>>       position p1, p2;
>>       @@
>>
>>      - fn(..., Error ** ____, ...)
>>      + fn(..., Error **_errp, ...)
>>        {
>>            ...
>>       (
>>      -     error_propagate_prepend(errp, ...);@p1
>>      +     error_propagate_prepend(_errp, ...);@p1
>>       |
>>      -     error_propagate(errp, ...);@p1
>>      +     error_propagate(_errp, ...);@p1
>>       )
>>            ...
>>       (
>>      -     error_propagate_prepend(errp, ...);@p2
>>      +     error_propagate_prepend(_errp, ...);@p2
>>       |
>>      -     error_propagate(errp, ...);@p2
>>      +     error_propagate(_errp, ...);@p2
>>       )
>>            ... when any
>>        }
>>
>> To my mild surprise, it still doesn't find anything in our tree.
>>
>> Should we decouple the previous rule from rule1, too?  I tested the
>> following on the whole tree:
>
> I don't think so. Why to check what we are not going to convert? If we want
> to check side things, it's better to do it in other coccinelle script..

Misunderstanding?  The rules are still chained together via the ___
hack, just not via function name, because that's unreliable and
redundant.

>>
>>      @@ -136,10 +136,10 @@ symbol errp;
>>
>>       // Warn several Error * definitions.
>>       @check1 disable optional_qualifier exists@
>>      -identifier fn = rule1.fn, local_err, local_err2;
>>      +identifier fn, _errp, local_err, local_err2;
>>       @@
>>
>>      - fn(..., Error ** ____, ...)
>>      + fn(..., Error **_errp, ...)
>>        {
>>            ...
>>            Error *local_err = NULL;
>>
>> Warnings remain unchanged.
>>
>>> +@ script:python @
>>> +fn << check2.fn;
>>> +p1 << check2.p1;
>>> +p2 << check2.p2;
>>> +@@
>>> +
>>> +print('Warning: function {} propagates to errp several times in '
>>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>> +
>>> +// Convert special case with goto separately.
>>> +// I tried merging this into the following rule the obvious way, but
>>> +// it made Coccinelle hang on block.c
>>> +//
>>> +// Note interesting thing: if we don't do it here, and try to fixup
>>> +// "out: }" things later after all transformations (the rule will be
>>> +// the same, just without error_propagate() call), coccinelle fails to
>>> +// match this "out: }".
>>> +@ disable optional_qualifier@
>>> +identifier rule1.fn, rule1.local_err, out;
>>
>> As explained above, I doubt the need for rule1.fn.  We do need
>> rule1.local_err to avoid unwanted transformations.  More of the same
>> below.
>
> Logically, I want to inherit from rule1. So why not to stress it by inheriting
> fn variable? It's just a correct thing to do.
> And I hope it helps coccinelle to work more efficiently.
>
>>
>>> +symbol errp;
>>> +@@
>>> +
>>> + fn(..., Error ** ____, ...)
>>> + {
>>> +     <...
>>> +-    goto out;
>>> ++    return;
>>> +     ...>
>>> +- out:
>>> +-    error_propagate(errp, local_err);
>>> + }
>>> +
>>> +// Convert most of local_err related stuff.
>>> +//
>>> +// Note, that we update everything related to matched by rule1
>>> +// function name and local_err name. We may match something not
>>> +// related to the pattern matched by rule1. For example, local_err may
>>> +// be defined with the same name in different blocks inside one
>>> +// function, and in one block follow the propagation pattern and in
>>> +// other block doesn't. Or we may have several functions with the same
>>> +// name (for different configurations).
>>> +//
>>> +// Note also that errp-cleaning functions
>>> +//   error_free_errp
>>> +//   error_report_errp
>>> +//   error_reportf_errp
>>> +//   warn_report_errp
>>> +//   warn_reportf_errp
>>> +// are not yet implemented. They must call corresponding Error* -
>>> +// freeing function and then set *errp to NULL, to avoid further
>>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>> +// For example, error_free_errp may look like this:
>>> +//
>>> +//    void error_free_errp(Error **errp)
>>> +//    {
>>> +//        error_free(*errp);
>>> +//        *errp = NULL;
>>> +//    }
>>> +@ disable optional_qualifier exists@
>>> +identifier rule1.fn, rule1.local_err;
>>> +expression list args;
>>> +symbol errp;
>>> +@@
>>> +
>>> + fn(..., Error ** ____, ...)
>>> + {
>>> +     <...
>>> +(
>>> +-    Error *local_err = NULL;
>>> +|
>>> +
>>> +// Convert error clearing functions
>>> +(
>>> +-    error_free(local_err);
>>> ++    error_free_errp(errp);
>>> +|
>>> +-    error_report_err(local_err);
>>> ++    error_report_errp(errp);
>>> +|
>>> +-    error_reportf_err(local_err, args);
>>> ++    error_reportf_errp(errp, args);
>>> +|
>>> +-    warn_report_err(local_err);
>>> ++    warn_report_errp(errp);
>>> +|
>>> +-    warn_reportf_err(local_err, args);
>>> ++    warn_reportf_errp(errp, args);
>>> +)
>>> +?-    local_err = NULL;
>>> +
>>> +|
>>> +-    error_propagate_prepend(errp, local_err, args);
>>> ++    error_prepend(errp, args);
>>> +|
>>> +-    error_propagate(errp, local_err);
>>> +|
>>> +-    &local_err
>>> ++    errp
>>> +)
>>> +     ...>
>>> + }
>>> +
>>> +// Convert remaining local_err usage. For example, different kinds of
>>> +// error checking in if conditionals. We can't merge this into
>>> +// previous hunk, as this conflicts with other substitutions in it (at
>>> +// least with "- local_err = NULL").
>>> +@ disable optional_qualifier@
>>> +identifier rule1.fn, rule1.local_err;
>>> +symbol errp;
>>> +@@
>>> +
>>> + fn(..., Error ** ____, ...)
>>> + {
>>> +     <...
>>> +-    local_err
>>> ++    *errp
>>> +     ...>
>>> + }
>>> +
>>> +// Always use the same pattern for checking error
>>> +@ disable optional_qualifier@
>>> +identifier rule1.fn;
>>> +symbol errp;
>>> +@@
>>> +
>>> + fn(..., Error ** ____, ...)
>>> + {
>>> +     <...
>>> +-    *errp != NULL
>>> ++    *errp
>>> +     ...>
>>> + }
>>> +
>>> +// Revert temporary ___ identifier.
>>> +@ disable optional_qualifier@
>>> +identifier rule1.fn;
>>> +@@
>>> +
>>> + fn(..., Error **
>>> +-   ____
>>> ++   errp
>>> +    , ...)
>>> + {
>>> +     ...
>>> + }
>>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>>> index 30140d9bfe..56c133520d 100644
>>> --- a/include/qapi/error.h
>>> +++ b/include/qapi/error.h
>>> @@ -214,6 +214,9 @@
>>>    *         }
>>>    *         ...
>>>    *     }
>>> + *
>>> + * For mass-conversion use script
>>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>>    */
>>>     #ifndef ERROR_H
>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>> index 857f969aa1..047f1b9714 100644
>>> --- a/MAINTAINERS
>>> +++ b/MAINTAINERS
>>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>>   F: qapi/error.json
>>>   F: util/error.c
>>>   F: util/qemu-error.c
>>> +F: scripts/coccinelle/*err*.cocci
>>>     GDB stub
>>>   M: Alex Bennée <alex.bennee@linaro.org>
>>


From 42a08c529024337d1b859839c9ce7f797f784555 Mon Sep 17 00:00:00 2001
From: Markus Armbruster <armbru@redhat.com>
Date: Fri, 13 Mar 2020 14:27:57 +0100
Subject: [PATCH] fixup! scripts: Coccinelle script to use
 ERRP_AUTO_PROPAGATE()

---
 scripts/coccinelle/auto-propagated-errp.cocci | 37 ++++++++++---------
 1 file changed, 20 insertions(+), 17 deletions(-)

diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
index 7dac2dcfa4..43b0b0e63b 100644
--- a/scripts/coccinelle/auto-propagated-errp.cocci
+++ b/scripts/coccinelle/auto-propagated-errp.cocci
@@ -136,45 +136,48 @@ symbol errp;
 
 // Warn several Error * definitions.
 @check1 disable optional_qualifier exists@
-identifier fn = rule1.fn, local_err, local_err2;
+identifier fn, _errp, local_err, local_err2;
+position p1, p2;
 @@
 
- fn(..., Error ** ____, ...)
+ fn(..., Error **_errp, ...)
  {
      ...
-     Error *local_err = NULL;
+     Error *local_err = NULL;@p1
      ... when any
-     Error *local_err2 = NULL;
+     Error *local_err2 = NULL;@p2
      ... when any
  }
 
 @ script:python @
 fn << check1.fn;
+p1 << check1.p1;
+p2 << check1.p2;
 @@
 
 print('Warning: function {} has several definitions of '
-      'Error * local variable'.format(fn))
+      'Error * local variable: at {}:{} and then at {}:{}'.format(
+          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
 
 // Warn several propagations in control flow.
 @check2 disable optional_qualifier exists@
-identifier fn = rule1.fn;
-symbol errp;
+identifier fn, _errp;
 position p1, p2;
 @@
 
- fn(..., Error ** ____, ...)
+ fn(..., Error **_errp, ...)
  {
      ...
 (
-     error_propagate_prepend(errp, ...);@p1
+     error_propagate_prepend(_errp, ...);@p1
 |
-     error_propagate(errp, ...);@p1
+     error_propagate(_errp, ...);@p1
 )
      ...
 (
-     error_propagate_prepend(errp, ...);@p2
+     error_propagate_prepend(_errp, ...);@p2
 |
-     error_propagate(errp, ...);@p2
+     error_propagate(_errp, ...);@p2
 )
      ... when any
  }
@@ -198,7 +201,7 @@ print('Warning: function {} propagates to errp several times in '
 // the same, just without error_propagate() call), coccinelle fails to
 // match this "out: }".
 @ disable optional_qualifier@
-identifier rule1.fn, rule1.local_err, out;
+identifier fn, rule1.local_err, out;
 symbol errp;
 @@
 
@@ -239,7 +242,7 @@ symbol errp;
 //        *errp = NULL;
 //    }
 @ disable optional_qualifier exists@
-identifier rule1.fn, rule1.local_err;
+identifier fn, rule1.local_err;
 expression list args;
 symbol errp;
 @@
@@ -287,7 +290,7 @@ symbol errp;
 // previous hunk, as this conflicts with other substitutions in it (at
 // least with "- local_err = NULL").
 @ disable optional_qualifier@
-identifier rule1.fn, rule1.local_err;
+identifier fn, rule1.local_err;
 symbol errp;
 @@
 
@@ -301,7 +304,7 @@ symbol errp;
 
 // Always use the same pattern for checking error
 @ disable optional_qualifier@
-identifier rule1.fn;
+identifier fn;
 symbol errp;
 @@
 
@@ -315,7 +318,7 @@ symbol errp;
 
 // Revert temporary ___ identifier.
 @ disable optional_qualifier@
-identifier rule1.fn;
+identifier fn;
 @@
 
  fn(..., Error **
-- 
2.21.1


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply related	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-13 15:42         ` [Xen-devel] " Markus Armbruster
@ 2020-03-13 16:12           ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-13 16:12 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

13.03.2020 18:42, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> 12.03.2020 19:36, Markus Armbruster wrote:
>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>> out now as is.
>>>
>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>
>>>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>>>> does corresponding changes in code (look for details in
>>>> include/qapi/error.h)
>>>>
>>>> Usage example:
>>>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>    --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>>>    --max-width 80 FILES...
>>>>
>>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>>> ---
>>>>
>>>> Cc: Eric Blake <eblake@redhat.com>
>>>> Cc: Kevin Wolf <kwolf@redhat.com>
>>>> Cc: Max Reitz <mreitz@redhat.com>
>>>> Cc: Greg Kurz <groug@kaod.org>
>>>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>>>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>>> Cc: Paul Durrant <paul@xen.org>
>>>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>>>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>>>> Cc: Markus Armbruster <armbru@redhat.com>
>>>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>>>> Cc: qemu-devel@nongnu.org
>>>> Cc: qemu-block@nongnu.org
>>>> Cc: xen-devel@lists.xenproject.org
>>>>
>>>>    scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>>>    include/qapi/error.h                          |   3 +
>>>>    MAINTAINERS                                   |   1 +
>>>>    3 files changed, 331 insertions(+)
>>>>    create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>>>
>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>> new file mode 100644
>>>> index 0000000000..7dac2dcfa4
>>>> --- /dev/null
>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>> @@ -0,0 +1,327 @@
>>>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>>> +//
>>>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>>>> +//
>>>> +// This program is free software; you can redistribute it and/or
>>>> +// modify it under the terms of the GNU General Public License as
>>>> +// published by the Free Software Foundation; either version 2 of the
>>>> +// License, or (at your option) any later version.
>>>> +//
>>>> +// This program is distributed in the hope that it will be useful,
>>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>> +// GNU General Public License for more details.
>>>> +//
>>>> +// You should have received a copy of the GNU General Public License
>>>> +// along with this program.  If not, see
>>>> +// <http://www.gnu.org/licenses/>.
>>>> +//
>>>> +// Usage example:
>>>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>>>> +//  --no-show-diff --max-width 80 FILES...
>>>> +//
>>>> +// Note: --max-width 80 is needed because coccinelle default is less
>>>> +// than 80, and without this parameter coccinelle may reindent some
>>>> +// lines which fit into 80 characters but not to coccinelle default,
>>>> +// which in turn produces extra patch hunks for no reason.
>>>
>>> This is about unwanted reformatting of parameter lists due to the ___
>>> chaining hack.  --max-width 80 makes that less likely, but not
>>> impossible.
>>>
>>> We can search for unwanted reformatting of parameter lists.  I think
>>> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
>>> tree, I get one false positive (not a parameter list), and one hit:
>>>
>>>       @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>>>            }
>>>        }
>>>
>>>       -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>>>       +void object_apply_global_props(Object *obj, const GPtrArray *props,
>>>       +                               Error **errp)
>>>        {
>>>       +    ERRP_AUTO_PROPAGATE();
>>>            int i;
>>>
>>>            if (!props) {
>>>
>>> Reformatting, but not unwanted.
>>
>> Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
>> ERRP_AUTO_PROPAGATE addition even for non-automatic patch.
> 
> Agree.
> 
>>>
>>> The --max-width 80 hack is good enough for me.
>>>
>>> It does result in slightly long transformed lines, e.g. this one in
>>> replication.c:
>>>
>>>       @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>>>                s->mode = REPLICATION_MODE_PRIMARY;
>>>                top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>>>                if (top_id) {
>>>       -            error_setg(&local_err, "The primary side does not support option top-id");
>>>       +            error_setg(errp, "The primary side does not support option top-id");
>>>                    goto fail;
>>>                }
>>>            } else if (!strcmp(mode, "secondary")) {
>>>
>>> v8 did break this line (that's how I found it).  However, v9 still
>>> shortens the line, just not below the target.  All your + lines look
>>> quite unlikely to lengthen lines.  Let's not worry about this.
>>>
>>>> +// Switch unusual Error ** parameter names to errp
>>>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>>>> +//
>>>> +// Disable optional_qualifier to skip functions with
>>>> +// "Error *const *errp" parameter.
>>>> +//
>>>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>>>> +// that signals unusual semantics, and the parameter name may well
>>>> +// serve a purpose. (like nbd_iter_channel_error()).
>>>> +//
>>>> +// Skip util/error.c to not touch, for example, error_propagate() and
>>>> +// error_propagate_prepend().
>>>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>>>> +identifier fn;
>>>> +identifier _errp != errp;
>>>> +@@
>>>> +
>>>> + fn(...,
>>>> +-   Error **_errp
>>>> ++   Error **errp
>>>> +    ,...)
>>>> + {
>>>> +(
>>>> +     ... when != assert(_errp && *_errp)
>>>> +&
>>>> +     <...
>>>> +-    _errp
>>>> ++    errp
>>>> +     ...>
>>>> +)
>>>> + }
>>>> +
>>>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>>> +// necessary
>>>> +//
>>>> +// Note, that without "when any" the final "..." does not mach
>>>> +// something matched by previous pattern, i.e. the rule will not match
>>>> +// double error_prepend in control flow like in
>>>> +// vfio_set_irq_signaling().
>>>> +//
>>>> +// Note, "exists" says that we want apply rule even if it matches not
>>>> +// on all possible control flows (otherwise, it will not match
>>>> +// standard pattern when error_propagate() call is in if branch).
>>>> +@ disable optional_qualifier exists@
>>>> +identifier fn, local_err;
>>>> +symbol errp;
>>>> +@@
>>>> +
>>>> + fn(..., Error **errp, ...)
>>>> + {
>>>> ++   ERRP_AUTO_PROPAGATE();
>>>> +    ...  when != ERRP_AUTO_PROPAGATE();
>>>> +(
>>>> +(
>>>> +    error_append_hint(errp, ...);
>>>> +|
>>>> +    error_prepend(errp, ...);
>>>> +|
>>>> +    error_vprepend(errp, ...);
>>>> +)
>>>> +    ... when any
>>>> +|
>>>> +    Error *local_err = NULL;
>>>> +    ...
>>>> +(
>>>> +    error_propagate_prepend(errp, local_err, ...);
>>>> +|
>>>> +    error_propagate(errp, local_err);
>>>> +)
>>>> +    ...
>>>> +)
>>>> + }
>>>> +
>>>> +
>>>> +// Match functions with propagation of local error to errp.
>>>> +// We want to refer these functions in several following rules, but I
>>>> +// don't know a proper way to inherit a function, not just its name
>>>> +// (to not match another functions with same name in following rules).
>>>> +// Not-proper way is as follows: rename errp parameter in functions
>>>> +// header and match it in following rules. Rename it back after all
>>>> +// transformations.
>>>> +//
>>>> +// The simplest case of propagation scheme is single definition of
>>>> +// local_err with at most one error_propagate_prepend or
>>>> +// error_propagate on each control-flow. Still, we want to match more
>>>> +// complex schemes too. We'll warn them with help of further rules.
>>>
>>> I think what we actually want is to examine instances of this pattern to
>>> figure out whether and how we want to transform them.  Perhaps:
>>>
>>>       // The common case is a single definition of local_err with at most one
>>>       // error_propagate_prepend() or error_propagate() on each control-flow
>>>       // path. Instances of this case we convert with this script. Functions
>>
>> For me, sounds a bit like "other things we don't convert".
>> Actually we convert other things too.
> 
> What other patterns of error propagation do we convert?

Something like in xen_block_device_destroy, why not? Otherwise, it's better to avoid
matching things like xen_block_device_destroy, not just warn them.
But I'd prefer to proceed now as is to fit into 5.0.. Too much time already
spent on this. So, I'm OK with your wording too.

> 
>>>       // with multiple definitions or propagates we want to examine
>>>       // manually. Later rules emit warnings to guide us to them.
>>>
>>>> +@rule1 disable optional_qualifier exists@
>>>> +identifier fn, local_err;
>>>> +symbol errp;
>>>> +@@
>>>> +
>>>> + fn(..., Error **
>>>> +-    errp
>>>> ++    ____
>>>> +    , ...)
>>>> + {
>>>> +     ...
>>>> +     Error *local_err = NULL;
>>>> +     ...
>>>> +(
>>>> +     error_propagate_prepend(errp, local_err, ...);
>>>> +|
>>>> +     error_propagate(errp, local_err);
>>>> +)
>>>> +     ...
>>>> + }
>>>> +
>>>> +
>>>> +// Warn several Error * definitions.
>>>> +@check1 disable optional_qualifier exists@
>>>> +identifier fn = rule1.fn, local_err, local_err2;
>>>
>>> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
>>> particular reason for the difference?
>>
>> I didn't find other way to ref check1.fn in next python rule. It just don't
>> work if I write here just rule1.fn.
>>
>>>
>>> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
>>> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
>>> everywhere, then apply the script to the complete tree, I get the same
>>> result.
>>
>> I think, it's more efficient to reuse names from previous rules. I think it should
>> work faster (more information, less extra matching).
> 
> Nope.  With my hacked up script (patch appended) Coccinelle is actually
> *faster* for the .[ch] touched by this series: with your unmodified
> script, it takes a bit over 12s on my box, with mine around 7s.  Output
> is identical.
> 
> Never guess performance, always measure it :)

Hmm, whole tree results would be better proof

> 
> Two notes on my script:
> 
> * Unlike yours, it recognizes double-propagation in my test case.
>    Discussed below.
> 
> * Its "several definitions of" warning includes positions.  That turned
>    out to be useless, but I've been too lazy to take that out again.
> 
>>>
>>>> +@@
>>>> +
>>>> + fn(..., Error ** ____, ...)
>>>> + {
>>>> +     ...
>>>> +     Error *local_err = NULL;
>>>> +     ... when any
>>>> +     Error *local_err2 = NULL;
>>>> +     ... when any
>>>> + }
>>>> +
>>>> +@ script:python @
>>>> +fn << check1.fn;
>>>> +@@
>>>> +
>>>> +print('Warning: function {} has several definitions of '
>>>> +      'Error * local variable'.format(fn))
>>>> +
>>>> +// Warn several propagations in control flow.
>>>> +@check2 disable optional_qualifier exists@
>>>> +identifier fn = rule1.fn;
>>>> +symbol errp;
>>>> +position p1, p2;
>>>> +@@
>>>> +
>>>> + fn(..., Error ** ____, ...)
>>>> + {
>>>> +     ...
>>>> +(
>>>> +     error_propagate_prepend(errp, ...);@p1
>>>> +|
>>>> +     error_propagate(errp, ...);@p1
>>>> +)
>>>> +     ...
>>>> +(
>>>> +     error_propagate_prepend(errp, ...);@p2
>>>> +|
>>>> +     error_propagate(errp, ...);@p2
>>>> +)
>>>> +     ... when any
>>>> + }
>>>> +
>>>
>>> Hmm, we don't catch the example I used in review of v8:
>>>
>>>       extern foo(int, Error **);
>>>       extern bar(int, Error **);
>>>
>>>       void frob(Error **errp)
>>>       {
>>>           Error *local_err = NULL;
>>>           int arg;
>>>
>>>           foo(arg, errp);
>>>           bar(arg, &local_err);
>>>           error_propagate(errp, local_err);
>>>           bar(arg + 1, &local_err);
>>>           error_propagate(errp, local_err);
>>>       }
>>>
>>> I believe this is because rule1 does not match here.
>>
>> Yes, rule1 wants at least one code flow with non-doubled propagation.
>>
>>>
>>> If I change the rule as follows, it catches the example:
>>>
>>>       @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
>>>
>>>        // Warn several propagations in control flow.
>>>        @check2 disable optional_qualifier exists@
>>>       -identifier fn = rule1.fn;
>>>       -symbol errp;
>>>       +identifier fn, _errp;
>>>        position p1, p2;
>>>        @@
>>>
>>>       - fn(..., Error ** ____, ...)
>>>       + fn(..., Error **_errp, ...)
>>>         {
>>>             ...
>>>        (
>>>       -     error_propagate_prepend(errp, ...);@p1
>>>       +     error_propagate_prepend(_errp, ...);@p1
>>>        |
>>>       -     error_propagate(errp, ...);@p1
>>>       +     error_propagate(_errp, ...);@p1
>>>        )
>>>             ...
>>>        (
>>>       -     error_propagate_prepend(errp, ...);@p2
>>>       +     error_propagate_prepend(_errp, ...);@p2
>>>        |
>>>       -     error_propagate(errp, ...);@p2
>>>       +     error_propagate(_errp, ...);@p2
>>>        )
>>>             ... when any
>>>         }
>>>
>>> To my mild surprise, it still doesn't find anything in our tree.
>>>
>>> Should we decouple the previous rule from rule1, too?  I tested the
>>> following on the whole tree:
>>
>> I don't think so. Why to check what we are not going to convert? If we want
>> to check side things, it's better to do it in other coccinelle script..
> 
> Misunderstanding?  The rules are still chained together via the ___
> hack, just not via function name, because that's unreliable and
> redundant.


Strange.. Then, how can it match something not matched by rule1?


> 
>>>
>>>       @@ -136,10 +136,10 @@ symbol errp;
>>>
>>>        // Warn several Error * definitions.
>>>        @check1 disable optional_qualifier exists@
>>>       -identifier fn = rule1.fn, local_err, local_err2;
>>>       +identifier fn, _errp, local_err, local_err2;
>>>        @@
>>>
>>>       - fn(..., Error ** ____, ...)
>>>       + fn(..., Error **_errp, ...)
>>>         {
>>>             ...
>>>             Error *local_err = NULL;
>>>
>>> Warnings remain unchanged.
>>>
>>>> +@ script:python @
>>>> +fn << check2.fn;
>>>> +p1 << check2.p1;
>>>> +p2 << check2.p2;
>>>> +@@
>>>> +
>>>> +print('Warning: function {} propagates to errp several times in '
>>>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>> +
>>>> +// Convert special case with goto separately.
>>>> +// I tried merging this into the following rule the obvious way, but
>>>> +// it made Coccinelle hang on block.c
>>>> +//
>>>> +// Note interesting thing: if we don't do it here, and try to fixup
>>>> +// "out: }" things later after all transformations (the rule will be
>>>> +// the same, just without error_propagate() call), coccinelle fails to
>>>> +// match this "out: }".
>>>> +@ disable optional_qualifier@
>>>> +identifier rule1.fn, rule1.local_err, out;
>>>
>>> As explained above, I doubt the need for rule1.fn.  We do need
>>> rule1.local_err to avoid unwanted transformations.  More of the same
>>> below.
>>
>> Logically, I want to inherit from rule1. So why not to stress it by inheriting
>> fn variable? It's just a correct thing to do.
>> And I hope it helps coccinelle to work more efficiently.
>>
>>>
>>>> +symbol errp;
>>>> +@@
>>>> +
>>>> + fn(..., Error ** ____, ...)
>>>> + {
>>>> +     <...
>>>> +-    goto out;
>>>> ++    return;
>>>> +     ...>
>>>> +- out:
>>>> +-    error_propagate(errp, local_err);
>>>> + }
>>>> +
>>>> +// Convert most of local_err related stuff.
>>>> +//
>>>> +// Note, that we update everything related to matched by rule1
>>>> +// function name and local_err name. We may match something not
>>>> +// related to the pattern matched by rule1. For example, local_err may
>>>> +// be defined with the same name in different blocks inside one
>>>> +// function, and in one block follow the propagation pattern and in
>>>> +// other block doesn't. Or we may have several functions with the same
>>>> +// name (for different configurations).
>>>> +//
>>>> +// Note also that errp-cleaning functions
>>>> +//   error_free_errp
>>>> +//   error_report_errp
>>>> +//   error_reportf_errp
>>>> +//   warn_report_errp
>>>> +//   warn_reportf_errp
>>>> +// are not yet implemented. They must call corresponding Error* -
>>>> +// freeing function and then set *errp to NULL, to avoid further
>>>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>>> +// For example, error_free_errp may look like this:
>>>> +//
>>>> +//    void error_free_errp(Error **errp)
>>>> +//    {
>>>> +//        error_free(*errp);
>>>> +//        *errp = NULL;
>>>> +//    }
>>>> +@ disable optional_qualifier exists@
>>>> +identifier rule1.fn, rule1.local_err;
>>>> +expression list args;
>>>> +symbol errp;
>>>> +@@
>>>> +
>>>> + fn(..., Error ** ____, ...)
>>>> + {
>>>> +     <...
>>>> +(
>>>> +-    Error *local_err = NULL;
>>>> +|
>>>> +
>>>> +// Convert error clearing functions
>>>> +(
>>>> +-    error_free(local_err);
>>>> ++    error_free_errp(errp);
>>>> +|
>>>> +-    error_report_err(local_err);
>>>> ++    error_report_errp(errp);
>>>> +|
>>>> +-    error_reportf_err(local_err, args);
>>>> ++    error_reportf_errp(errp, args);
>>>> +|
>>>> +-    warn_report_err(local_err);
>>>> ++    warn_report_errp(errp);
>>>> +|
>>>> +-    warn_reportf_err(local_err, args);
>>>> ++    warn_reportf_errp(errp, args);
>>>> +)
>>>> +?-    local_err = NULL;
>>>> +
>>>> +|
>>>> +-    error_propagate_prepend(errp, local_err, args);
>>>> ++    error_prepend(errp, args);
>>>> +|
>>>> +-    error_propagate(errp, local_err);
>>>> +|
>>>> +-    &local_err
>>>> ++    errp
>>>> +)
>>>> +     ...>
>>>> + }
>>>> +
>>>> +// Convert remaining local_err usage. For example, different kinds of
>>>> +// error checking in if conditionals. We can't merge this into
>>>> +// previous hunk, as this conflicts with other substitutions in it (at
>>>> +// least with "- local_err = NULL").
>>>> +@ disable optional_qualifier@
>>>> +identifier rule1.fn, rule1.local_err;
>>>> +symbol errp;
>>>> +@@
>>>> +
>>>> + fn(..., Error ** ____, ...)
>>>> + {
>>>> +     <...
>>>> +-    local_err
>>>> ++    *errp
>>>> +     ...>
>>>> + }
>>>> +
>>>> +// Always use the same pattern for checking error
>>>> +@ disable optional_qualifier@
>>>> +identifier rule1.fn;
>>>> +symbol errp;
>>>> +@@
>>>> +
>>>> + fn(..., Error ** ____, ...)
>>>> + {
>>>> +     <...
>>>> +-    *errp != NULL
>>>> ++    *errp
>>>> +     ...>
>>>> + }
>>>> +
>>>> +// Revert temporary ___ identifier.
>>>> +@ disable optional_qualifier@
>>>> +identifier rule1.fn;
>>>> +@@
>>>> +
>>>> + fn(..., Error **
>>>> +-   ____
>>>> ++   errp
>>>> +    , ...)
>>>> + {
>>>> +     ...
>>>> + }
>>>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>>>> index 30140d9bfe..56c133520d 100644
>>>> --- a/include/qapi/error.h
>>>> +++ b/include/qapi/error.h
>>>> @@ -214,6 +214,9 @@
>>>>     *         }
>>>>     *         ...
>>>>     *     }
>>>> + *
>>>> + * For mass-conversion use script
>>>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>>>     */
>>>>      #ifndef ERROR_H
>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>> index 857f969aa1..047f1b9714 100644
>>>> --- a/MAINTAINERS
>>>> +++ b/MAINTAINERS
>>>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>>>    F: qapi/error.json
>>>>    F: util/error.c
>>>>    F: util/qemu-error.c
>>>> +F: scripts/coccinelle/*err*.cocci
>>>>      GDB stub
>>>>    M: Alex Bennée <alex.bennee@linaro.org>
>>>
> 
> 
>  From 42a08c529024337d1b859839c9ce7f797f784555 Mon Sep 17 00:00:00 2001
> From: Markus Armbruster <armbru@redhat.com>
> Date: Fri, 13 Mar 2020 14:27:57 +0100
> Subject: [PATCH] fixup! scripts: Coccinelle script to use
>   ERRP_AUTO_PROPAGATE()
> 
> ---
>   scripts/coccinelle/auto-propagated-errp.cocci | 37 ++++++++++---------
>   1 file changed, 20 insertions(+), 17 deletions(-)
> 
> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
> index 7dac2dcfa4..43b0b0e63b 100644
> --- a/scripts/coccinelle/auto-propagated-errp.cocci
> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
> @@ -136,45 +136,48 @@ symbol errp;
>   
>   // Warn several Error * definitions.
>   @check1 disable optional_qualifier exists@
> -identifier fn = rule1.fn, local_err, local_err2;
> +identifier fn, _errp, local_err, local_err2;
> +position p1, p2;


Hmm, seems like I forget to define ____ as symbol in my patch

>   @@
>   
> - fn(..., Error ** ____, ...)
> + fn(..., Error **_errp, ...)

Ahmm.. it will break compilation?

Or, how will it work when _errp defined as meta variable is only in "+..." line? Should it be symbol instead, or just not defined?

>    {
>        ...
> -     Error *local_err = NULL;
> +     Error *local_err = NULL;@p1

Why to do -/+ here? Nothing changed..

>        ... when any
> -     Error *local_err2 = NULL;
> +     Error *local_err2 = NULL;@p2
>        ... when any
>    }
>   
>   @ script:python @
>   fn << check1.fn;
> +p1 << check1.p1;
> +p2 << check1.p2;
>   @@
>   
>   print('Warning: function {} has several definitions of '
> -      'Error * local variable'.format(fn))
> +      'Error * local variable: at {}:{} and then at {}:{}'.format(
> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>   
>   // Warn several propagations in control flow.
>   @check2 disable optional_qualifier exists@
> -identifier fn = rule1.fn;
> -symbol errp;
> +identifier fn, _errp;
>   position p1, p2;
>   @@
>   
> - fn(..., Error ** ____, ...)
> + fn(..., Error **_errp, ...)
>    {
>        ...
>   (
> -     error_propagate_prepend(errp, ...);@p1
> +     error_propagate_prepend(_errp, ...);@p1
>   |
> -     error_propagate(errp, ...);@p1
> +     error_propagate(_errp, ...);@p1
>   )
>        ...
>   (
> -     error_propagate_prepend(errp, ...);@p2
> +     error_propagate_prepend(_errp, ...);@p2
>   |
> -     error_propagate(errp, ...);@p2
> +     error_propagate(_errp, ...);@p2
>   )

You change some occurrences of errp to _errp, but not all. It breaks compilation.

>        ... when any
>    }
> @@ -198,7 +201,7 @@ print('Warning: function {} propagates to errp several times in '
>   // the same, just without error_propagate() call), coccinelle fails to
>   // match this "out: }".
>   @ disable optional_qualifier@
> -identifier rule1.fn, rule1.local_err, out;
> +identifier fn, rule1.local_err, out;

Hmm. If it improves performance it is strange.. But I can live with this change.

>   symbol errp;
>   @@
>   
> @@ -239,7 +242,7 @@ symbol errp;
>   //        *errp = NULL;
>   //    }
>   @ disable optional_qualifier exists@
> -identifier rule1.fn, rule1.local_err;
> +identifier fn, rule1.local_err;
>   expression list args;
>   symbol errp;
>   @@
> @@ -287,7 +290,7 @@ symbol errp;
>   // previous hunk, as this conflicts with other substitutions in it (at
>   // least with "- local_err = NULL").
>   @ disable optional_qualifier@
> -identifier rule1.fn, rule1.local_err;
> +identifier fn, rule1.local_err;
>   symbol errp;
>   @@
>   
> @@ -301,7 +304,7 @@ symbol errp;
>   
>   // Always use the same pattern for checking error
>   @ disable optional_qualifier@
> -identifier rule1.fn;
> +identifier fn;
>   symbol errp;
>   @@
>   
> @@ -315,7 +318,7 @@ symbol errp;
>   
>   // Revert temporary ___ identifier.
>   @ disable optional_qualifier@
> -identifier rule1.fn;
> +identifier fn;
>   @@
>   
>    fn(..., Error **
> 


-- 
Best regards,
Vladimir


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-13 16:12           ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-13 16:12 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

13.03.2020 18:42, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> 12.03.2020 19:36, Markus Armbruster wrote:
>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>> out now as is.
>>>
>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>
>>>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>>>> does corresponding changes in code (look for details in
>>>> include/qapi/error.h)
>>>>
>>>> Usage example:
>>>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>    --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>>>    --max-width 80 FILES...
>>>>
>>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>>> ---
>>>>
>>>> Cc: Eric Blake <eblake@redhat.com>
>>>> Cc: Kevin Wolf <kwolf@redhat.com>
>>>> Cc: Max Reitz <mreitz@redhat.com>
>>>> Cc: Greg Kurz <groug@kaod.org>
>>>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>>>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>>> Cc: Paul Durrant <paul@xen.org>
>>>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>>>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>>>> Cc: Markus Armbruster <armbru@redhat.com>
>>>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>>>> Cc: qemu-devel@nongnu.org
>>>> Cc: qemu-block@nongnu.org
>>>> Cc: xen-devel@lists.xenproject.org
>>>>
>>>>    scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>>>    include/qapi/error.h                          |   3 +
>>>>    MAINTAINERS                                   |   1 +
>>>>    3 files changed, 331 insertions(+)
>>>>    create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>>>
>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>> new file mode 100644
>>>> index 0000000000..7dac2dcfa4
>>>> --- /dev/null
>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>> @@ -0,0 +1,327 @@
>>>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>>> +//
>>>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>>>> +//
>>>> +// This program is free software; you can redistribute it and/or
>>>> +// modify it under the terms of the GNU General Public License as
>>>> +// published by the Free Software Foundation; either version 2 of the
>>>> +// License, or (at your option) any later version.
>>>> +//
>>>> +// This program is distributed in the hope that it will be useful,
>>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>> +// GNU General Public License for more details.
>>>> +//
>>>> +// You should have received a copy of the GNU General Public License
>>>> +// along with this program.  If not, see
>>>> +// <http://www.gnu.org/licenses/>.
>>>> +//
>>>> +// Usage example:
>>>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>>>> +//  --no-show-diff --max-width 80 FILES...
>>>> +//
>>>> +// Note: --max-width 80 is needed because coccinelle default is less
>>>> +// than 80, and without this parameter coccinelle may reindent some
>>>> +// lines which fit into 80 characters but not to coccinelle default,
>>>> +// which in turn produces extra patch hunks for no reason.
>>>
>>> This is about unwanted reformatting of parameter lists due to the ___
>>> chaining hack.  --max-width 80 makes that less likely, but not
>>> impossible.
>>>
>>> We can search for unwanted reformatting of parameter lists.  I think
>>> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
>>> tree, I get one false positive (not a parameter list), and one hit:
>>>
>>>       @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>>>            }
>>>        }
>>>
>>>       -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>>>       +void object_apply_global_props(Object *obj, const GPtrArray *props,
>>>       +                               Error **errp)
>>>        {
>>>       +    ERRP_AUTO_PROPAGATE();
>>>            int i;
>>>
>>>            if (!props) {
>>>
>>> Reformatting, but not unwanted.
>>
>> Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
>> ERRP_AUTO_PROPAGATE addition even for non-automatic patch.
> 
> Agree.
> 
>>>
>>> The --max-width 80 hack is good enough for me.
>>>
>>> It does result in slightly long transformed lines, e.g. this one in
>>> replication.c:
>>>
>>>       @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>>>                s->mode = REPLICATION_MODE_PRIMARY;
>>>                top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>>>                if (top_id) {
>>>       -            error_setg(&local_err, "The primary side does not support option top-id");
>>>       +            error_setg(errp, "The primary side does not support option top-id");
>>>                    goto fail;
>>>                }
>>>            } else if (!strcmp(mode, "secondary")) {
>>>
>>> v8 did break this line (that's how I found it).  However, v9 still
>>> shortens the line, just not below the target.  All your + lines look
>>> quite unlikely to lengthen lines.  Let's not worry about this.
>>>
>>>> +// Switch unusual Error ** parameter names to errp
>>>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>>>> +//
>>>> +// Disable optional_qualifier to skip functions with
>>>> +// "Error *const *errp" parameter.
>>>> +//
>>>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>>>> +// that signals unusual semantics, and the parameter name may well
>>>> +// serve a purpose. (like nbd_iter_channel_error()).
>>>> +//
>>>> +// Skip util/error.c to not touch, for example, error_propagate() and
>>>> +// error_propagate_prepend().
>>>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>>>> +identifier fn;
>>>> +identifier _errp != errp;
>>>> +@@
>>>> +
>>>> + fn(...,
>>>> +-   Error **_errp
>>>> ++   Error **errp
>>>> +    ,...)
>>>> + {
>>>> +(
>>>> +     ... when != assert(_errp && *_errp)
>>>> +&
>>>> +     <...
>>>> +-    _errp
>>>> ++    errp
>>>> +     ...>
>>>> +)
>>>> + }
>>>> +
>>>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>>> +// necessary
>>>> +//
>>>> +// Note, that without "when any" the final "..." does not mach
>>>> +// something matched by previous pattern, i.e. the rule will not match
>>>> +// double error_prepend in control flow like in
>>>> +// vfio_set_irq_signaling().
>>>> +//
>>>> +// Note, "exists" says that we want apply rule even if it matches not
>>>> +// on all possible control flows (otherwise, it will not match
>>>> +// standard pattern when error_propagate() call is in if branch).
>>>> +@ disable optional_qualifier exists@
>>>> +identifier fn, local_err;
>>>> +symbol errp;
>>>> +@@
>>>> +
>>>> + fn(..., Error **errp, ...)
>>>> + {
>>>> ++   ERRP_AUTO_PROPAGATE();
>>>> +    ...  when != ERRP_AUTO_PROPAGATE();
>>>> +(
>>>> +(
>>>> +    error_append_hint(errp, ...);
>>>> +|
>>>> +    error_prepend(errp, ...);
>>>> +|
>>>> +    error_vprepend(errp, ...);
>>>> +)
>>>> +    ... when any
>>>> +|
>>>> +    Error *local_err = NULL;
>>>> +    ...
>>>> +(
>>>> +    error_propagate_prepend(errp, local_err, ...);
>>>> +|
>>>> +    error_propagate(errp, local_err);
>>>> +)
>>>> +    ...
>>>> +)
>>>> + }
>>>> +
>>>> +
>>>> +// Match functions with propagation of local error to errp.
>>>> +// We want to refer these functions in several following rules, but I
>>>> +// don't know a proper way to inherit a function, not just its name
>>>> +// (to not match another functions with same name in following rules).
>>>> +// Not-proper way is as follows: rename errp parameter in functions
>>>> +// header and match it in following rules. Rename it back after all
>>>> +// transformations.
>>>> +//
>>>> +// The simplest case of propagation scheme is single definition of
>>>> +// local_err with at most one error_propagate_prepend or
>>>> +// error_propagate on each control-flow. Still, we want to match more
>>>> +// complex schemes too. We'll warn them with help of further rules.
>>>
>>> I think what we actually want is to examine instances of this pattern to
>>> figure out whether and how we want to transform them.  Perhaps:
>>>
>>>       // The common case is a single definition of local_err with at most one
>>>       // error_propagate_prepend() or error_propagate() on each control-flow
>>>       // path. Instances of this case we convert with this script. Functions
>>
>> For me, sounds a bit like "other things we don't convert".
>> Actually we convert other things too.
> 
> What other patterns of error propagation do we convert?

Something like in xen_block_device_destroy, why not? Otherwise, it's better to avoid
matching things like xen_block_device_destroy, not just warn them.
But I'd prefer to proceed now as is to fit into 5.0.. Too much time already
spent on this. So, I'm OK with your wording too.

> 
>>>       // with multiple definitions or propagates we want to examine
>>>       // manually. Later rules emit warnings to guide us to them.
>>>
>>>> +@rule1 disable optional_qualifier exists@
>>>> +identifier fn, local_err;
>>>> +symbol errp;
>>>> +@@
>>>> +
>>>> + fn(..., Error **
>>>> +-    errp
>>>> ++    ____
>>>> +    , ...)
>>>> + {
>>>> +     ...
>>>> +     Error *local_err = NULL;
>>>> +     ...
>>>> +(
>>>> +     error_propagate_prepend(errp, local_err, ...);
>>>> +|
>>>> +     error_propagate(errp, local_err);
>>>> +)
>>>> +     ...
>>>> + }
>>>> +
>>>> +
>>>> +// Warn several Error * definitions.
>>>> +@check1 disable optional_qualifier exists@
>>>> +identifier fn = rule1.fn, local_err, local_err2;
>>>
>>> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
>>> particular reason for the difference?
>>
>> I didn't find other way to ref check1.fn in next python rule. It just don't
>> work if I write here just rule1.fn.
>>
>>>
>>> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
>>> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
>>> everywhere, then apply the script to the complete tree, I get the same
>>> result.
>>
>> I think, it's more efficient to reuse names from previous rules. I think it should
>> work faster (more information, less extra matching).
> 
> Nope.  With my hacked up script (patch appended) Coccinelle is actually
> *faster* for the .[ch] touched by this series: with your unmodified
> script, it takes a bit over 12s on my box, with mine around 7s.  Output
> is identical.
> 
> Never guess performance, always measure it :)

Hmm, whole tree results would be better proof

> 
> Two notes on my script:
> 
> * Unlike yours, it recognizes double-propagation in my test case.
>    Discussed below.
> 
> * Its "several definitions of" warning includes positions.  That turned
>    out to be useless, but I've been too lazy to take that out again.
> 
>>>
>>>> +@@
>>>> +
>>>> + fn(..., Error ** ____, ...)
>>>> + {
>>>> +     ...
>>>> +     Error *local_err = NULL;
>>>> +     ... when any
>>>> +     Error *local_err2 = NULL;
>>>> +     ... when any
>>>> + }
>>>> +
>>>> +@ script:python @
>>>> +fn << check1.fn;
>>>> +@@
>>>> +
>>>> +print('Warning: function {} has several definitions of '
>>>> +      'Error * local variable'.format(fn))
>>>> +
>>>> +// Warn several propagations in control flow.
>>>> +@check2 disable optional_qualifier exists@
>>>> +identifier fn = rule1.fn;
>>>> +symbol errp;
>>>> +position p1, p2;
>>>> +@@
>>>> +
>>>> + fn(..., Error ** ____, ...)
>>>> + {
>>>> +     ...
>>>> +(
>>>> +     error_propagate_prepend(errp, ...);@p1
>>>> +|
>>>> +     error_propagate(errp, ...);@p1
>>>> +)
>>>> +     ...
>>>> +(
>>>> +     error_propagate_prepend(errp, ...);@p2
>>>> +|
>>>> +     error_propagate(errp, ...);@p2
>>>> +)
>>>> +     ... when any
>>>> + }
>>>> +
>>>
>>> Hmm, we don't catch the example I used in review of v8:
>>>
>>>       extern foo(int, Error **);
>>>       extern bar(int, Error **);
>>>
>>>       void frob(Error **errp)
>>>       {
>>>           Error *local_err = NULL;
>>>           int arg;
>>>
>>>           foo(arg, errp);
>>>           bar(arg, &local_err);
>>>           error_propagate(errp, local_err);
>>>           bar(arg + 1, &local_err);
>>>           error_propagate(errp, local_err);
>>>       }
>>>
>>> I believe this is because rule1 does not match here.
>>
>> Yes, rule1 wants at least one code flow with non-doubled propagation.
>>
>>>
>>> If I change the rule as follows, it catches the example:
>>>
>>>       @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
>>>
>>>        // Warn several propagations in control flow.
>>>        @check2 disable optional_qualifier exists@
>>>       -identifier fn = rule1.fn;
>>>       -symbol errp;
>>>       +identifier fn, _errp;
>>>        position p1, p2;
>>>        @@
>>>
>>>       - fn(..., Error ** ____, ...)
>>>       + fn(..., Error **_errp, ...)
>>>         {
>>>             ...
>>>        (
>>>       -     error_propagate_prepend(errp, ...);@p1
>>>       +     error_propagate_prepend(_errp, ...);@p1
>>>        |
>>>       -     error_propagate(errp, ...);@p1
>>>       +     error_propagate(_errp, ...);@p1
>>>        )
>>>             ...
>>>        (
>>>       -     error_propagate_prepend(errp, ...);@p2
>>>       +     error_propagate_prepend(_errp, ...);@p2
>>>        |
>>>       -     error_propagate(errp, ...);@p2
>>>       +     error_propagate(_errp, ...);@p2
>>>        )
>>>             ... when any
>>>         }
>>>
>>> To my mild surprise, it still doesn't find anything in our tree.
>>>
>>> Should we decouple the previous rule from rule1, too?  I tested the
>>> following on the whole tree:
>>
>> I don't think so. Why to check what we are not going to convert? If we want
>> to check side things, it's better to do it in other coccinelle script..
> 
> Misunderstanding?  The rules are still chained together via the ___
> hack, just not via function name, because that's unreliable and
> redundant.


Strange.. Then, how can it match something not matched by rule1?


> 
>>>
>>>       @@ -136,10 +136,10 @@ symbol errp;
>>>
>>>        // Warn several Error * definitions.
>>>        @check1 disable optional_qualifier exists@
>>>       -identifier fn = rule1.fn, local_err, local_err2;
>>>       +identifier fn, _errp, local_err, local_err2;
>>>        @@
>>>
>>>       - fn(..., Error ** ____, ...)
>>>       + fn(..., Error **_errp, ...)
>>>         {
>>>             ...
>>>             Error *local_err = NULL;
>>>
>>> Warnings remain unchanged.
>>>
>>>> +@ script:python @
>>>> +fn << check2.fn;
>>>> +p1 << check2.p1;
>>>> +p2 << check2.p2;
>>>> +@@
>>>> +
>>>> +print('Warning: function {} propagates to errp several times in '
>>>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>> +
>>>> +// Convert special case with goto separately.
>>>> +// I tried merging this into the following rule the obvious way, but
>>>> +// it made Coccinelle hang on block.c
>>>> +//
>>>> +// Note interesting thing: if we don't do it here, and try to fixup
>>>> +// "out: }" things later after all transformations (the rule will be
>>>> +// the same, just without error_propagate() call), coccinelle fails to
>>>> +// match this "out: }".
>>>> +@ disable optional_qualifier@
>>>> +identifier rule1.fn, rule1.local_err, out;
>>>
>>> As explained above, I doubt the need for rule1.fn.  We do need
>>> rule1.local_err to avoid unwanted transformations.  More of the same
>>> below.
>>
>> Logically, I want to inherit from rule1. So why not to stress it by inheriting
>> fn variable? It's just a correct thing to do.
>> And I hope it helps coccinelle to work more efficiently.
>>
>>>
>>>> +symbol errp;
>>>> +@@
>>>> +
>>>> + fn(..., Error ** ____, ...)
>>>> + {
>>>> +     <...
>>>> +-    goto out;
>>>> ++    return;
>>>> +     ...>
>>>> +- out:
>>>> +-    error_propagate(errp, local_err);
>>>> + }
>>>> +
>>>> +// Convert most of local_err related stuff.
>>>> +//
>>>> +// Note, that we update everything related to matched by rule1
>>>> +// function name and local_err name. We may match something not
>>>> +// related to the pattern matched by rule1. For example, local_err may
>>>> +// be defined with the same name in different blocks inside one
>>>> +// function, and in one block follow the propagation pattern and in
>>>> +// other block doesn't. Or we may have several functions with the same
>>>> +// name (for different configurations).
>>>> +//
>>>> +// Note also that errp-cleaning functions
>>>> +//   error_free_errp
>>>> +//   error_report_errp
>>>> +//   error_reportf_errp
>>>> +//   warn_report_errp
>>>> +//   warn_reportf_errp
>>>> +// are not yet implemented. They must call corresponding Error* -
>>>> +// freeing function and then set *errp to NULL, to avoid further
>>>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>>> +// For example, error_free_errp may look like this:
>>>> +//
>>>> +//    void error_free_errp(Error **errp)
>>>> +//    {
>>>> +//        error_free(*errp);
>>>> +//        *errp = NULL;
>>>> +//    }
>>>> +@ disable optional_qualifier exists@
>>>> +identifier rule1.fn, rule1.local_err;
>>>> +expression list args;
>>>> +symbol errp;
>>>> +@@
>>>> +
>>>> + fn(..., Error ** ____, ...)
>>>> + {
>>>> +     <...
>>>> +(
>>>> +-    Error *local_err = NULL;
>>>> +|
>>>> +
>>>> +// Convert error clearing functions
>>>> +(
>>>> +-    error_free(local_err);
>>>> ++    error_free_errp(errp);
>>>> +|
>>>> +-    error_report_err(local_err);
>>>> ++    error_report_errp(errp);
>>>> +|
>>>> +-    error_reportf_err(local_err, args);
>>>> ++    error_reportf_errp(errp, args);
>>>> +|
>>>> +-    warn_report_err(local_err);
>>>> ++    warn_report_errp(errp);
>>>> +|
>>>> +-    warn_reportf_err(local_err, args);
>>>> ++    warn_reportf_errp(errp, args);
>>>> +)
>>>> +?-    local_err = NULL;
>>>> +
>>>> +|
>>>> +-    error_propagate_prepend(errp, local_err, args);
>>>> ++    error_prepend(errp, args);
>>>> +|
>>>> +-    error_propagate(errp, local_err);
>>>> +|
>>>> +-    &local_err
>>>> ++    errp
>>>> +)
>>>> +     ...>
>>>> + }
>>>> +
>>>> +// Convert remaining local_err usage. For example, different kinds of
>>>> +// error checking in if conditionals. We can't merge this into
>>>> +// previous hunk, as this conflicts with other substitutions in it (at
>>>> +// least with "- local_err = NULL").
>>>> +@ disable optional_qualifier@
>>>> +identifier rule1.fn, rule1.local_err;
>>>> +symbol errp;
>>>> +@@
>>>> +
>>>> + fn(..., Error ** ____, ...)
>>>> + {
>>>> +     <...
>>>> +-    local_err
>>>> ++    *errp
>>>> +     ...>
>>>> + }
>>>> +
>>>> +// Always use the same pattern for checking error
>>>> +@ disable optional_qualifier@
>>>> +identifier rule1.fn;
>>>> +symbol errp;
>>>> +@@
>>>> +
>>>> + fn(..., Error ** ____, ...)
>>>> + {
>>>> +     <...
>>>> +-    *errp != NULL
>>>> ++    *errp
>>>> +     ...>
>>>> + }
>>>> +
>>>> +// Revert temporary ___ identifier.
>>>> +@ disable optional_qualifier@
>>>> +identifier rule1.fn;
>>>> +@@
>>>> +
>>>> + fn(..., Error **
>>>> +-   ____
>>>> ++   errp
>>>> +    , ...)
>>>> + {
>>>> +     ...
>>>> + }
>>>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>>>> index 30140d9bfe..56c133520d 100644
>>>> --- a/include/qapi/error.h
>>>> +++ b/include/qapi/error.h
>>>> @@ -214,6 +214,9 @@
>>>>     *         }
>>>>     *         ...
>>>>     *     }
>>>> + *
>>>> + * For mass-conversion use script
>>>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>>>     */
>>>>      #ifndef ERROR_H
>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>> index 857f969aa1..047f1b9714 100644
>>>> --- a/MAINTAINERS
>>>> +++ b/MAINTAINERS
>>>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>>>    F: qapi/error.json
>>>>    F: util/error.c
>>>>    F: util/qemu-error.c
>>>> +F: scripts/coccinelle/*err*.cocci
>>>>      GDB stub
>>>>    M: Alex Bennée <alex.bennee@linaro.org>
>>>
> 
> 
>  From 42a08c529024337d1b859839c9ce7f797f784555 Mon Sep 17 00:00:00 2001
> From: Markus Armbruster <armbru@redhat.com>
> Date: Fri, 13 Mar 2020 14:27:57 +0100
> Subject: [PATCH] fixup! scripts: Coccinelle script to use
>   ERRP_AUTO_PROPAGATE()
> 
> ---
>   scripts/coccinelle/auto-propagated-errp.cocci | 37 ++++++++++---------
>   1 file changed, 20 insertions(+), 17 deletions(-)
> 
> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
> index 7dac2dcfa4..43b0b0e63b 100644
> --- a/scripts/coccinelle/auto-propagated-errp.cocci
> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
> @@ -136,45 +136,48 @@ symbol errp;
>   
>   // Warn several Error * definitions.
>   @check1 disable optional_qualifier exists@
> -identifier fn = rule1.fn, local_err, local_err2;
> +identifier fn, _errp, local_err, local_err2;
> +position p1, p2;


Hmm, seems like I forget to define ____ as symbol in my patch

>   @@
>   
> - fn(..., Error ** ____, ...)
> + fn(..., Error **_errp, ...)

Ahmm.. it will break compilation?

Or, how will it work when _errp defined as meta variable is only in "+..." line? Should it be symbol instead, or just not defined?

>    {
>        ...
> -     Error *local_err = NULL;
> +     Error *local_err = NULL;@p1

Why to do -/+ here? Nothing changed..

>        ... when any
> -     Error *local_err2 = NULL;
> +     Error *local_err2 = NULL;@p2
>        ... when any
>    }
>   
>   @ script:python @
>   fn << check1.fn;
> +p1 << check1.p1;
> +p2 << check1.p2;
>   @@
>   
>   print('Warning: function {} has several definitions of '
> -      'Error * local variable'.format(fn))
> +      'Error * local variable: at {}:{} and then at {}:{}'.format(
> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>   
>   // Warn several propagations in control flow.
>   @check2 disable optional_qualifier exists@
> -identifier fn = rule1.fn;
> -symbol errp;
> +identifier fn, _errp;
>   position p1, p2;
>   @@
>   
> - fn(..., Error ** ____, ...)
> + fn(..., Error **_errp, ...)
>    {
>        ...
>   (
> -     error_propagate_prepend(errp, ...);@p1
> +     error_propagate_prepend(_errp, ...);@p1
>   |
> -     error_propagate(errp, ...);@p1
> +     error_propagate(_errp, ...);@p1
>   )
>        ...
>   (
> -     error_propagate_prepend(errp, ...);@p2
> +     error_propagate_prepend(_errp, ...);@p2
>   |
> -     error_propagate(errp, ...);@p2
> +     error_propagate(_errp, ...);@p2
>   )

You change some occurrences of errp to _errp, but not all. It breaks compilation.

>        ... when any
>    }
> @@ -198,7 +201,7 @@ print('Warning: function {} propagates to errp several times in '
>   // the same, just without error_propagate() call), coccinelle fails to
>   // match this "out: }".
>   @ disable optional_qualifier@
> -identifier rule1.fn, rule1.local_err, out;
> +identifier fn, rule1.local_err, out;

Hmm. If it improves performance it is strange.. But I can live with this change.

>   symbol errp;
>   @@
>   
> @@ -239,7 +242,7 @@ symbol errp;
>   //        *errp = NULL;
>   //    }
>   @ disable optional_qualifier exists@
> -identifier rule1.fn, rule1.local_err;
> +identifier fn, rule1.local_err;
>   expression list args;
>   symbol errp;
>   @@
> @@ -287,7 +290,7 @@ symbol errp;
>   // previous hunk, as this conflicts with other substitutions in it (at
>   // least with "- local_err = NULL").
>   @ disable optional_qualifier@
> -identifier rule1.fn, rule1.local_err;
> +identifier fn, rule1.local_err;
>   symbol errp;
>   @@
>   
> @@ -301,7 +304,7 @@ symbol errp;
>   
>   // Always use the same pattern for checking error
>   @ disable optional_qualifier@
> -identifier rule1.fn;
> +identifier fn;
>   symbol errp;
>   @@
>   
> @@ -315,7 +318,7 @@ symbol errp;
>   
>   // Revert temporary ___ identifier.
>   @ disable optional_qualifier@
> -identifier rule1.fn;
> +identifier fn;
>   @@
>   
>    fn(..., Error **
> 


-- 
Best regards,
Vladimir

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-13 16:12           ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-13 21:54             ` Markus Armbruster
  -1 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-13 21:54 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	qemu-devel, Laszlo Ersek, Christian Schoenebeck,
	Markus Armbruster, Michael Roth, Greg Kurz, Gerd Hoffmann,
	Stefan Hajnoczi, Anthony Perard, xen-devel, Max Reitz,
	Philippe Mathieu-Daudé,
	Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 13.03.2020 18:42, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>
>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>> out now as is.
>>>>
>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>
>>>>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>>>>> does corresponding changes in code (look for details in
>>>>> include/qapi/error.h)
>>>>>
>>>>> Usage example:
>>>>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>    --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>>>>    --max-width 80 FILES...
>>>>>
>>>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>>>> ---
>>>>>
>>>>> Cc: Eric Blake <eblake@redhat.com>
>>>>> Cc: Kevin Wolf <kwolf@redhat.com>
>>>>> Cc: Max Reitz <mreitz@redhat.com>
>>>>> Cc: Greg Kurz <groug@kaod.org>
>>>>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>>>>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>>>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>>>> Cc: Paul Durrant <paul@xen.org>
>>>>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>>>>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>>>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>>>>> Cc: Markus Armbruster <armbru@redhat.com>
>>>>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>>>>> Cc: qemu-devel@nongnu.org
>>>>> Cc: qemu-block@nongnu.org
>>>>> Cc: xen-devel@lists.xenproject.org
>>>>>
>>>>>    scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>>>>    include/qapi/error.h                          |   3 +
>>>>>    MAINTAINERS                                   |   1 +
>>>>>    3 files changed, 331 insertions(+)
>>>>>    create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>>>>
>>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>> new file mode 100644
>>>>> index 0000000000..7dac2dcfa4
>>>>> --- /dev/null
>>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>> @@ -0,0 +1,327 @@
>>>>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>>>> +//
>>>>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>>>>> +//
>>>>> +// This program is free software; you can redistribute it and/or
>>>>> +// modify it under the terms of the GNU General Public License as
>>>>> +// published by the Free Software Foundation; either version 2 of the
>>>>> +// License, or (at your option) any later version.
>>>>> +//
>>>>> +// This program is distributed in the hope that it will be useful,
>>>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>>> +// GNU General Public License for more details.
>>>>> +//
>>>>> +// You should have received a copy of the GNU General Public License
>>>>> +// along with this program.  If not, see
>>>>> +// <http://www.gnu.org/licenses/>.
>>>>> +//
>>>>> +// Usage example:
>>>>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>>>>> +//  --no-show-diff --max-width 80 FILES...
>>>>> +//
>>>>> +// Note: --max-width 80 is needed because coccinelle default is less
>>>>> +// than 80, and without this parameter coccinelle may reindent some
>>>>> +// lines which fit into 80 characters but not to coccinelle default,
>>>>> +// which in turn produces extra patch hunks for no reason.
>>>>
>>>> This is about unwanted reformatting of parameter lists due to the ___
>>>> chaining hack.  --max-width 80 makes that less likely, but not
>>>> impossible.
>>>>
>>>> We can search for unwanted reformatting of parameter lists.  I think
>>>> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
>>>> tree, I get one false positive (not a parameter list), and one hit:
>>>>
>>>>       @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>>>>            }
>>>>        }
>>>>
>>>>       -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>>>>       +void object_apply_global_props(Object *obj, const GPtrArray *props,
>>>>       +                               Error **errp)
>>>>        {
>>>>       +    ERRP_AUTO_PROPAGATE();
>>>>            int i;
>>>>
>>>>            if (!props) {
>>>>
>>>> Reformatting, but not unwanted.
>>>
>>> Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
>>> ERRP_AUTO_PROPAGATE addition even for non-automatic patch.
>>
>> Agree.
>>
>>>>
>>>> The --max-width 80 hack is good enough for me.
>>>>
>>>> It does result in slightly long transformed lines, e.g. this one in
>>>> replication.c:
>>>>
>>>>       @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>>>>                s->mode = REPLICATION_MODE_PRIMARY;
>>>>                top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>>>>                if (top_id) {
>>>>       -            error_setg(&local_err, "The primary side does not support option top-id");
>>>>       +            error_setg(errp, "The primary side does not support option top-id");
>>>>                    goto fail;
>>>>                }
>>>>            } else if (!strcmp(mode, "secondary")) {
>>>>
>>>> v8 did break this line (that's how I found it).  However, v9 still
>>>> shortens the line, just not below the target.  All your + lines look
>>>> quite unlikely to lengthen lines.  Let's not worry about this.
>>>>
>>>>> +// Switch unusual Error ** parameter names to errp
>>>>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>>>>> +//
>>>>> +// Disable optional_qualifier to skip functions with
>>>>> +// "Error *const *errp" parameter.
>>>>> +//
>>>>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>>>>> +// that signals unusual semantics, and the parameter name may well
>>>>> +// serve a purpose. (like nbd_iter_channel_error()).
>>>>> +//
>>>>> +// Skip util/error.c to not touch, for example, error_propagate() and
>>>>> +// error_propagate_prepend().
>>>>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>>>>> +identifier fn;
>>>>> +identifier _errp != errp;
>>>>> +@@
>>>>> +
>>>>> + fn(...,
>>>>> +-   Error **_errp
>>>>> ++   Error **errp
>>>>> +    ,...)
>>>>> + {
>>>>> +(
>>>>> +     ... when != assert(_errp && *_errp)
>>>>> +&
>>>>> +     <...
>>>>> +-    _errp
>>>>> ++    errp
>>>>> +     ...>
>>>>> +)
>>>>> + }
>>>>> +
>>>>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>>>> +// necessary
>>>>> +//
>>>>> +// Note, that without "when any" the final "..." does not mach
>>>>> +// something matched by previous pattern, i.e. the rule will not match
>>>>> +// double error_prepend in control flow like in
>>>>> +// vfio_set_irq_signaling().
>>>>> +//
>>>>> +// Note, "exists" says that we want apply rule even if it matches not
>>>>> +// on all possible control flows (otherwise, it will not match
>>>>> +// standard pattern when error_propagate() call is in if branch).
>>>>> +@ disable optional_qualifier exists@
>>>>> +identifier fn, local_err;
>>>>> +symbol errp;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error **errp, ...)
>>>>> + {
>>>>> ++   ERRP_AUTO_PROPAGATE();
>>>>> +    ...  when != ERRP_AUTO_PROPAGATE();
>>>>> +(
>>>>> +(
>>>>> +    error_append_hint(errp, ...);
>>>>> +|
>>>>> +    error_prepend(errp, ...);
>>>>> +|
>>>>> +    error_vprepend(errp, ...);
>>>>> +)
>>>>> +    ... when any
>>>>> +|
>>>>> +    Error *local_err = NULL;
>>>>> +    ...
>>>>> +(
>>>>> +    error_propagate_prepend(errp, local_err, ...);
>>>>> +|
>>>>> +    error_propagate(errp, local_err);
>>>>> +)
>>>>> +    ...
>>>>> +)
>>>>> + }
>>>>> +
>>>>> +
>>>>> +// Match functions with propagation of local error to errp.
>>>>> +// We want to refer these functions in several following rules, but I
>>>>> +// don't know a proper way to inherit a function, not just its name
>>>>> +// (to not match another functions with same name in following rules).
>>>>> +// Not-proper way is as follows: rename errp parameter in functions
>>>>> +// header and match it in following rules. Rename it back after all
>>>>> +// transformations.
>>>>> +//
>>>>> +// The simplest case of propagation scheme is single definition of
>>>>> +// local_err with at most one error_propagate_prepend or
>>>>> +// error_propagate on each control-flow. Still, we want to match more
>>>>> +// complex schemes too. We'll warn them with help of further rules.
>>>>
>>>> I think what we actually want is to examine instances of this pattern to
>>>> figure out whether and how we want to transform them.  Perhaps:
>>>>
>>>>       // The common case is a single definition of local_err with at most one
>>>>       // error_propagate_prepend() or error_propagate() on each control-flow
>>>>       // path. Instances of this case we convert with this script. Functions
>>>
>>> For me, sounds a bit like "other things we don't convert".
>>> Actually we convert other things too.
>>
>> What other patterns of error propagation do we convert?
>
> Something like in xen_block_device_destroy, why not? Otherwise, it's better to avoid
> matching things like xen_block_device_destroy, not just warn them.
> But I'd prefer to proceed now as is to fit into 5.0.. Too much time already
> spent on this. So, I'm OK with your wording too.

Let's scratch "Instances of this case we convert with this script."

>>>>       // with multiple definitions or propagates we want to examine
>>>>       // manually. Later rules emit warnings to guide us to them.
>>>>
>>>>> +@rule1 disable optional_qualifier exists@
>>>>> +identifier fn, local_err;
>>>>> +symbol errp;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error **
>>>>> +-    errp
>>>>> ++    ____
>>>>> +    , ...)
>>>>> + {
>>>>> +     ...
>>>>> +     Error *local_err = NULL;
>>>>> +     ...
>>>>> +(
>>>>> +     error_propagate_prepend(errp, local_err, ...);
>>>>> +|
>>>>> +     error_propagate(errp, local_err);
>>>>> +)
>>>>> +     ...
>>>>> + }
>>>>> +
>>>>> +
>>>>> +// Warn several Error * definitions.
>>>>> +@check1 disable optional_qualifier exists@
>>>>> +identifier fn = rule1.fn, local_err, local_err2;
>>>>
>>>> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
>>>> particular reason for the difference?
>>>
>>> I didn't find other way to ref check1.fn in next python rule. It just don't
>>> work if I write here just rule1.fn.
>>>
>>>>
>>>> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
>>>> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
>>>> everywhere, then apply the script to the complete tree, I get the same
>>>> result.
>>>
>>> I think, it's more efficient to reuse names from previous rules. I think it should
>>> work faster (more information, less extra matching).
>>
>> Nope.  With my hacked up script (patch appended) Coccinelle is actually
>> *faster* for the .[ch] touched by this series: with your unmodified
>> script, it takes a bit over 12s on my box, with mine around 7s.  Output
>> is identical.
>>
>> Never guess performance, always measure it :)
>
> Hmm, whole tree results would be better proof
>
>>
>> Two notes on my script:
>>
>> * Unlike yours, it recognizes double-propagation in my test case.
>>    Discussed below.
>>
>> * Its "several definitions of" warning includes positions.  That turned
>>    out to be useless, but I've been too lazy to take that out again.
>>
>>>>
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error ** ____, ...)
>>>>> + {
>>>>> +     ...
>>>>> +     Error *local_err = NULL;
>>>>> +     ... when any
>>>>> +     Error *local_err2 = NULL;
>>>>> +     ... when any
>>>>> + }

This flags functions that have more than one declaration along any
control flow path.  It doesn't flag this one:

    void gnat(bool b, Error **errp)
    {
        if (b) {
            Error *local_err = NULL;
            foo(arg, &local_err);
            error_propagate(errp, local_err);
        } else {
            Error *local_err = NULL;
            bar(arg, &local_err);
            error_propagate(errp, local_err);
        }
    }

The Coccinelle script does the right thing for this one regardless.

I'd prefer to have such functions flagged, too.  But spending time on
convincing Coccinelle to do it for me is not worthwhile; I can simply
search the diff produced by Coccinelle for deletions of declarations
that are not indented exactly four spaces.

But if we keep this rule, we should adjust its comment

    // Warn several Error * definitions.

because it sure suggests it also catches functions like the one I gave
above.

>>>>> +
>>>>> +@ script:python @
>>>>> +fn << check1.fn;
>>>>> +@@
>>>>> +
>>>>> +print('Warning: function {} has several definitions of '
>>>>> +      'Error * local variable'.format(fn))
>>>>> +
>>>>> +// Warn several propagations in control flow.
>>>>> +@check2 disable optional_qualifier exists@
>>>>> +identifier fn = rule1.fn;
>>>>> +symbol errp;
>>>>> +position p1, p2;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error ** ____, ...)
>>>>> + {
>>>>> +     ...
>>>>> +(
>>>>> +     error_propagate_prepend(errp, ...);@p1
>>>>> +|
>>>>> +     error_propagate(errp, ...);@p1
>>>>> +)
>>>>> +     ...
>>>>> +(
>>>>> +     error_propagate_prepend(errp, ...);@p2
>>>>> +|
>>>>> +     error_propagate(errp, ...);@p2
>>>>> +)
>>>>> +     ... when any
>>>>> + }
>>>>> +
>>>>
>>>> Hmm, we don't catch the example I used in review of v8:
>>>>
>>>>       extern foo(int, Error **);
>>>>       extern bar(int, Error **);
>>>>
>>>>       void frob(Error **errp)
>>>>       {
>>>>           Error *local_err = NULL;
>>>>           int arg;
>>>>
>>>>           foo(arg, errp);
>>>>           bar(arg, &local_err);
>>>>           error_propagate(errp, local_err);
>>>>           bar(arg + 1, &local_err);
>>>>           error_propagate(errp, local_err);
>>>>       }
>>>>
>>>> I believe this is because rule1 does not match here.
>>>
>>> Yes, rule1 wants at least one code flow with non-doubled propagation.
>>>
>>>>
>>>> If I change the rule as follows, it catches the example:
>>>>
>>>>       @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
>>>>
>>>>        // Warn several propagations in control flow.
>>>>        @check2 disable optional_qualifier exists@
>>>>       -identifier fn = rule1.fn;
>>>>       -symbol errp;
>>>>       +identifier fn, _errp;
>>>>        position p1, p2;
>>>>        @@
>>>>
>>>>       - fn(..., Error ** ____, ...)
>>>>       + fn(..., Error **_errp, ...)
>>>>         {
>>>>             ...
>>>>        (
>>>>       -     error_propagate_prepend(errp, ...);@p1
>>>>       +     error_propagate_prepend(_errp, ...);@p1
>>>>        |
>>>>       -     error_propagate(errp, ...);@p1
>>>>       +     error_propagate(_errp, ...);@p1
>>>>        )
>>>>             ...
>>>>        (
>>>>       -     error_propagate_prepend(errp, ...);@p2
>>>>       +     error_propagate_prepend(_errp, ...);@p2
>>>>        |
>>>>       -     error_propagate(errp, ...);@p2
>>>>       +     error_propagate(_errp, ...);@p2
>>>>        )
>>>>             ... when any
>>>>         }
>>>>
>>>> To my mild surprise, it still doesn't find anything in our tree.
>>>>
>>>> Should we decouple the previous rule from rule1, too?  I tested the
>>>> following on the whole tree:
>>>
>>> I don't think so. Why to check what we are not going to convert? If we want
>>> to check side things, it's better to do it in other coccinelle script..
>>
>> Misunderstanding?  The rules are still chained together via the ___
>> hack, just not via function name, because that's unreliable and
>> redundant.
>
> Strange.. Then, how can it match something not matched by rule1?

I think I got confused when I wrote the "Misunderstanding?" paragraph.

Let me try again.

First rule check2.

The common case is a at most one propagation to @errp along any control
flow path.  We trust your Coccinelle script to convert that alright.

Any other propagation to @errp I want to review.  Whether the script
attempts a conversion or not is unimportant, as long as it points me to
the function to review.

Rule rule1 matches functions that propagate to @errp once along at least
one control flow path.

Unchained from rule rule1, rule check2 flags any function that
propagates to @errp multiple times along any control flow path.

Chained to rule1, it flags only functions that also have a path with
single propagation.

In other words, the unchained rule flags *all* multi-propagations to
@errp, while the chained rule flags only the ones the script attempts to
convert.  The former is much more useful to me.

Now rule check1.  It flags functions with multiple declarations along
any control flow path.  Again, chaining it to rule1 restricts it to the
functions we attempt to convert.  Makes it less useful to me.  However,
because my desire to review multiple declarations in function we don't
attempt to convert is lower than my desire to review multiple
propagations to @errp in such functions, chaining check1 is tolerable
for me.  But why chain check1 if we don't chain check2?

>
>>
>>>>
>>>>       @@ -136,10 +136,10 @@ symbol errp;
>>>>
>>>>        // Warn several Error * definitions.
>>>>        @check1 disable optional_qualifier exists@
>>>>       -identifier fn = rule1.fn, local_err, local_err2;
>>>>       +identifier fn, _errp, local_err, local_err2;
>>>>        @@
>>>>
>>>>       - fn(..., Error ** ____, ...)
>>>>       + fn(..., Error **_errp, ...)
>>>>         {
>>>>             ...
>>>>             Error *local_err = NULL;
>>>>
>>>> Warnings remain unchanged.
>>>>
>>>>> +@ script:python @
>>>>> +fn << check2.fn;
>>>>> +p1 << check2.p1;
>>>>> +p2 << check2.p2;
>>>>> +@@
>>>>> +
>>>>> +print('Warning: function {} propagates to errp several times in '
>>>>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>>> +
>>>>> +// Convert special case with goto separately.
>>>>> +// I tried merging this into the following rule the obvious way, but
>>>>> +// it made Coccinelle hang on block.c
>>>>> +//
>>>>> +// Note interesting thing: if we don't do it here, and try to fixup
>>>>> +// "out: }" things later after all transformations (the rule will be
>>>>> +// the same, just without error_propagate() call), coccinelle fails to
>>>>> +// match this "out: }".
>>>>> +@ disable optional_qualifier@
>>>>> +identifier rule1.fn, rule1.local_err, out;
>>>>
>>>> As explained above, I doubt the need for rule1.fn.  We do need
>>>> rule1.local_err to avoid unwanted transformations.  More of the same
>>>> below.
>>>
>>> Logically, I want to inherit from rule1. So why not to stress it by inheriting
>>> fn variable? It's just a correct thing to do.
>>> And I hope it helps coccinelle to work more efficiently.
>>>
>>>>
>>>>> +symbol errp;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error ** ____, ...)
>>>>> + {
>>>>> +     <...
>>>>> +-    goto out;
>>>>> ++    return;
>>>>> +     ...>
>>>>> +- out:
>>>>> +-    error_propagate(errp, local_err);
>>>>> + }
>>>>> +
>>>>> +// Convert most of local_err related stuff.
>>>>> +//
>>>>> +// Note, that we update everything related to matched by rule1
>>>>> +// function name and local_err name. We may match something not
>>>>> +// related to the pattern matched by rule1. For example, local_err may
>>>>> +// be defined with the same name in different blocks inside one
>>>>> +// function, and in one block follow the propagation pattern and in
>>>>> +// other block doesn't. Or we may have several functions with the same
>>>>> +// name (for different configurations).
>>>>> +//
>>>>> +// Note also that errp-cleaning functions
>>>>> +//   error_free_errp
>>>>> +//   error_report_errp
>>>>> +//   error_reportf_errp
>>>>> +//   warn_report_errp
>>>>> +//   warn_reportf_errp
>>>>> +// are not yet implemented. They must call corresponding Error* -
>>>>> +// freeing function and then set *errp to NULL, to avoid further
>>>>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>>>> +// For example, error_free_errp may look like this:
>>>>> +//
>>>>> +//    void error_free_errp(Error **errp)
>>>>> +//    {
>>>>> +//        error_free(*errp);
>>>>> +//        *errp = NULL;
>>>>> +//    }
>>>>> +@ disable optional_qualifier exists@
>>>>> +identifier rule1.fn, rule1.local_err;
>>>>> +expression list args;
>>>>> +symbol errp;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error ** ____, ...)
>>>>> + {
>>>>> +     <...
>>>>> +(
>>>>> +-    Error *local_err = NULL;
>>>>> +|
>>>>> +
>>>>> +// Convert error clearing functions
>>>>> +(
>>>>> +-    error_free(local_err);
>>>>> ++    error_free_errp(errp);
>>>>> +|
>>>>> +-    error_report_err(local_err);
>>>>> ++    error_report_errp(errp);
>>>>> +|
>>>>> +-    error_reportf_err(local_err, args);
>>>>> ++    error_reportf_errp(errp, args);
>>>>> +|
>>>>> +-    warn_report_err(local_err);
>>>>> ++    warn_report_errp(errp);
>>>>> +|
>>>>> +-    warn_reportf_err(local_err, args);
>>>>> ++    warn_reportf_errp(errp, args);
>>>>> +)
>>>>> +?-    local_err = NULL;
>>>>> +
>>>>> +|
>>>>> +-    error_propagate_prepend(errp, local_err, args);
>>>>> ++    error_prepend(errp, args);
>>>>> +|
>>>>> +-    error_propagate(errp, local_err);
>>>>> +|
>>>>> +-    &local_err
>>>>> ++    errp
>>>>> +)
>>>>> +     ...>
>>>>> + }
>>>>> +
>>>>> +// Convert remaining local_err usage. For example, different kinds of
>>>>> +// error checking in if conditionals. We can't merge this into
>>>>> +// previous hunk, as this conflicts with other substitutions in it (at
>>>>> +// least with "- local_err = NULL").
>>>>> +@ disable optional_qualifier@
>>>>> +identifier rule1.fn, rule1.local_err;
>>>>> +symbol errp;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error ** ____, ...)
>>>>> + {
>>>>> +     <...
>>>>> +-    local_err
>>>>> ++    *errp
>>>>> +     ...>
>>>>> + }
>>>>> +
>>>>> +// Always use the same pattern for checking error
>>>>> +@ disable optional_qualifier@
>>>>> +identifier rule1.fn;
>>>>> +symbol errp;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error ** ____, ...)
>>>>> + {
>>>>> +     <...
>>>>> +-    *errp != NULL
>>>>> ++    *errp
>>>>> +     ...>
>>>>> + }
>>>>> +
>>>>> +// Revert temporary ___ identifier.
>>>>> +@ disable optional_qualifier@
>>>>> +identifier rule1.fn;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error **
>>>>> +-   ____
>>>>> ++   errp
>>>>> +    , ...)
>>>>> + {
>>>>> +     ...
>>>>> + }
>>>>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>>>>> index 30140d9bfe..56c133520d 100644
>>>>> --- a/include/qapi/error.h
>>>>> +++ b/include/qapi/error.h
>>>>> @@ -214,6 +214,9 @@
>>>>>     *         }
>>>>>     *         ...
>>>>>     *     }
>>>>> + *
>>>>> + * For mass-conversion use script
>>>>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>>>>     */
>>>>>      #ifndef ERROR_H
>>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>>> index 857f969aa1..047f1b9714 100644
>>>>> --- a/MAINTAINERS
>>>>> +++ b/MAINTAINERS
>>>>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>>>>    F: qapi/error.json
>>>>>    F: util/error.c
>>>>>    F: util/qemu-error.c
>>>>> +F: scripts/coccinelle/*err*.cocci
>>>>>      GDB stub
>>>>>    M: Alex Bennée <alex.bennee@linaro.org>
>>>>
>>
>>
>>  From 42a08c529024337d1b859839c9ce7f797f784555 Mon Sep 17 00:00:00 2001
>> From: Markus Armbruster <armbru@redhat.com>
>> Date: Fri, 13 Mar 2020 14:27:57 +0100
>> Subject: [PATCH] fixup! scripts: Coccinelle script to use
>>   ERRP_AUTO_PROPAGATE()
>>
>> ---
>>   scripts/coccinelle/auto-propagated-errp.cocci | 37 ++++++++++---------
>>   1 file changed, 20 insertions(+), 17 deletions(-)
>>
>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>> index 7dac2dcfa4..43b0b0e63b 100644
>> --- a/scripts/coccinelle/auto-propagated-errp.cocci
>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>> @@ -136,45 +136,48 @@ symbol errp;
>>     // Warn several Error * definitions.
>>   @check1 disable optional_qualifier exists@
>> -identifier fn = rule1.fn, local_err, local_err2;
>> +identifier fn, _errp, local_err, local_err2;
>> +position p1, p2;
>
>
> Hmm, seems like I forget to define ____ as symbol in my patch

Coccinelle defaults to symbol.

>>   @@
>>   - fn(..., Error ** ____, ...)
>> + fn(..., Error **_errp, ...)
>
> Ahmm.. it will break compilation?
>
> Or, how will it work when _errp defined as meta variable is only in "+..." line? Should it be symbol instead, or just not defined?

Misunderstanding?  It's a diff between your .cocci and mine.  My version
is

    // Warn several Error * definitions.
    @check1 disable optional_qualifier exists@
    identifier fn, _errp, local_err, local_err2;
    position p1, p2;
    @@

     fn(..., Error **_errp, ...)
     {
         ...
         Error *local_err = NULL;@p1
         ... when any
         Error *local_err2 = NULL;@p2
         ... when any
     }

    @ script:python @
    fn << check1.fn;
    p1 << check1.p1;
    p2 << check1.p2;
    @@

>>    {
>>        ...
>> -     Error *local_err = NULL;
>> +     Error *local_err = NULL;@p1
>
> Why to do -/+ here? Nothing changed..
>
>>        ... when any
>> -     Error *local_err2 = NULL;
>> +     Error *local_err2 = NULL;@p2
>>        ... when any
>>    }
>>     @ script:python @
>>   fn << check1.fn;
>> +p1 << check1.p1;
>> +p2 << check1.p2;
>>   @@
>>     print('Warning: function {} has several definitions of '
>> -      'Error * local variable'.format(fn))
>> +      'Error * local variable: at {}:{} and then at {}:{}'.format(
>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>     // Warn several propagations in control flow.
>>   @check2 disable optional_qualifier exists@
>> -identifier fn = rule1.fn;
>> -symbol errp;
>> +identifier fn, _errp;
>>   position p1, p2;
>>   @@
>>   - fn(..., Error ** ____, ...)
>> + fn(..., Error **_errp, ...)
>>    {
>>        ...
>>   (
>> -     error_propagate_prepend(errp, ...);@p1
>> +     error_propagate_prepend(_errp, ...);@p1
>>   |
>> -     error_propagate(errp, ...);@p1
>> +     error_propagate(_errp, ...);@p1
>>   )
>>        ...
>>   (
>> -     error_propagate_prepend(errp, ...);@p2
>> +     error_propagate_prepend(_errp, ...);@p2
>>   |
>> -     error_propagate(errp, ...);@p2
>> +     error_propagate(_errp, ...);@p2
>>   )
>
> You change some occurrences of errp to _errp, but not all. It breaks compilation.
>
>>        ... when any
>>    }
>> @@ -198,7 +201,7 @@ print('Warning: function {} propagates to errp several times in '
>>   // the same, just without error_propagate() call), coccinelle fails to
>>   // match this "out: }".
>>   @ disable optional_qualifier@
>> -identifier rule1.fn, rule1.local_err, out;
>> +identifier fn, rule1.local_err, out;
>
> Hmm. If it improves performance it is strange.. But I can live with this change.
>
>>   symbol errp;
>>   @@
>>   @@ -239,7 +242,7 @@ symbol errp;
>>   //        *errp = NULL;
>>   //    }
>>   @ disable optional_qualifier exists@
>> -identifier rule1.fn, rule1.local_err;
>> +identifier fn, rule1.local_err;
>>   expression list args;
>>   symbol errp;
>>   @@
>> @@ -287,7 +290,7 @@ symbol errp;
>>   // previous hunk, as this conflicts with other substitutions in it (at
>>   // least with "- local_err = NULL").
>>   @ disable optional_qualifier@
>> -identifier rule1.fn, rule1.local_err;
>> +identifier fn, rule1.local_err;
>>   symbol errp;
>>   @@
>>   @@ -301,7 +304,7 @@ symbol errp;
>>     // Always use the same pattern for checking error
>>   @ disable optional_qualifier@
>> -identifier rule1.fn;
>> +identifier fn;
>>   symbol errp;
>>   @@
>>   @@ -315,7 +318,7 @@ symbol errp;
>>     // Revert temporary ___ identifier.
>>   @ disable optional_qualifier@
>> -identifier rule1.fn;
>> +identifier fn;
>>   @@
>>      fn(..., Error **
>>

I append my hacked up version of auto-propagated-errp.cocci.  It
produces the same patch as yours for the complete tree.



// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
//
// Copyright (c) 2020 Virtuozzo International GmbH.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see
// <http://www.gnu.org/licenses/>.
//
// Usage example:
// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
//  --macro-file scripts/cocci-macro-file.h --in-place \
//  --no-show-diff --max-width 80 FILES...
//
// Note: --max-width 80 is needed because coccinelle default is less
// than 80, and without this parameter coccinelle may reindent some
// lines which fit into 80 characters but not to coccinelle default,
// which in turn produces extra patch hunks for no reason.

// Switch unusual Error ** parameter names to errp
// (this is necessary to use ERRP_AUTO_PROPAGATE).
//
// Disable optional_qualifier to skip functions with
// "Error *const *errp" parameter.
//
// Skip functions with "assert(_errp && *_errp)" statement, because
// that signals unusual semantics, and the parameter name may well
// serve a purpose. (like nbd_iter_channel_error()).
//
// Skip util/error.c to not touch, for example, error_propagate() and
// error_propagate_prepend().
@ depends on !(file in "util/error.c") disable optional_qualifier@
identifier fn;
identifier _errp != errp;
@@

 fn(...,
-   Error **_errp
+   Error **errp
    ,...)
 {
(
     ... when != assert(_errp && *_errp)
&
     <...
-    _errp
+    errp
     ...>
)
 }

// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
// necessary
//
// Note, that without "when any" the final "..." does not mach
// something matched by previous pattern, i.e. the rule will not match
// double error_prepend in control flow like in
// vfio_set_irq_signaling().
//
// Note, "exists" says that we want apply rule even if it matches not
// on all possible control flows (otherwise, it will not match
// standard pattern when error_propagate() call is in if branch).
@ disable optional_qualifier exists@
identifier fn, local_err;
symbol errp;
@@

 fn(..., Error **errp, ...)
 {
+   ERRP_AUTO_PROPAGATE();
    ...  when != ERRP_AUTO_PROPAGATE();
(
(
    error_append_hint(errp, ...);
|
    error_prepend(errp, ...);
|
    error_vprepend(errp, ...);
)
    ... when any
|
    Error *local_err = NULL;
    ...
(
    error_propagate_prepend(errp, local_err, ...);
|
    error_propagate(errp, local_err);
)
    ...
)
 }


// Match functions with propagation of local error to errp.
// We want to refer these functions in several following rules, but I
// don't know a proper way to inherit a function, not just its name
// (to not match another functions with same name in following rules).
// Not-proper way is as follows: rename errp parameter in functions
// header and match it in following rules. Rename it back after all
// transformations.
//
// The simplest case of propagation scheme is single definition of
// local_err with at most one error_propagate_prepend or
// error_propagate on each control-flow. Still, we want to match more
// complex schemes too. We'll warn them with help of further rules.
@rule1 disable optional_qualifier exists@
identifier fn, local_err;
symbol errp;
@@

 fn(..., Error **
-    errp
+    ____
    , ...)
 {
     ...
     Error *local_err = NULL;
     ...
(
     error_propagate_prepend(errp, local_err, ...);
|
     error_propagate(errp, local_err);
)
     ...
 }


// Warn several Error * definitions.
@check1 disable optional_qualifier exists@
identifier fn, _errp, local_err, local_err2;
position p1, p2;
@@

 fn(..., Error **_errp, ...)
 {
     ...
     Error *local_err = NULL;@p1
     ... when any
     Error *local_err2 = NULL;@p2
     ... when any
 }

@ script:python @
fn << check1.fn;
p1 << check1.p1;
p2 << check1.p2;
@@

print('Warning: function {} has several definitions of '
      'Error * local variable: at {}:{} and then at {}:{}'.format(
          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))

// Warn several propagations in control flow.
@check2 disable optional_qualifier exists@
identifier fn, _errp;
position p1, p2;
@@

 fn(..., Error **_errp, ...)
 {
     ...
(
     error_propagate_prepend(_errp, ...);@p1
|
     error_propagate(_errp, ...);@p1
)
     ...
(
     error_propagate_prepend(_errp, ...);@p2
|
     error_propagate(_errp, ...);@p2
)
     ... when any
 }

@ script:python @
fn << check2.fn;
p1 << check2.p1;
p2 << check2.p2;
@@

print('Warning: function {} propagates to errp several times in '
      'one control flow: at {}:{} and then at {}:{}'.format(
          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))

// Convert special case with goto separately.
// I tried merging this into the following rule the obvious way, but
// it made Coccinelle hang on block.c
//
// Note interesting thing: if we don't do it here, and try to fixup
// "out: }" things later after all transformations (the rule will be
// the same, just without error_propagate() call), coccinelle fails to
// match this "out: }".
@ disable optional_qualifier@
identifier fn, rule1.local_err, out;
symbol errp;
@@

 fn(..., Error ** ____, ...)
 {
     <...
-    goto out;
+    return;
     ...>
- out:
-    error_propagate(errp, local_err);
 }

// Convert most of local_err related stuff.
//
// Note, that we update everything related to matched by rule1
// function name and local_err name. We may match something not
// related to the pattern matched by rule1. For example, local_err may
// be defined with the same name in different blocks inside one
// function, and in one block follow the propagation pattern and in
// other block doesn't. Or we may have several functions with the same
// name (for different configurations).
//
// Note also that errp-cleaning functions
//   error_free_errp
//   error_report_errp
//   error_reportf_errp
//   warn_report_errp
//   warn_reportf_errp
// are not yet implemented. They must call corresponding Error* -
// freeing function and then set *errp to NULL, to avoid further
// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
// For example, error_free_errp may look like this:
//
//    void error_free_errp(Error **errp)
//    {
//        error_free(*errp);
//        *errp = NULL;
//    }
@ disable optional_qualifier exists@
identifier fn, rule1.local_err;
expression list args;
symbol errp;
@@

 fn(..., Error ** ____, ...)
 {
     <...
(
-    Error *local_err = NULL;
|

// Convert error clearing functions
(
-    error_free(local_err);
+    error_free_errp(errp);
|
-    error_report_err(local_err);
+    error_report_errp(errp);
|
-    error_reportf_err(local_err, args);
+    error_reportf_errp(errp, args);
|
-    warn_report_err(local_err);
+    warn_report_errp(errp);
|
-    warn_reportf_err(local_err, args);
+    warn_reportf_errp(errp, args);
)
?-    local_err = NULL;

|
-    error_propagate_prepend(errp, local_err, args);
+    error_prepend(errp, args);
|
-    error_propagate(errp, local_err);
|
-    &local_err
+    errp
)
     ...>
 }

// Convert remaining local_err usage. For example, different kinds of
// error checking in if conditionals. We can't merge this into
// previous hunk, as this conflicts with other substitutions in it (at
// least with "- local_err = NULL").
@ disable optional_qualifier@
identifier fn, rule1.local_err;
symbol errp;
@@

 fn(..., Error ** ____, ...)
 {
     <...
-    local_err
+    *errp
     ...>
 }

// Always use the same pattern for checking error
@ disable optional_qualifier@
identifier fn;
symbol errp;
@@

 fn(..., Error ** ____, ...)
 {
     <...
-    *errp != NULL
+    *errp
     ...>
 }

// Revert temporary ___ identifier.
@ disable optional_qualifier@
identifier fn;
@@

 fn(..., Error **
-   ____
+   errp
    , ...)
 {
     ...
 }



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-13 21:54             ` Markus Armbruster
  0 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-13 21:54 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	qemu-devel, Laszlo Ersek, Christian Schoenebeck,
	Markus Armbruster, Michael Roth, Greg Kurz, Gerd Hoffmann,
	Stefan Hajnoczi, Anthony Perard, xen-devel, Max Reitz,
	Philippe Mathieu-Daudé,
	Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 13.03.2020 18:42, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>
>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>> out now as is.
>>>>
>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>
>>>>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>>>>> does corresponding changes in code (look for details in
>>>>> include/qapi/error.h)
>>>>>
>>>>> Usage example:
>>>>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>    --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>>>>    --max-width 80 FILES...
>>>>>
>>>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>>>> ---
>>>>>
>>>>> Cc: Eric Blake <eblake@redhat.com>
>>>>> Cc: Kevin Wolf <kwolf@redhat.com>
>>>>> Cc: Max Reitz <mreitz@redhat.com>
>>>>> Cc: Greg Kurz <groug@kaod.org>
>>>>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>>>>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>>>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>>>> Cc: Paul Durrant <paul@xen.org>
>>>>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>>>>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>>>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>>>>> Cc: Markus Armbruster <armbru@redhat.com>
>>>>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>>>>> Cc: qemu-devel@nongnu.org
>>>>> Cc: qemu-block@nongnu.org
>>>>> Cc: xen-devel@lists.xenproject.org
>>>>>
>>>>>    scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>>>>    include/qapi/error.h                          |   3 +
>>>>>    MAINTAINERS                                   |   1 +
>>>>>    3 files changed, 331 insertions(+)
>>>>>    create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>>>>
>>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>> new file mode 100644
>>>>> index 0000000000..7dac2dcfa4
>>>>> --- /dev/null
>>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>> @@ -0,0 +1,327 @@
>>>>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>>>> +//
>>>>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>>>>> +//
>>>>> +// This program is free software; you can redistribute it and/or
>>>>> +// modify it under the terms of the GNU General Public License as
>>>>> +// published by the Free Software Foundation; either version 2 of the
>>>>> +// License, or (at your option) any later version.
>>>>> +//
>>>>> +// This program is distributed in the hope that it will be useful,
>>>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>>> +// GNU General Public License for more details.
>>>>> +//
>>>>> +// You should have received a copy of the GNU General Public License
>>>>> +// along with this program.  If not, see
>>>>> +// <http://www.gnu.org/licenses/>.
>>>>> +//
>>>>> +// Usage example:
>>>>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>>>>> +//  --no-show-diff --max-width 80 FILES...
>>>>> +//
>>>>> +// Note: --max-width 80 is needed because coccinelle default is less
>>>>> +// than 80, and without this parameter coccinelle may reindent some
>>>>> +// lines which fit into 80 characters but not to coccinelle default,
>>>>> +// which in turn produces extra patch hunks for no reason.
>>>>
>>>> This is about unwanted reformatting of parameter lists due to the ___
>>>> chaining hack.  --max-width 80 makes that less likely, but not
>>>> impossible.
>>>>
>>>> We can search for unwanted reformatting of parameter lists.  I think
>>>> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
>>>> tree, I get one false positive (not a parameter list), and one hit:
>>>>
>>>>       @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>>>>            }
>>>>        }
>>>>
>>>>       -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>>>>       +void object_apply_global_props(Object *obj, const GPtrArray *props,
>>>>       +                               Error **errp)
>>>>        {
>>>>       +    ERRP_AUTO_PROPAGATE();
>>>>            int i;
>>>>
>>>>            if (!props) {
>>>>
>>>> Reformatting, but not unwanted.
>>>
>>> Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
>>> ERRP_AUTO_PROPAGATE addition even for non-automatic patch.
>>
>> Agree.
>>
>>>>
>>>> The --max-width 80 hack is good enough for me.
>>>>
>>>> It does result in slightly long transformed lines, e.g. this one in
>>>> replication.c:
>>>>
>>>>       @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>>>>                s->mode = REPLICATION_MODE_PRIMARY;
>>>>                top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>>>>                if (top_id) {
>>>>       -            error_setg(&local_err, "The primary side does not support option top-id");
>>>>       +            error_setg(errp, "The primary side does not support option top-id");
>>>>                    goto fail;
>>>>                }
>>>>            } else if (!strcmp(mode, "secondary")) {
>>>>
>>>> v8 did break this line (that's how I found it).  However, v9 still
>>>> shortens the line, just not below the target.  All your + lines look
>>>> quite unlikely to lengthen lines.  Let's not worry about this.
>>>>
>>>>> +// Switch unusual Error ** parameter names to errp
>>>>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>>>>> +//
>>>>> +// Disable optional_qualifier to skip functions with
>>>>> +// "Error *const *errp" parameter.
>>>>> +//
>>>>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>>>>> +// that signals unusual semantics, and the parameter name may well
>>>>> +// serve a purpose. (like nbd_iter_channel_error()).
>>>>> +//
>>>>> +// Skip util/error.c to not touch, for example, error_propagate() and
>>>>> +// error_propagate_prepend().
>>>>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>>>>> +identifier fn;
>>>>> +identifier _errp != errp;
>>>>> +@@
>>>>> +
>>>>> + fn(...,
>>>>> +-   Error **_errp
>>>>> ++   Error **errp
>>>>> +    ,...)
>>>>> + {
>>>>> +(
>>>>> +     ... when != assert(_errp && *_errp)
>>>>> +&
>>>>> +     <...
>>>>> +-    _errp
>>>>> ++    errp
>>>>> +     ...>
>>>>> +)
>>>>> + }
>>>>> +
>>>>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>>>> +// necessary
>>>>> +//
>>>>> +// Note, that without "when any" the final "..." does not mach
>>>>> +// something matched by previous pattern, i.e. the rule will not match
>>>>> +// double error_prepend in control flow like in
>>>>> +// vfio_set_irq_signaling().
>>>>> +//
>>>>> +// Note, "exists" says that we want apply rule even if it matches not
>>>>> +// on all possible control flows (otherwise, it will not match
>>>>> +// standard pattern when error_propagate() call is in if branch).
>>>>> +@ disable optional_qualifier exists@
>>>>> +identifier fn, local_err;
>>>>> +symbol errp;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error **errp, ...)
>>>>> + {
>>>>> ++   ERRP_AUTO_PROPAGATE();
>>>>> +    ...  when != ERRP_AUTO_PROPAGATE();
>>>>> +(
>>>>> +(
>>>>> +    error_append_hint(errp, ...);
>>>>> +|
>>>>> +    error_prepend(errp, ...);
>>>>> +|
>>>>> +    error_vprepend(errp, ...);
>>>>> +)
>>>>> +    ... when any
>>>>> +|
>>>>> +    Error *local_err = NULL;
>>>>> +    ...
>>>>> +(
>>>>> +    error_propagate_prepend(errp, local_err, ...);
>>>>> +|
>>>>> +    error_propagate(errp, local_err);
>>>>> +)
>>>>> +    ...
>>>>> +)
>>>>> + }
>>>>> +
>>>>> +
>>>>> +// Match functions with propagation of local error to errp.
>>>>> +// We want to refer these functions in several following rules, but I
>>>>> +// don't know a proper way to inherit a function, not just its name
>>>>> +// (to not match another functions with same name in following rules).
>>>>> +// Not-proper way is as follows: rename errp parameter in functions
>>>>> +// header and match it in following rules. Rename it back after all
>>>>> +// transformations.
>>>>> +//
>>>>> +// The simplest case of propagation scheme is single definition of
>>>>> +// local_err with at most one error_propagate_prepend or
>>>>> +// error_propagate on each control-flow. Still, we want to match more
>>>>> +// complex schemes too. We'll warn them with help of further rules.
>>>>
>>>> I think what we actually want is to examine instances of this pattern to
>>>> figure out whether and how we want to transform them.  Perhaps:
>>>>
>>>>       // The common case is a single definition of local_err with at most one
>>>>       // error_propagate_prepend() or error_propagate() on each control-flow
>>>>       // path. Instances of this case we convert with this script. Functions
>>>
>>> For me, sounds a bit like "other things we don't convert".
>>> Actually we convert other things too.
>>
>> What other patterns of error propagation do we convert?
>
> Something like in xen_block_device_destroy, why not? Otherwise, it's better to avoid
> matching things like xen_block_device_destroy, not just warn them.
> But I'd prefer to proceed now as is to fit into 5.0.. Too much time already
> spent on this. So, I'm OK with your wording too.

Let's scratch "Instances of this case we convert with this script."

>>>>       // with multiple definitions or propagates we want to examine
>>>>       // manually. Later rules emit warnings to guide us to them.
>>>>
>>>>> +@rule1 disable optional_qualifier exists@
>>>>> +identifier fn, local_err;
>>>>> +symbol errp;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error **
>>>>> +-    errp
>>>>> ++    ____
>>>>> +    , ...)
>>>>> + {
>>>>> +     ...
>>>>> +     Error *local_err = NULL;
>>>>> +     ...
>>>>> +(
>>>>> +     error_propagate_prepend(errp, local_err, ...);
>>>>> +|
>>>>> +     error_propagate(errp, local_err);
>>>>> +)
>>>>> +     ...
>>>>> + }
>>>>> +
>>>>> +
>>>>> +// Warn several Error * definitions.
>>>>> +@check1 disable optional_qualifier exists@
>>>>> +identifier fn = rule1.fn, local_err, local_err2;
>>>>
>>>> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
>>>> particular reason for the difference?
>>>
>>> I didn't find other way to ref check1.fn in next python rule. It just don't
>>> work if I write here just rule1.fn.
>>>
>>>>
>>>> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
>>>> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
>>>> everywhere, then apply the script to the complete tree, I get the same
>>>> result.
>>>
>>> I think, it's more efficient to reuse names from previous rules. I think it should
>>> work faster (more information, less extra matching).
>>
>> Nope.  With my hacked up script (patch appended) Coccinelle is actually
>> *faster* for the .[ch] touched by this series: with your unmodified
>> script, it takes a bit over 12s on my box, with mine around 7s.  Output
>> is identical.
>>
>> Never guess performance, always measure it :)
>
> Hmm, whole tree results would be better proof
>
>>
>> Two notes on my script:
>>
>> * Unlike yours, it recognizes double-propagation in my test case.
>>    Discussed below.
>>
>> * Its "several definitions of" warning includes positions.  That turned
>>    out to be useless, but I've been too lazy to take that out again.
>>
>>>>
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error ** ____, ...)
>>>>> + {
>>>>> +     ...
>>>>> +     Error *local_err = NULL;
>>>>> +     ... when any
>>>>> +     Error *local_err2 = NULL;
>>>>> +     ... when any
>>>>> + }

This flags functions that have more than one declaration along any
control flow path.  It doesn't flag this one:

    void gnat(bool b, Error **errp)
    {
        if (b) {
            Error *local_err = NULL;
            foo(arg, &local_err);
            error_propagate(errp, local_err);
        } else {
            Error *local_err = NULL;
            bar(arg, &local_err);
            error_propagate(errp, local_err);
        }
    }

The Coccinelle script does the right thing for this one regardless.

I'd prefer to have such functions flagged, too.  But spending time on
convincing Coccinelle to do it for me is not worthwhile; I can simply
search the diff produced by Coccinelle for deletions of declarations
that are not indented exactly four spaces.

But if we keep this rule, we should adjust its comment

    // Warn several Error * definitions.

because it sure suggests it also catches functions like the one I gave
above.

>>>>> +
>>>>> +@ script:python @
>>>>> +fn << check1.fn;
>>>>> +@@
>>>>> +
>>>>> +print('Warning: function {} has several definitions of '
>>>>> +      'Error * local variable'.format(fn))
>>>>> +
>>>>> +// Warn several propagations in control flow.
>>>>> +@check2 disable optional_qualifier exists@
>>>>> +identifier fn = rule1.fn;
>>>>> +symbol errp;
>>>>> +position p1, p2;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error ** ____, ...)
>>>>> + {
>>>>> +     ...
>>>>> +(
>>>>> +     error_propagate_prepend(errp, ...);@p1
>>>>> +|
>>>>> +     error_propagate(errp, ...);@p1
>>>>> +)
>>>>> +     ...
>>>>> +(
>>>>> +     error_propagate_prepend(errp, ...);@p2
>>>>> +|
>>>>> +     error_propagate(errp, ...);@p2
>>>>> +)
>>>>> +     ... when any
>>>>> + }
>>>>> +
>>>>
>>>> Hmm, we don't catch the example I used in review of v8:
>>>>
>>>>       extern foo(int, Error **);
>>>>       extern bar(int, Error **);
>>>>
>>>>       void frob(Error **errp)
>>>>       {
>>>>           Error *local_err = NULL;
>>>>           int arg;
>>>>
>>>>           foo(arg, errp);
>>>>           bar(arg, &local_err);
>>>>           error_propagate(errp, local_err);
>>>>           bar(arg + 1, &local_err);
>>>>           error_propagate(errp, local_err);
>>>>       }
>>>>
>>>> I believe this is because rule1 does not match here.
>>>
>>> Yes, rule1 wants at least one code flow with non-doubled propagation.
>>>
>>>>
>>>> If I change the rule as follows, it catches the example:
>>>>
>>>>       @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
>>>>
>>>>        // Warn several propagations in control flow.
>>>>        @check2 disable optional_qualifier exists@
>>>>       -identifier fn = rule1.fn;
>>>>       -symbol errp;
>>>>       +identifier fn, _errp;
>>>>        position p1, p2;
>>>>        @@
>>>>
>>>>       - fn(..., Error ** ____, ...)
>>>>       + fn(..., Error **_errp, ...)
>>>>         {
>>>>             ...
>>>>        (
>>>>       -     error_propagate_prepend(errp, ...);@p1
>>>>       +     error_propagate_prepend(_errp, ...);@p1
>>>>        |
>>>>       -     error_propagate(errp, ...);@p1
>>>>       +     error_propagate(_errp, ...);@p1
>>>>        )
>>>>             ...
>>>>        (
>>>>       -     error_propagate_prepend(errp, ...);@p2
>>>>       +     error_propagate_prepend(_errp, ...);@p2
>>>>        |
>>>>       -     error_propagate(errp, ...);@p2
>>>>       +     error_propagate(_errp, ...);@p2
>>>>        )
>>>>             ... when any
>>>>         }
>>>>
>>>> To my mild surprise, it still doesn't find anything in our tree.
>>>>
>>>> Should we decouple the previous rule from rule1, too?  I tested the
>>>> following on the whole tree:
>>>
>>> I don't think so. Why to check what we are not going to convert? If we want
>>> to check side things, it's better to do it in other coccinelle script..
>>
>> Misunderstanding?  The rules are still chained together via the ___
>> hack, just not via function name, because that's unreliable and
>> redundant.
>
> Strange.. Then, how can it match something not matched by rule1?

I think I got confused when I wrote the "Misunderstanding?" paragraph.

Let me try again.

First rule check2.

The common case is a at most one propagation to @errp along any control
flow path.  We trust your Coccinelle script to convert that alright.

Any other propagation to @errp I want to review.  Whether the script
attempts a conversion or not is unimportant, as long as it points me to
the function to review.

Rule rule1 matches functions that propagate to @errp once along at least
one control flow path.

Unchained from rule rule1, rule check2 flags any function that
propagates to @errp multiple times along any control flow path.

Chained to rule1, it flags only functions that also have a path with
single propagation.

In other words, the unchained rule flags *all* multi-propagations to
@errp, while the chained rule flags only the ones the script attempts to
convert.  The former is much more useful to me.

Now rule check1.  It flags functions with multiple declarations along
any control flow path.  Again, chaining it to rule1 restricts it to the
functions we attempt to convert.  Makes it less useful to me.  However,
because my desire to review multiple declarations in function we don't
attempt to convert is lower than my desire to review multiple
propagations to @errp in such functions, chaining check1 is tolerable
for me.  But why chain check1 if we don't chain check2?

>
>>
>>>>
>>>>       @@ -136,10 +136,10 @@ symbol errp;
>>>>
>>>>        // Warn several Error * definitions.
>>>>        @check1 disable optional_qualifier exists@
>>>>       -identifier fn = rule1.fn, local_err, local_err2;
>>>>       +identifier fn, _errp, local_err, local_err2;
>>>>        @@
>>>>
>>>>       - fn(..., Error ** ____, ...)
>>>>       + fn(..., Error **_errp, ...)
>>>>         {
>>>>             ...
>>>>             Error *local_err = NULL;
>>>>
>>>> Warnings remain unchanged.
>>>>
>>>>> +@ script:python @
>>>>> +fn << check2.fn;
>>>>> +p1 << check2.p1;
>>>>> +p2 << check2.p2;
>>>>> +@@
>>>>> +
>>>>> +print('Warning: function {} propagates to errp several times in '
>>>>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>>> +
>>>>> +// Convert special case with goto separately.
>>>>> +// I tried merging this into the following rule the obvious way, but
>>>>> +// it made Coccinelle hang on block.c
>>>>> +//
>>>>> +// Note interesting thing: if we don't do it here, and try to fixup
>>>>> +// "out: }" things later after all transformations (the rule will be
>>>>> +// the same, just without error_propagate() call), coccinelle fails to
>>>>> +// match this "out: }".
>>>>> +@ disable optional_qualifier@
>>>>> +identifier rule1.fn, rule1.local_err, out;
>>>>
>>>> As explained above, I doubt the need for rule1.fn.  We do need
>>>> rule1.local_err to avoid unwanted transformations.  More of the same
>>>> below.
>>>
>>> Logically, I want to inherit from rule1. So why not to stress it by inheriting
>>> fn variable? It's just a correct thing to do.
>>> And I hope it helps coccinelle to work more efficiently.
>>>
>>>>
>>>>> +symbol errp;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error ** ____, ...)
>>>>> + {
>>>>> +     <...
>>>>> +-    goto out;
>>>>> ++    return;
>>>>> +     ...>
>>>>> +- out:
>>>>> +-    error_propagate(errp, local_err);
>>>>> + }
>>>>> +
>>>>> +// Convert most of local_err related stuff.
>>>>> +//
>>>>> +// Note, that we update everything related to matched by rule1
>>>>> +// function name and local_err name. We may match something not
>>>>> +// related to the pattern matched by rule1. For example, local_err may
>>>>> +// be defined with the same name in different blocks inside one
>>>>> +// function, and in one block follow the propagation pattern and in
>>>>> +// other block doesn't. Or we may have several functions with the same
>>>>> +// name (for different configurations).
>>>>> +//
>>>>> +// Note also that errp-cleaning functions
>>>>> +//   error_free_errp
>>>>> +//   error_report_errp
>>>>> +//   error_reportf_errp
>>>>> +//   warn_report_errp
>>>>> +//   warn_reportf_errp
>>>>> +// are not yet implemented. They must call corresponding Error* -
>>>>> +// freeing function and then set *errp to NULL, to avoid further
>>>>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>>>> +// For example, error_free_errp may look like this:
>>>>> +//
>>>>> +//    void error_free_errp(Error **errp)
>>>>> +//    {
>>>>> +//        error_free(*errp);
>>>>> +//        *errp = NULL;
>>>>> +//    }
>>>>> +@ disable optional_qualifier exists@
>>>>> +identifier rule1.fn, rule1.local_err;
>>>>> +expression list args;
>>>>> +symbol errp;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error ** ____, ...)
>>>>> + {
>>>>> +     <...
>>>>> +(
>>>>> +-    Error *local_err = NULL;
>>>>> +|
>>>>> +
>>>>> +// Convert error clearing functions
>>>>> +(
>>>>> +-    error_free(local_err);
>>>>> ++    error_free_errp(errp);
>>>>> +|
>>>>> +-    error_report_err(local_err);
>>>>> ++    error_report_errp(errp);
>>>>> +|
>>>>> +-    error_reportf_err(local_err, args);
>>>>> ++    error_reportf_errp(errp, args);
>>>>> +|
>>>>> +-    warn_report_err(local_err);
>>>>> ++    warn_report_errp(errp);
>>>>> +|
>>>>> +-    warn_reportf_err(local_err, args);
>>>>> ++    warn_reportf_errp(errp, args);
>>>>> +)
>>>>> +?-    local_err = NULL;
>>>>> +
>>>>> +|
>>>>> +-    error_propagate_prepend(errp, local_err, args);
>>>>> ++    error_prepend(errp, args);
>>>>> +|
>>>>> +-    error_propagate(errp, local_err);
>>>>> +|
>>>>> +-    &local_err
>>>>> ++    errp
>>>>> +)
>>>>> +     ...>
>>>>> + }
>>>>> +
>>>>> +// Convert remaining local_err usage. For example, different kinds of
>>>>> +// error checking in if conditionals. We can't merge this into
>>>>> +// previous hunk, as this conflicts with other substitutions in it (at
>>>>> +// least with "- local_err = NULL").
>>>>> +@ disable optional_qualifier@
>>>>> +identifier rule1.fn, rule1.local_err;
>>>>> +symbol errp;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error ** ____, ...)
>>>>> + {
>>>>> +     <...
>>>>> +-    local_err
>>>>> ++    *errp
>>>>> +     ...>
>>>>> + }
>>>>> +
>>>>> +// Always use the same pattern for checking error
>>>>> +@ disable optional_qualifier@
>>>>> +identifier rule1.fn;
>>>>> +symbol errp;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error ** ____, ...)
>>>>> + {
>>>>> +     <...
>>>>> +-    *errp != NULL
>>>>> ++    *errp
>>>>> +     ...>
>>>>> + }
>>>>> +
>>>>> +// Revert temporary ___ identifier.
>>>>> +@ disable optional_qualifier@
>>>>> +identifier rule1.fn;
>>>>> +@@
>>>>> +
>>>>> + fn(..., Error **
>>>>> +-   ____
>>>>> ++   errp
>>>>> +    , ...)
>>>>> + {
>>>>> +     ...
>>>>> + }
>>>>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>>>>> index 30140d9bfe..56c133520d 100644
>>>>> --- a/include/qapi/error.h
>>>>> +++ b/include/qapi/error.h
>>>>> @@ -214,6 +214,9 @@
>>>>>     *         }
>>>>>     *         ...
>>>>>     *     }
>>>>> + *
>>>>> + * For mass-conversion use script
>>>>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>>>>     */
>>>>>      #ifndef ERROR_H
>>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>>> index 857f969aa1..047f1b9714 100644
>>>>> --- a/MAINTAINERS
>>>>> +++ b/MAINTAINERS
>>>>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>>>>    F: qapi/error.json
>>>>>    F: util/error.c
>>>>>    F: util/qemu-error.c
>>>>> +F: scripts/coccinelle/*err*.cocci
>>>>>      GDB stub
>>>>>    M: Alex Bennée <alex.bennee@linaro.org>
>>>>
>>
>>
>>  From 42a08c529024337d1b859839c9ce7f797f784555 Mon Sep 17 00:00:00 2001
>> From: Markus Armbruster <armbru@redhat.com>
>> Date: Fri, 13 Mar 2020 14:27:57 +0100
>> Subject: [PATCH] fixup! scripts: Coccinelle script to use
>>   ERRP_AUTO_PROPAGATE()
>>
>> ---
>>   scripts/coccinelle/auto-propagated-errp.cocci | 37 ++++++++++---------
>>   1 file changed, 20 insertions(+), 17 deletions(-)
>>
>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>> index 7dac2dcfa4..43b0b0e63b 100644
>> --- a/scripts/coccinelle/auto-propagated-errp.cocci
>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>> @@ -136,45 +136,48 @@ symbol errp;
>>     // Warn several Error * definitions.
>>   @check1 disable optional_qualifier exists@
>> -identifier fn = rule1.fn, local_err, local_err2;
>> +identifier fn, _errp, local_err, local_err2;
>> +position p1, p2;
>
>
> Hmm, seems like I forget to define ____ as symbol in my patch

Coccinelle defaults to symbol.

>>   @@
>>   - fn(..., Error ** ____, ...)
>> + fn(..., Error **_errp, ...)
>
> Ahmm.. it will break compilation?
>
> Or, how will it work when _errp defined as meta variable is only in "+..." line? Should it be symbol instead, or just not defined?

Misunderstanding?  It's a diff between your .cocci and mine.  My version
is

    // Warn several Error * definitions.
    @check1 disable optional_qualifier exists@
    identifier fn, _errp, local_err, local_err2;
    position p1, p2;
    @@

     fn(..., Error **_errp, ...)
     {
         ...
         Error *local_err = NULL;@p1
         ... when any
         Error *local_err2 = NULL;@p2
         ... when any
     }

    @ script:python @
    fn << check1.fn;
    p1 << check1.p1;
    p2 << check1.p2;
    @@

>>    {
>>        ...
>> -     Error *local_err = NULL;
>> +     Error *local_err = NULL;@p1
>
> Why to do -/+ here? Nothing changed..
>
>>        ... when any
>> -     Error *local_err2 = NULL;
>> +     Error *local_err2 = NULL;@p2
>>        ... when any
>>    }
>>     @ script:python @
>>   fn << check1.fn;
>> +p1 << check1.p1;
>> +p2 << check1.p2;
>>   @@
>>     print('Warning: function {} has several definitions of '
>> -      'Error * local variable'.format(fn))
>> +      'Error * local variable: at {}:{} and then at {}:{}'.format(
>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>     // Warn several propagations in control flow.
>>   @check2 disable optional_qualifier exists@
>> -identifier fn = rule1.fn;
>> -symbol errp;
>> +identifier fn, _errp;
>>   position p1, p2;
>>   @@
>>   - fn(..., Error ** ____, ...)
>> + fn(..., Error **_errp, ...)
>>    {
>>        ...
>>   (
>> -     error_propagate_prepend(errp, ...);@p1
>> +     error_propagate_prepend(_errp, ...);@p1
>>   |
>> -     error_propagate(errp, ...);@p1
>> +     error_propagate(_errp, ...);@p1
>>   )
>>        ...
>>   (
>> -     error_propagate_prepend(errp, ...);@p2
>> +     error_propagate_prepend(_errp, ...);@p2
>>   |
>> -     error_propagate(errp, ...);@p2
>> +     error_propagate(_errp, ...);@p2
>>   )
>
> You change some occurrences of errp to _errp, but not all. It breaks compilation.
>
>>        ... when any
>>    }
>> @@ -198,7 +201,7 @@ print('Warning: function {} propagates to errp several times in '
>>   // the same, just without error_propagate() call), coccinelle fails to
>>   // match this "out: }".
>>   @ disable optional_qualifier@
>> -identifier rule1.fn, rule1.local_err, out;
>> +identifier fn, rule1.local_err, out;
>
> Hmm. If it improves performance it is strange.. But I can live with this change.
>
>>   symbol errp;
>>   @@
>>   @@ -239,7 +242,7 @@ symbol errp;
>>   //        *errp = NULL;
>>   //    }
>>   @ disable optional_qualifier exists@
>> -identifier rule1.fn, rule1.local_err;
>> +identifier fn, rule1.local_err;
>>   expression list args;
>>   symbol errp;
>>   @@
>> @@ -287,7 +290,7 @@ symbol errp;
>>   // previous hunk, as this conflicts with other substitutions in it (at
>>   // least with "- local_err = NULL").
>>   @ disable optional_qualifier@
>> -identifier rule1.fn, rule1.local_err;
>> +identifier fn, rule1.local_err;
>>   symbol errp;
>>   @@
>>   @@ -301,7 +304,7 @@ symbol errp;
>>     // Always use the same pattern for checking error
>>   @ disable optional_qualifier@
>> -identifier rule1.fn;
>> +identifier fn;
>>   symbol errp;
>>   @@
>>   @@ -315,7 +318,7 @@ symbol errp;
>>     // Revert temporary ___ identifier.
>>   @ disable optional_qualifier@
>> -identifier rule1.fn;
>> +identifier fn;
>>   @@
>>      fn(..., Error **
>>

I append my hacked up version of auto-propagated-errp.cocci.  It
produces the same patch as yours for the complete tree.



// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
//
// Copyright (c) 2020 Virtuozzo International GmbH.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see
// <http://www.gnu.org/licenses/>.
//
// Usage example:
// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
//  --macro-file scripts/cocci-macro-file.h --in-place \
//  --no-show-diff --max-width 80 FILES...
//
// Note: --max-width 80 is needed because coccinelle default is less
// than 80, and without this parameter coccinelle may reindent some
// lines which fit into 80 characters but not to coccinelle default,
// which in turn produces extra patch hunks for no reason.

// Switch unusual Error ** parameter names to errp
// (this is necessary to use ERRP_AUTO_PROPAGATE).
//
// Disable optional_qualifier to skip functions with
// "Error *const *errp" parameter.
//
// Skip functions with "assert(_errp && *_errp)" statement, because
// that signals unusual semantics, and the parameter name may well
// serve a purpose. (like nbd_iter_channel_error()).
//
// Skip util/error.c to not touch, for example, error_propagate() and
// error_propagate_prepend().
@ depends on !(file in "util/error.c") disable optional_qualifier@
identifier fn;
identifier _errp != errp;
@@

 fn(...,
-   Error **_errp
+   Error **errp
    ,...)
 {
(
     ... when != assert(_errp && *_errp)
&
     <...
-    _errp
+    errp
     ...>
)
 }

// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
// necessary
//
// Note, that without "when any" the final "..." does not mach
// something matched by previous pattern, i.e. the rule will not match
// double error_prepend in control flow like in
// vfio_set_irq_signaling().
//
// Note, "exists" says that we want apply rule even if it matches not
// on all possible control flows (otherwise, it will not match
// standard pattern when error_propagate() call is in if branch).
@ disable optional_qualifier exists@
identifier fn, local_err;
symbol errp;
@@

 fn(..., Error **errp, ...)
 {
+   ERRP_AUTO_PROPAGATE();
    ...  when != ERRP_AUTO_PROPAGATE();
(
(
    error_append_hint(errp, ...);
|
    error_prepend(errp, ...);
|
    error_vprepend(errp, ...);
)
    ... when any
|
    Error *local_err = NULL;
    ...
(
    error_propagate_prepend(errp, local_err, ...);
|
    error_propagate(errp, local_err);
)
    ...
)
 }


// Match functions with propagation of local error to errp.
// We want to refer these functions in several following rules, but I
// don't know a proper way to inherit a function, not just its name
// (to not match another functions with same name in following rules).
// Not-proper way is as follows: rename errp parameter in functions
// header and match it in following rules. Rename it back after all
// transformations.
//
// The simplest case of propagation scheme is single definition of
// local_err with at most one error_propagate_prepend or
// error_propagate on each control-flow. Still, we want to match more
// complex schemes too. We'll warn them with help of further rules.
@rule1 disable optional_qualifier exists@
identifier fn, local_err;
symbol errp;
@@

 fn(..., Error **
-    errp
+    ____
    , ...)
 {
     ...
     Error *local_err = NULL;
     ...
(
     error_propagate_prepend(errp, local_err, ...);
|
     error_propagate(errp, local_err);
)
     ...
 }


// Warn several Error * definitions.
@check1 disable optional_qualifier exists@
identifier fn, _errp, local_err, local_err2;
position p1, p2;
@@

 fn(..., Error **_errp, ...)
 {
     ...
     Error *local_err = NULL;@p1
     ... when any
     Error *local_err2 = NULL;@p2
     ... when any
 }

@ script:python @
fn << check1.fn;
p1 << check1.p1;
p2 << check1.p2;
@@

print('Warning: function {} has several definitions of '
      'Error * local variable: at {}:{} and then at {}:{}'.format(
          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))

// Warn several propagations in control flow.
@check2 disable optional_qualifier exists@
identifier fn, _errp;
position p1, p2;
@@

 fn(..., Error **_errp, ...)
 {
     ...
(
     error_propagate_prepend(_errp, ...);@p1
|
     error_propagate(_errp, ...);@p1
)
     ...
(
     error_propagate_prepend(_errp, ...);@p2
|
     error_propagate(_errp, ...);@p2
)
     ... when any
 }

@ script:python @
fn << check2.fn;
p1 << check2.p1;
p2 << check2.p2;
@@

print('Warning: function {} propagates to errp several times in '
      'one control flow: at {}:{} and then at {}:{}'.format(
          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))

// Convert special case with goto separately.
// I tried merging this into the following rule the obvious way, but
// it made Coccinelle hang on block.c
//
// Note interesting thing: if we don't do it here, and try to fixup
// "out: }" things later after all transformations (the rule will be
// the same, just without error_propagate() call), coccinelle fails to
// match this "out: }".
@ disable optional_qualifier@
identifier fn, rule1.local_err, out;
symbol errp;
@@

 fn(..., Error ** ____, ...)
 {
     <...
-    goto out;
+    return;
     ...>
- out:
-    error_propagate(errp, local_err);
 }

// Convert most of local_err related stuff.
//
// Note, that we update everything related to matched by rule1
// function name and local_err name. We may match something not
// related to the pattern matched by rule1. For example, local_err may
// be defined with the same name in different blocks inside one
// function, and in one block follow the propagation pattern and in
// other block doesn't. Or we may have several functions with the same
// name (for different configurations).
//
// Note also that errp-cleaning functions
//   error_free_errp
//   error_report_errp
//   error_reportf_errp
//   warn_report_errp
//   warn_reportf_errp
// are not yet implemented. They must call corresponding Error* -
// freeing function and then set *errp to NULL, to avoid further
// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
// For example, error_free_errp may look like this:
//
//    void error_free_errp(Error **errp)
//    {
//        error_free(*errp);
//        *errp = NULL;
//    }
@ disable optional_qualifier exists@
identifier fn, rule1.local_err;
expression list args;
symbol errp;
@@

 fn(..., Error ** ____, ...)
 {
     <...
(
-    Error *local_err = NULL;
|

// Convert error clearing functions
(
-    error_free(local_err);
+    error_free_errp(errp);
|
-    error_report_err(local_err);
+    error_report_errp(errp);
|
-    error_reportf_err(local_err, args);
+    error_reportf_errp(errp, args);
|
-    warn_report_err(local_err);
+    warn_report_errp(errp);
|
-    warn_reportf_err(local_err, args);
+    warn_reportf_errp(errp, args);
)
?-    local_err = NULL;

|
-    error_propagate_prepend(errp, local_err, args);
+    error_prepend(errp, args);
|
-    error_propagate(errp, local_err);
|
-    &local_err
+    errp
)
     ...>
 }

// Convert remaining local_err usage. For example, different kinds of
// error checking in if conditionals. We can't merge this into
// previous hunk, as this conflicts with other substitutions in it (at
// least with "- local_err = NULL").
@ disable optional_qualifier@
identifier fn, rule1.local_err;
symbol errp;
@@

 fn(..., Error ** ____, ...)
 {
     <...
-    local_err
+    *errp
     ...>
 }

// Always use the same pattern for checking error
@ disable optional_qualifier@
identifier fn;
symbol errp;
@@

 fn(..., Error ** ____, ...)
 {
     <...
-    *errp != NULL
+    *errp
     ...>
 }

// Revert temporary ___ identifier.
@ disable optional_qualifier@
identifier fn;
@@

 fn(..., Error **
-   ____
+   errp
    , ...)
 {
     ...
 }


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-13 21:54             ` [Xen-devel] " Markus Armbruster
@ 2020-03-13 22:12               ` Eric Blake
  -1 siblings, 0 replies; 67+ messages in thread
From: Eric Blake @ 2020-03-13 22:12 UTC (permalink / raw)
  To: Markus Armbruster, Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, qemu-devel, Michael Roth, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

On 3/13/20 4:54 PM, Markus Armbruster wrote:

> 
> I append my hacked up version of auto-propagated-errp.cocci.  It
> produces the same patch as yours for the complete tree.
> 
> 
> 
> // Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
> //

> //
> // Usage example:
> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
> //  --macro-file scripts/cocci-macro-file.h --in-place \
> //  --no-show-diff --max-width 80 FILES...
> //
> // Note: --max-width 80 is needed because coccinelle default is less
> // than 80, and without this parameter coccinelle may reindent some
> // lines which fit into 80 characters but not to coccinelle default,
> // which in turn produces extra patch hunks for no reason.

Do we really need this note?  And/or should we update other Coccinelle 
script examples to mention --max-width?

> 
> // Switch unusual Error ** parameter names to errp
> // (this is necessary to use ERRP_AUTO_PROPAGATE).
> //
> // Disable optional_qualifier to skip functions with
> // "Error *const *errp" parameter.
> //
> // Skip functions with "assert(_errp && *_errp)" statement, because
> // that signals unusual semantics, and the parameter name may well
> // serve a purpose. (like nbd_iter_channel_error()).
> //
> // Skip util/error.c to not touch, for example, error_propagate() and
> // error_propagate_prepend().
> @ depends on !(file in "util/error.c") disable optional_qualifier@

The comments are definitely helpful.

> identifier fn;
> identifier _errp != errp;
> @@
> 
>   fn(...,
> -   Error **_errp
> +   Error **errp
>      ,...)
>   {
> (
>       ... when != assert(_errp && *_errp)
> &
>       <...
> -    _errp
> +    errp
>       ...>
> )
>   }
> 
> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
> // necessary
> //
> // Note, that without "when any" the final "..." does not mach
> // something matched by previous pattern, i.e. the rule will not match
> // double error_prepend in control flow like in
> // vfio_set_irq_signaling().

How likely are we that this comment might go stale over time?  But I'm 
not opposed to it.

> //
> // Note, "exists" says that we want apply rule even if it matches not
> // on all possible control flows (otherwise, it will not match

s/matches not on/does not match on/

> // standard pattern when error_propagate() call is in if branch).
> @ disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
> 
>   fn(..., Error **errp, ...)
>   {
> +   ERRP_AUTO_PROPAGATE();
>      ...  when != ERRP_AUTO_PROPAGATE();
> (
> (
>      error_append_hint(errp, ...);
> |
>      error_prepend(errp, ...);
> |
>      error_vprepend(errp, ...);
> )
>      ... when any
> |
>      Error *local_err = NULL;
>      ...
> (
>      error_propagate_prepend(errp, local_err, ...);
> |
>      error_propagate(errp, local_err);
> )
>      ...
> )
>   }
> 
> 
> // Match functions with propagation of local error to errp.
> // We want to refer these functions in several following rules, but I
> // don't know a proper way to inherit a function, not just its name
> // (to not match another functions with same name in following rules).
> // Not-proper way is as follows: rename errp parameter in functions
> // header and match it in following rules. Rename it back after all
> // transformations.
> //
> // The simplest case of propagation scheme is single definition of
> // local_err with at most one error_propagate_prepend or
> // error_propagate on each control-flow. Still, we want to match more
> // complex schemes too. We'll warn them with help of further rules.

We'll warn for those with the help of further rules.

> @rule1 disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
> 
>   fn(..., Error **
> -    errp
> +    ____
>      , ...)
>   {
>       ...
>       Error *local_err = NULL;
>       ...
> (
>       error_propagate_prepend(errp, local_err, ...);
> |
>       error_propagate(errp, local_err);
> )
>       ...
>   }
> 
> 
> // Warn several Error * definitions.

// Warn when there are several Error * definitions.


> @check1 disable optional_qualifier exists@
> identifier fn, _errp, local_err, local_err2;
> position p1, p2;
> @@
> 
>   fn(..., Error **_errp, ...)
>   {
>       ...
>       Error *local_err = NULL;@p1
>       ... when any
>       Error *local_err2 = NULL;@p2
>       ... when any
>   }
> 
> @ script:python @
> fn << check1.fn;
> p1 << check1.p1;
> p2 << check1.p2;
> @@
> 
> print('Warning: function {} has several definitions of '
>        'Error * local variable: at {}:{} and then at {}:{}'.format(
>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> 
> // Warn several propagations in control flow.

// Warn when several propagations are in the control flow.

> @check2 disable optional_qualifier exists@
> identifier fn, _errp;
> position p1, p2;
> @@
> 
>   fn(..., Error **_errp, ...)
>   {
>       ...
> (
>       error_propagate_prepend(_errp, ...);@p1
> |
>       error_propagate(_errp, ...);@p1
> )
>       ...
> (
>       error_propagate_prepend(_errp, ...);@p2
> |
>       error_propagate(_errp, ...);@p2
> )
>       ... when any
>   }
> 
> @ script:python @
> fn << check2.fn;
> p1 << check2.p1;
> p2 << check2.p2;
> @@
> 
> print('Warning: function {} propagates to errp several times in '
>        'one control flow: at {}:{} and then at {}:{}'.format(
>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> 
> // Convert special case with goto separately.
> // I tried merging this into the following rule the obvious way, but
> // it made Coccinelle hang on block.c
> //
> // Note interesting thing: if we don't do it here, and try to fixup
> // "out: }" things later after all transformations (the rule will be
> // the same, just without error_propagate() call), coccinelle fails to
> // match this "out: }".
> @ disable optional_qualifier@
> identifier fn, rule1.local_err, out;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    goto out;
> +    return;
>       ...>
> - out:
> -    error_propagate(errp, local_err);
>   }
> 
> // Convert most of local_err related stuff.
> //
> // Note, that we update everything related to matched by rule1

either 'related to' or 'matched by', but not both.

> // function name and local_err name. We may match something not
> // related to the pattern matched by rule1. For example, local_err may
> // be defined with the same name in different blocks inside one
> // function, and in one block follow the propagation pattern and in
> // other block doesn't. Or we may have several functions with the same
> // name (for different configurations).
> //
> // Note also that errp-cleaning functions
> //   error_free_errp
> //   error_report_errp
> //   error_reportf_errp
> //   warn_report_errp
> //   warn_reportf_errp
> // are not yet implemented. They must call corresponding Error* -
> // freeing function and then set *errp to NULL, to avoid further
> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).

Do we need this part of the patch if we aren't using it?  Or can it be 
added incrementally later when we actually do have those functions added?

> // For example, error_free_errp may look like this:
> //
> //    void error_free_errp(Error **errp)
> //    {
> //        error_free(*errp);
> //        *errp = NULL;
> //    }
> @ disable optional_qualifier exists@
> identifier fn, rule1.local_err;
> expression list args;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> (
> -    Error *local_err = NULL;
> |
> 
> // Convert error clearing functions
> (
> -    error_free(local_err);
> +    error_free_errp(errp);
> |
> -    error_report_err(local_err);
> +    error_report_errp(errp);
> |
> -    error_reportf_err(local_err, args);
> +    error_reportf_errp(errp, args);
> |
> -    warn_report_err(local_err);
> +    warn_report_errp(errp);
> |
> -    warn_reportf_err(local_err, args);
> +    warn_reportf_errp(errp, args);
> )
> ?-    local_err = NULL;
> 
> |
> -    error_propagate_prepend(errp, local_err, args);
> +    error_prepend(errp, args);
> |
> -    error_propagate(errp, local_err);
> |
> -    &local_err
> +    errp
> )
>       ...>
>   }
> 
> // Convert remaining local_err usage. For example, different kinds of
> // error checking in if conditionals. We can't merge this into
> // previous hunk, as this conflicts with other substitutions in it (at
> // least with "- local_err = NULL").
> @ disable optional_qualifier@
> identifier fn, rule1.local_err;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    local_err
> +    *errp
>       ...>
>   }
> 
> // Always use the same pattern for checking error
> @ disable optional_qualifier@
> identifier fn;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    *errp != NULL
> +    *errp
>       ...>
>   }
> 
> // Revert temporary ___ identifier.
> @ disable optional_qualifier@
> identifier fn;
> @@
> 
>   fn(..., Error **
> -   ____
> +   errp
>      , ...)
>   {
>       ...
>   }
> 
> 

Ultimately, the proof is in the pudding - if we are happy with the 
conversion and the warnings produced by this script, and the amount of 
manual touchup to address those warnings, then I'm happy to accept the 
script even if I didn't fully check what it does (here, I'm trusting 
what Vladimir and Markus have been doing in their back-and-forth 
refinements of the script).

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-13 22:12               ` Eric Blake
  0 siblings, 0 replies; 67+ messages in thread
From: Eric Blake @ 2020-03-13 22:12 UTC (permalink / raw)
  To: Markus Armbruster, Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, qemu-devel, Michael Roth, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

On 3/13/20 4:54 PM, Markus Armbruster wrote:

> 
> I append my hacked up version of auto-propagated-errp.cocci.  It
> produces the same patch as yours for the complete tree.
> 
> 
> 
> // Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
> //

> //
> // Usage example:
> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
> //  --macro-file scripts/cocci-macro-file.h --in-place \
> //  --no-show-diff --max-width 80 FILES...
> //
> // Note: --max-width 80 is needed because coccinelle default is less
> // than 80, and without this parameter coccinelle may reindent some
> // lines which fit into 80 characters but not to coccinelle default,
> // which in turn produces extra patch hunks for no reason.

Do we really need this note?  And/or should we update other Coccinelle 
script examples to mention --max-width?

> 
> // Switch unusual Error ** parameter names to errp
> // (this is necessary to use ERRP_AUTO_PROPAGATE).
> //
> // Disable optional_qualifier to skip functions with
> // "Error *const *errp" parameter.
> //
> // Skip functions with "assert(_errp && *_errp)" statement, because
> // that signals unusual semantics, and the parameter name may well
> // serve a purpose. (like nbd_iter_channel_error()).
> //
> // Skip util/error.c to not touch, for example, error_propagate() and
> // error_propagate_prepend().
> @ depends on !(file in "util/error.c") disable optional_qualifier@

The comments are definitely helpful.

> identifier fn;
> identifier _errp != errp;
> @@
> 
>   fn(...,
> -   Error **_errp
> +   Error **errp
>      ,...)
>   {
> (
>       ... when != assert(_errp && *_errp)
> &
>       <...
> -    _errp
> +    errp
>       ...>
> )
>   }
> 
> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
> // necessary
> //
> // Note, that without "when any" the final "..." does not mach
> // something matched by previous pattern, i.e. the rule will not match
> // double error_prepend in control flow like in
> // vfio_set_irq_signaling().

How likely are we that this comment might go stale over time?  But I'm 
not opposed to it.

> //
> // Note, "exists" says that we want apply rule even if it matches not
> // on all possible control flows (otherwise, it will not match

s/matches not on/does not match on/

> // standard pattern when error_propagate() call is in if branch).
> @ disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
> 
>   fn(..., Error **errp, ...)
>   {
> +   ERRP_AUTO_PROPAGATE();
>      ...  when != ERRP_AUTO_PROPAGATE();
> (
> (
>      error_append_hint(errp, ...);
> |
>      error_prepend(errp, ...);
> |
>      error_vprepend(errp, ...);
> )
>      ... when any
> |
>      Error *local_err = NULL;
>      ...
> (
>      error_propagate_prepend(errp, local_err, ...);
> |
>      error_propagate(errp, local_err);
> )
>      ...
> )
>   }
> 
> 
> // Match functions with propagation of local error to errp.
> // We want to refer these functions in several following rules, but I
> // don't know a proper way to inherit a function, not just its name
> // (to not match another functions with same name in following rules).
> // Not-proper way is as follows: rename errp parameter in functions
> // header and match it in following rules. Rename it back after all
> // transformations.
> //
> // The simplest case of propagation scheme is single definition of
> // local_err with at most one error_propagate_prepend or
> // error_propagate on each control-flow. Still, we want to match more
> // complex schemes too. We'll warn them with help of further rules.

We'll warn for those with the help of further rules.

> @rule1 disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
> 
>   fn(..., Error **
> -    errp
> +    ____
>      , ...)
>   {
>       ...
>       Error *local_err = NULL;
>       ...
> (
>       error_propagate_prepend(errp, local_err, ...);
> |
>       error_propagate(errp, local_err);
> )
>       ...
>   }
> 
> 
> // Warn several Error * definitions.

// Warn when there are several Error * definitions.


> @check1 disable optional_qualifier exists@
> identifier fn, _errp, local_err, local_err2;
> position p1, p2;
> @@
> 
>   fn(..., Error **_errp, ...)
>   {
>       ...
>       Error *local_err = NULL;@p1
>       ... when any
>       Error *local_err2 = NULL;@p2
>       ... when any
>   }
> 
> @ script:python @
> fn << check1.fn;
> p1 << check1.p1;
> p2 << check1.p2;
> @@
> 
> print('Warning: function {} has several definitions of '
>        'Error * local variable: at {}:{} and then at {}:{}'.format(
>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> 
> // Warn several propagations in control flow.

// Warn when several propagations are in the control flow.

> @check2 disable optional_qualifier exists@
> identifier fn, _errp;
> position p1, p2;
> @@
> 
>   fn(..., Error **_errp, ...)
>   {
>       ...
> (
>       error_propagate_prepend(_errp, ...);@p1
> |
>       error_propagate(_errp, ...);@p1
> )
>       ...
> (
>       error_propagate_prepend(_errp, ...);@p2
> |
>       error_propagate(_errp, ...);@p2
> )
>       ... when any
>   }
> 
> @ script:python @
> fn << check2.fn;
> p1 << check2.p1;
> p2 << check2.p2;
> @@
> 
> print('Warning: function {} propagates to errp several times in '
>        'one control flow: at {}:{} and then at {}:{}'.format(
>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> 
> // Convert special case with goto separately.
> // I tried merging this into the following rule the obvious way, but
> // it made Coccinelle hang on block.c
> //
> // Note interesting thing: if we don't do it here, and try to fixup
> // "out: }" things later after all transformations (the rule will be
> // the same, just without error_propagate() call), coccinelle fails to
> // match this "out: }".
> @ disable optional_qualifier@
> identifier fn, rule1.local_err, out;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    goto out;
> +    return;
>       ...>
> - out:
> -    error_propagate(errp, local_err);
>   }
> 
> // Convert most of local_err related stuff.
> //
> // Note, that we update everything related to matched by rule1

either 'related to' or 'matched by', but not both.

> // function name and local_err name. We may match something not
> // related to the pattern matched by rule1. For example, local_err may
> // be defined with the same name in different blocks inside one
> // function, and in one block follow the propagation pattern and in
> // other block doesn't. Or we may have several functions with the same
> // name (for different configurations).
> //
> // Note also that errp-cleaning functions
> //   error_free_errp
> //   error_report_errp
> //   error_reportf_errp
> //   warn_report_errp
> //   warn_reportf_errp
> // are not yet implemented. They must call corresponding Error* -
> // freeing function and then set *errp to NULL, to avoid further
> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).

Do we need this part of the patch if we aren't using it?  Or can it be 
added incrementally later when we actually do have those functions added?

> // For example, error_free_errp may look like this:
> //
> //    void error_free_errp(Error **errp)
> //    {
> //        error_free(*errp);
> //        *errp = NULL;
> //    }
> @ disable optional_qualifier exists@
> identifier fn, rule1.local_err;
> expression list args;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> (
> -    Error *local_err = NULL;
> |
> 
> // Convert error clearing functions
> (
> -    error_free(local_err);
> +    error_free_errp(errp);
> |
> -    error_report_err(local_err);
> +    error_report_errp(errp);
> |
> -    error_reportf_err(local_err, args);
> +    error_reportf_errp(errp, args);
> |
> -    warn_report_err(local_err);
> +    warn_report_errp(errp);
> |
> -    warn_reportf_err(local_err, args);
> +    warn_reportf_errp(errp, args);
> )
> ?-    local_err = NULL;
> 
> |
> -    error_propagate_prepend(errp, local_err, args);
> +    error_prepend(errp, args);
> |
> -    error_propagate(errp, local_err);
> |
> -    &local_err
> +    errp
> )
>       ...>
>   }
> 
> // Convert remaining local_err usage. For example, different kinds of
> // error checking in if conditionals. We can't merge this into
> // previous hunk, as this conflicts with other substitutions in it (at
> // least with "- local_err = NULL").
> @ disable optional_qualifier@
> identifier fn, rule1.local_err;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    local_err
> +    *errp
>       ...>
>   }
> 
> // Always use the same pattern for checking error
> @ disable optional_qualifier@
> identifier fn;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    *errp != NULL
> +    *errp
>       ...>
>   }
> 
> // Revert temporary ___ identifier.
> @ disable optional_qualifier@
> identifier fn;
> @@
> 
>   fn(..., Error **
> -   ____
> +   errp
>      , ...)
>   {
>       ...
>   }
> 
> 

Ultimately, the proof is in the pudding - if we are happy with the 
conversion and the warnings produced by this script, and the amount of 
manual touchup to address those warnings, then I'm happy to accept the 
script even if I didn't fully check what it does (here, I'm trusting 
what Vladimir and Markus have been doing in their back-and-forth 
refinements of the script).

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3226
Virtualization:  qemu.org | libvirt.org


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-13 22:12               ` [Xen-devel] " Eric Blake
@ 2020-03-15 16:38                 ` Markus Armbruster
  -1 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-15 16:38 UTC (permalink / raw)
  To: Eric Blake
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Michael Roth, Greg Kurz, Stefano Stabellini, Gerd Hoffmann,
	Stefan Hajnoczi, Anthony Perard, xen-devel, Max Reitz,
	Philippe Mathieu-Daudé,
	Stefan Berger

Eric Blake <eblake@redhat.com> writes:

> On 3/13/20 4:54 PM, Markus Armbruster wrote:
>
>>
>> I append my hacked up version of auto-propagated-errp.cocci.  It
>> produces the same patch as yours for the complete tree.
>>
>>
>>
>> // Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>> //
>
>> //
>> // Usage example:
>> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>> //  --macro-file scripts/cocci-macro-file.h --in-place \
>> //  --no-show-diff --max-width 80 FILES...
>> //
>> // Note: --max-width 80 is needed because coccinelle default is less
>> // than 80, and without this parameter coccinelle may reindent some
>> // lines which fit into 80 characters but not to coccinelle default,
>> // which in turn produces extra patch hunks for no reason.
>
> Do we really need this note?  And/or should we update other Coccinelle
> script examples to mention --max-width?

What makes this Coccinelle script special is its rule chaining hack.  We
want to transform certain functions by applying a sequence of rules.  We
want to chain these rules together, i.e. have subsequent rules match
only where the first rule matches.  We do this by renaming the Error
**errp parameter to ___ in the first rule, and back to errp in the last
rule.  The two renames cancel out, but of course Coccinelle doesn't
special-case that, but does what it always does when it touches long
lines: it wraps them.  This leads to unwanted patch hunks wrapping
formal parameter lists.

Increasing Coccinelle's line width limit just a bit gets rid of almost
all of them.

>> // Switch unusual Error ** parameter names to errp
>> // (this is necessary to use ERRP_AUTO_PROPAGATE).
>> //
>> // Disable optional_qualifier to skip functions with
>> // "Error *const *errp" parameter.
>> //
>> // Skip functions with "assert(_errp && *_errp)" statement, because
>> // that signals unusual semantics, and the parameter name may well
>> // serve a purpose. (like nbd_iter_channel_error()).
>> //
>> // Skip util/error.c to not touch, for example, error_propagate() and
>> // error_propagate_prepend().
>> @ depends on !(file in "util/error.c") disable optional_qualifier@
>
> The comments are definitely helpful.

Oh boy, they are!

>> identifier fn;
>> identifier _errp != errp;
>> @@
>>
>>   fn(...,
>> -   Error **_errp
>> +   Error **errp
>>      ,...)
>>   {
>> (
>>       ... when != assert(_errp && *_errp)
>> &
>>       <...
>> -    _errp
>> +    errp
>>       ...>
>> )
>>   }
>>
>> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>> // necessary
>> //
>> // Note, that without "when any" the final "..." does not mach
>> // something matched by previous pattern, i.e. the rule will not match
>> // double error_prepend in control flow like in
>> // vfio_set_irq_signaling().
>
> How likely are we that this comment might go stale over time?  But I'm
> not opposed to it.

My plan is to complete the conversion in 5.1.  The script should become
uninteresting soon after.  Comments that risk going stale don't bother
me.

>> //
>> // Note, "exists" says that we want apply rule even if it matches not
>> // on all possible control flows (otherwise, it will not match
>
> s/matches not on/does not match on/
>
>> // standard pattern when error_propagate() call is in if branch).
>> @ disable optional_qualifier exists@
>> identifier fn, local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error **errp, ...)
>>   {
>> +   ERRP_AUTO_PROPAGATE();
>>      ...  when != ERRP_AUTO_PROPAGATE();
>> (
>> (
>>      error_append_hint(errp, ...);
>> |
>>      error_prepend(errp, ...);
>> |
>>      error_vprepend(errp, ...);
>> )
>>      ... when any
>> |
>>      Error *local_err = NULL;
>>      ...
>> (
>>      error_propagate_prepend(errp, local_err, ...);
>> |
>>      error_propagate(errp, local_err);
>> )
>>      ...
>> )
>>   }
>>
>>
>> // Match functions with propagation of local error to errp.
>> // We want to refer these functions in several following rules, but I
>> // don't know a proper way to inherit a function, not just its name
>> // (to not match another functions with same name in following rules).
>> // Not-proper way is as follows: rename errp parameter in functions
>> // header and match it in following rules. Rename it back after all
>> // transformations.
>> //
>> // The simplest case of propagation scheme is single definition of
>> // local_err with at most one error_propagate_prepend or
>> // error_propagate on each control-flow. Still, we want to match more
>> // complex schemes too. We'll warn them with help of further rules.
>
> We'll warn for those with the help of further rules.
>
>> @rule1 disable optional_qualifier exists@
>> identifier fn, local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error **
>> -    errp
>> +    ____
>>      , ...)
>>   {
>>       ...
>>       Error *local_err = NULL;
>>       ...
>> (
>>       error_propagate_prepend(errp, local_err, ...);
>> |
>>       error_propagate(errp, local_err);
>> )
>>       ...
>>   }
>>
>>
>> // Warn several Error * definitions.
>
> // Warn when there are several Error * definitions.
>
>
>> @check1 disable optional_qualifier exists@
>> identifier fn, _errp, local_err, local_err2;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>>   {
>>       ...
>>       Error *local_err = NULL;@p1
>>       ... when any
>>       Error *local_err2 = NULL;@p2
>>       ... when any
>>   }
>>
>> @ script:python @
>> fn << check1.fn;
>> p1 << check1.p1;
>> p2 << check1.p2;
>> @@
>>
>> print('Warning: function {} has several definitions of '
>>        'Error * local variable: at {}:{} and then at {}:{}'.format(
>>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>
>> // Warn several propagations in control flow.
>
> // Warn when several propagations are in the control flow.
>
>> @check2 disable optional_qualifier exists@
>> identifier fn, _errp;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>>   {
>>       ...
>> (
>>       error_propagate_prepend(_errp, ...);@p1
>> |
>>       error_propagate(_errp, ...);@p1
>> )
>>       ...
>> (
>>       error_propagate_prepend(_errp, ...);@p2
>> |
>>       error_propagate(_errp, ...);@p2
>> )
>>       ... when any
>>   }
>>
>> @ script:python @
>> fn << check2.fn;
>> p1 << check2.p1;
>> p2 << check2.p2;
>> @@
>>
>> print('Warning: function {} propagates to errp several times in '
>>        'one control flow: at {}:{} and then at {}:{}'.format(
>>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>
>> // Convert special case with goto separately.
>> // I tried merging this into the following rule the obvious way, but
>> // it made Coccinelle hang on block.c
>> //
>> // Note interesting thing: if we don't do it here, and try to fixup
>> // "out: }" things later after all transformations (the rule will be
>> // the same, just without error_propagate() call), coccinelle fails to
>> // match this "out: }".
>> @ disable optional_qualifier@
>> identifier fn, rule1.local_err, out;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    goto out;
>> +    return;
>>       ...>
>> - out:
>> -    error_propagate(errp, local_err);
>>   }
>>
>> // Convert most of local_err related stuff.
>> //
>> // Note, that we update everything related to matched by rule1
>
> either 'related to' or 'matched by', but not both.
>
>> // function name and local_err name. We may match something not
>> // related to the pattern matched by rule1. For example, local_err may
>> // be defined with the same name in different blocks inside one
>> // function, and in one block follow the propagation pattern and in
>> // other block doesn't. Or we may have several functions with the same
>> // name (for different configurations).
>> //
>> // Note also that errp-cleaning functions
>> //   error_free_errp
>> //   error_report_errp
>> //   error_reportf_errp
>> //   warn_report_errp
>> //   warn_reportf_errp
>> // are not yet implemented. They must call corresponding Error* -
>> // freeing function and then set *errp to NULL, to avoid further
>> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>
> Do we need this part of the patch if we aren't using it?  Or can it be
> added incrementally later when we actually do have those functions
> added?

When I asked a similar question, Vladimir pointed out that transforming
these functions is required for correctness.

If we keep the rule and add the functions only when it's used, the
compiler will tell us when it's used.

If we add the rule only when we believe it's used, we risk silent
incorrect transformations.

>> // For example, error_free_errp may look like this:
>> //
>> //    void error_free_errp(Error **errp)
>> //    {
>> //        error_free(*errp);
>> //        *errp = NULL;
>> //    }
>> @ disable optional_qualifier exists@
>> identifier fn, rule1.local_err;
>> expression list args;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> (
>> -    Error *local_err = NULL;
>> |
>>
>> // Convert error clearing functions
>> (
>> -    error_free(local_err);
>> +    error_free_errp(errp);
>> |
>> -    error_report_err(local_err);
>> +    error_report_errp(errp);
>> |
>> -    error_reportf_err(local_err, args);
>> +    error_reportf_errp(errp, args);
>> |
>> -    warn_report_err(local_err);
>> +    warn_report_errp(errp);
>> |
>> -    warn_reportf_err(local_err, args);
>> +    warn_reportf_errp(errp, args);
>> )
>> ?-    local_err = NULL;
>>
>> |
>> -    error_propagate_prepend(errp, local_err, args);
>> +    error_prepend(errp, args);
>> |
>> -    error_propagate(errp, local_err);
>> |
>> -    &local_err
>> +    errp
>> )
>>       ...>
>>   }
>>
>> // Convert remaining local_err usage. For example, different kinds of
>> // error checking in if conditionals. We can't merge this into
>> // previous hunk, as this conflicts with other substitutions in it (at
>> // least with "- local_err = NULL").
>> @ disable optional_qualifier@
>> identifier fn, rule1.local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    local_err
>> +    *errp
>>       ...>
>>   }
>>
>> // Always use the same pattern for checking error
>> @ disable optional_qualifier@
>> identifier fn;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    *errp != NULL
>> +    *errp
>>       ...>
>>   }
>>
>> // Revert temporary ___ identifier.
>> @ disable optional_qualifier@
>> identifier fn;
>> @@
>>
>>   fn(..., Error **
>> -   ____
>> +   errp
>>      , ...)
>>   {
>>       ...
>>   }
>>
>>
>
> Ultimately, the proof is in the pudding - if we are happy with the
> conversion and the warnings produced by this script, and the amount of
> manual touchup to address those warnings, then I'm happy to accept the
> script even if I didn't fully check what it does (here, I'm trusting
> what Vladimir and Markus have been doing in their back-and-forth
> refinements of the script).

I decided that the patches produced by this script are too large to be
reviewed by a single person: the monotony blinds you a few percent in.
Instead, I spent my time on understanding the script, building trust in
its workings, and searching its output for unusual patterns.

Patches to subsystems are hopefully small enough for review by subsystem
experts.



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-15 16:38                 ` Markus Armbruster
  0 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-15 16:38 UTC (permalink / raw)
  To: Eric Blake
  Cc: Kevin Wolf, Vladimir Sementsov-Ogievskiy, qemu-block,
	Paul Durrant, Laszlo Ersek, Christian Schoenebeck, qemu-devel,
	Michael Roth, Greg Kurz, Stefano Stabellini, Gerd Hoffmann,
	Stefan Hajnoczi, Anthony Perard, xen-devel, Max Reitz,
	Philippe Mathieu-Daudé,
	Stefan Berger

Eric Blake <eblake@redhat.com> writes:

> On 3/13/20 4:54 PM, Markus Armbruster wrote:
>
>>
>> I append my hacked up version of auto-propagated-errp.cocci.  It
>> produces the same patch as yours for the complete tree.
>>
>>
>>
>> // Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>> //
>
>> //
>> // Usage example:
>> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>> //  --macro-file scripts/cocci-macro-file.h --in-place \
>> //  --no-show-diff --max-width 80 FILES...
>> //
>> // Note: --max-width 80 is needed because coccinelle default is less
>> // than 80, and without this parameter coccinelle may reindent some
>> // lines which fit into 80 characters but not to coccinelle default,
>> // which in turn produces extra patch hunks for no reason.
>
> Do we really need this note?  And/or should we update other Coccinelle
> script examples to mention --max-width?

What makes this Coccinelle script special is its rule chaining hack.  We
want to transform certain functions by applying a sequence of rules.  We
want to chain these rules together, i.e. have subsequent rules match
only where the first rule matches.  We do this by renaming the Error
**errp parameter to ___ in the first rule, and back to errp in the last
rule.  The two renames cancel out, but of course Coccinelle doesn't
special-case that, but does what it always does when it touches long
lines: it wraps them.  This leads to unwanted patch hunks wrapping
formal parameter lists.

Increasing Coccinelle's line width limit just a bit gets rid of almost
all of them.

>> // Switch unusual Error ** parameter names to errp
>> // (this is necessary to use ERRP_AUTO_PROPAGATE).
>> //
>> // Disable optional_qualifier to skip functions with
>> // "Error *const *errp" parameter.
>> //
>> // Skip functions with "assert(_errp && *_errp)" statement, because
>> // that signals unusual semantics, and the parameter name may well
>> // serve a purpose. (like nbd_iter_channel_error()).
>> //
>> // Skip util/error.c to not touch, for example, error_propagate() and
>> // error_propagate_prepend().
>> @ depends on !(file in "util/error.c") disable optional_qualifier@
>
> The comments are definitely helpful.

Oh boy, they are!

>> identifier fn;
>> identifier _errp != errp;
>> @@
>>
>>   fn(...,
>> -   Error **_errp
>> +   Error **errp
>>      ,...)
>>   {
>> (
>>       ... when != assert(_errp && *_errp)
>> &
>>       <...
>> -    _errp
>> +    errp
>>       ...>
>> )
>>   }
>>
>> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>> // necessary
>> //
>> // Note, that without "when any" the final "..." does not mach
>> // something matched by previous pattern, i.e. the rule will not match
>> // double error_prepend in control flow like in
>> // vfio_set_irq_signaling().
>
> How likely are we that this comment might go stale over time?  But I'm
> not opposed to it.

My plan is to complete the conversion in 5.1.  The script should become
uninteresting soon after.  Comments that risk going stale don't bother
me.

>> //
>> // Note, "exists" says that we want apply rule even if it matches not
>> // on all possible control flows (otherwise, it will not match
>
> s/matches not on/does not match on/
>
>> // standard pattern when error_propagate() call is in if branch).
>> @ disable optional_qualifier exists@
>> identifier fn, local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error **errp, ...)
>>   {
>> +   ERRP_AUTO_PROPAGATE();
>>      ...  when != ERRP_AUTO_PROPAGATE();
>> (
>> (
>>      error_append_hint(errp, ...);
>> |
>>      error_prepend(errp, ...);
>> |
>>      error_vprepend(errp, ...);
>> )
>>      ... when any
>> |
>>      Error *local_err = NULL;
>>      ...
>> (
>>      error_propagate_prepend(errp, local_err, ...);
>> |
>>      error_propagate(errp, local_err);
>> )
>>      ...
>> )
>>   }
>>
>>
>> // Match functions with propagation of local error to errp.
>> // We want to refer these functions in several following rules, but I
>> // don't know a proper way to inherit a function, not just its name
>> // (to not match another functions with same name in following rules).
>> // Not-proper way is as follows: rename errp parameter in functions
>> // header and match it in following rules. Rename it back after all
>> // transformations.
>> //
>> // The simplest case of propagation scheme is single definition of
>> // local_err with at most one error_propagate_prepend or
>> // error_propagate on each control-flow. Still, we want to match more
>> // complex schemes too. We'll warn them with help of further rules.
>
> We'll warn for those with the help of further rules.
>
>> @rule1 disable optional_qualifier exists@
>> identifier fn, local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error **
>> -    errp
>> +    ____
>>      , ...)
>>   {
>>       ...
>>       Error *local_err = NULL;
>>       ...
>> (
>>       error_propagate_prepend(errp, local_err, ...);
>> |
>>       error_propagate(errp, local_err);
>> )
>>       ...
>>   }
>>
>>
>> // Warn several Error * definitions.
>
> // Warn when there are several Error * definitions.
>
>
>> @check1 disable optional_qualifier exists@
>> identifier fn, _errp, local_err, local_err2;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>>   {
>>       ...
>>       Error *local_err = NULL;@p1
>>       ... when any
>>       Error *local_err2 = NULL;@p2
>>       ... when any
>>   }
>>
>> @ script:python @
>> fn << check1.fn;
>> p1 << check1.p1;
>> p2 << check1.p2;
>> @@
>>
>> print('Warning: function {} has several definitions of '
>>        'Error * local variable: at {}:{} and then at {}:{}'.format(
>>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>
>> // Warn several propagations in control flow.
>
> // Warn when several propagations are in the control flow.
>
>> @check2 disable optional_qualifier exists@
>> identifier fn, _errp;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>>   {
>>       ...
>> (
>>       error_propagate_prepend(_errp, ...);@p1
>> |
>>       error_propagate(_errp, ...);@p1
>> )
>>       ...
>> (
>>       error_propagate_prepend(_errp, ...);@p2
>> |
>>       error_propagate(_errp, ...);@p2
>> )
>>       ... when any
>>   }
>>
>> @ script:python @
>> fn << check2.fn;
>> p1 << check2.p1;
>> p2 << check2.p2;
>> @@
>>
>> print('Warning: function {} propagates to errp several times in '
>>        'one control flow: at {}:{} and then at {}:{}'.format(
>>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>
>> // Convert special case with goto separately.
>> // I tried merging this into the following rule the obvious way, but
>> // it made Coccinelle hang on block.c
>> //
>> // Note interesting thing: if we don't do it here, and try to fixup
>> // "out: }" things later after all transformations (the rule will be
>> // the same, just without error_propagate() call), coccinelle fails to
>> // match this "out: }".
>> @ disable optional_qualifier@
>> identifier fn, rule1.local_err, out;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    goto out;
>> +    return;
>>       ...>
>> - out:
>> -    error_propagate(errp, local_err);
>>   }
>>
>> // Convert most of local_err related stuff.
>> //
>> // Note, that we update everything related to matched by rule1
>
> either 'related to' or 'matched by', but not both.
>
>> // function name and local_err name. We may match something not
>> // related to the pattern matched by rule1. For example, local_err may
>> // be defined with the same name in different blocks inside one
>> // function, and in one block follow the propagation pattern and in
>> // other block doesn't. Or we may have several functions with the same
>> // name (for different configurations).
>> //
>> // Note also that errp-cleaning functions
>> //   error_free_errp
>> //   error_report_errp
>> //   error_reportf_errp
>> //   warn_report_errp
>> //   warn_reportf_errp
>> // are not yet implemented. They must call corresponding Error* -
>> // freeing function and then set *errp to NULL, to avoid further
>> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>
> Do we need this part of the patch if we aren't using it?  Or can it be
> added incrementally later when we actually do have those functions
> added?

When I asked a similar question, Vladimir pointed out that transforming
these functions is required for correctness.

If we keep the rule and add the functions only when it's used, the
compiler will tell us when it's used.

If we add the rule only when we believe it's used, we risk silent
incorrect transformations.

>> // For example, error_free_errp may look like this:
>> //
>> //    void error_free_errp(Error **errp)
>> //    {
>> //        error_free(*errp);
>> //        *errp = NULL;
>> //    }
>> @ disable optional_qualifier exists@
>> identifier fn, rule1.local_err;
>> expression list args;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> (
>> -    Error *local_err = NULL;
>> |
>>
>> // Convert error clearing functions
>> (
>> -    error_free(local_err);
>> +    error_free_errp(errp);
>> |
>> -    error_report_err(local_err);
>> +    error_report_errp(errp);
>> |
>> -    error_reportf_err(local_err, args);
>> +    error_reportf_errp(errp, args);
>> |
>> -    warn_report_err(local_err);
>> +    warn_report_errp(errp);
>> |
>> -    warn_reportf_err(local_err, args);
>> +    warn_reportf_errp(errp, args);
>> )
>> ?-    local_err = NULL;
>>
>> |
>> -    error_propagate_prepend(errp, local_err, args);
>> +    error_prepend(errp, args);
>> |
>> -    error_propagate(errp, local_err);
>> |
>> -    &local_err
>> +    errp
>> )
>>       ...>
>>   }
>>
>> // Convert remaining local_err usage. For example, different kinds of
>> // error checking in if conditionals. We can't merge this into
>> // previous hunk, as this conflicts with other substitutions in it (at
>> // least with "- local_err = NULL").
>> @ disable optional_qualifier@
>> identifier fn, rule1.local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    local_err
>> +    *errp
>>       ...>
>>   }
>>
>> // Always use the same pattern for checking error
>> @ disable optional_qualifier@
>> identifier fn;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    *errp != NULL
>> +    *errp
>>       ...>
>>   }
>>
>> // Revert temporary ___ identifier.
>> @ disable optional_qualifier@
>> identifier fn;
>> @@
>>
>>   fn(..., Error **
>> -   ____
>> +   errp
>>      , ...)
>>   {
>>       ...
>>   }
>>
>>
>
> Ultimately, the proof is in the pudding - if we are happy with the
> conversion and the warnings produced by this script, and the amount of
> manual touchup to address those warnings, then I'm happy to accept the
> script even if I didn't fully check what it does (here, I'm trusting
> what Vladimir and Markus have been doing in their back-and-forth
> refinements of the script).

I decided that the patches produced by this script are too large to be
reviewed by a single person: the monotony blinds you a few percent in.
Instead, I spent my time on understanding the script, building trust in
its workings, and searching its output for unusual patterns.

Patches to subsystems are hopefully small enough for review by subsystem
experts.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-13 21:54             ` [Xen-devel] " Markus Armbruster
@ 2020-03-16  7:12               ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-16  7:12 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Laszlo Ersek, Christian Schoenebeck, Michael Roth, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger



On 14.03.2020 00:54, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> 13.03.2020 18:42, Markus Armbruster wrote:
>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>
>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>> out now as is.
>>>>>
>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>
>>>>>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>>>>>> does corresponding changes in code (look for details in
>>>>>> include/qapi/error.h)
>>>>>>
>>>>>> Usage example:
>>>>>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>>     --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>>>>>     --max-width 80 FILES...
>>>>>>
>>>>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>>>>> ---
>>>>>>
>>>>>> Cc: Eric Blake <eblake@redhat.com>
>>>>>> Cc: Kevin Wolf <kwolf@redhat.com>
>>>>>> Cc: Max Reitz <mreitz@redhat.com>
>>>>>> Cc: Greg Kurz <groug@kaod.org>
>>>>>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>>>>>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>>>>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>>>>> Cc: Paul Durrant <paul@xen.org>
>>>>>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>>>>>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>>>>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>>>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>>>>>> Cc: Markus Armbruster <armbru@redhat.com>
>>>>>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>>>>>> Cc: qemu-devel@nongnu.org
>>>>>> Cc: qemu-block@nongnu.org
>>>>>> Cc: xen-devel@lists.xenproject.org
>>>>>>
>>>>>>     scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>>>>>     include/qapi/error.h                          |   3 +
>>>>>>     MAINTAINERS                                   |   1 +
>>>>>>     3 files changed, 331 insertions(+)
>>>>>>     create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>
>>>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>> new file mode 100644
>>>>>> index 0000000000..7dac2dcfa4
>>>>>> --- /dev/null
>>>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>> @@ -0,0 +1,327 @@
>>>>>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>>>>> +//
>>>>>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>>>>>> +//
>>>>>> +// This program is free software; you can redistribute it and/or
>>>>>> +// modify it under the terms of the GNU General Public License as
>>>>>> +// published by the Free Software Foundation; either version 2 of the
>>>>>> +// License, or (at your option) any later version.
>>>>>> +//
>>>>>> +// This program is distributed in the hope that it will be useful,
>>>>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>>>> +// GNU General Public License for more details.
>>>>>> +//
>>>>>> +// You should have received a copy of the GNU General Public License
>>>>>> +// along with this program.  If not, see
>>>>>> +// <http://www.gnu.org/licenses/>.
>>>>>> +//
>>>>>> +// Usage example:
>>>>>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>>>>>> +//  --no-show-diff --max-width 80 FILES...
>>>>>> +//
>>>>>> +// Note: --max-width 80 is needed because coccinelle default is less
>>>>>> +// than 80, and without this parameter coccinelle may reindent some
>>>>>> +// lines which fit into 80 characters but not to coccinelle default,
>>>>>> +// which in turn produces extra patch hunks for no reason.
>>>>>
>>>>> This is about unwanted reformatting of parameter lists due to the ___
>>>>> chaining hack.  --max-width 80 makes that less likely, but not
>>>>> impossible.
>>>>>
>>>>> We can search for unwanted reformatting of parameter lists.  I think
>>>>> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
>>>>> tree, I get one false positive (not a parameter list), and one hit:
>>>>>
>>>>>        @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>>>>>             }
>>>>>         }
>>>>>
>>>>>        -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>>>>>        +void object_apply_global_props(Object *obj, const GPtrArray *props,
>>>>>        +                               Error **errp)
>>>>>         {
>>>>>        +    ERRP_AUTO_PROPAGATE();
>>>>>             int i;
>>>>>
>>>>>             if (!props) {
>>>>>
>>>>> Reformatting, but not unwanted.
>>>>
>>>> Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
>>>> ERRP_AUTO_PROPAGATE addition even for non-automatic patch.
>>>
>>> Agree.
>>>
>>>>>
>>>>> The --max-width 80 hack is good enough for me.
>>>>>
>>>>> It does result in slightly long transformed lines, e.g. this one in
>>>>> replication.c:
>>>>>
>>>>>        @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>>>>>                 s->mode = REPLICATION_MODE_PRIMARY;
>>>>>                 top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>>>>>                 if (top_id) {
>>>>>        -            error_setg(&local_err, "The primary side does not support option top-id");
>>>>>        +            error_setg(errp, "The primary side does not support option top-id");
>>>>>                     goto fail;
>>>>>                 }
>>>>>             } else if (!strcmp(mode, "secondary")) {
>>>>>
>>>>> v8 did break this line (that's how I found it).  However, v9 still
>>>>> shortens the line, just not below the target.  All your + lines look
>>>>> quite unlikely to lengthen lines.  Let's not worry about this.
>>>>>
>>>>>> +// Switch unusual Error ** parameter names to errp
>>>>>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>>>>>> +//
>>>>>> +// Disable optional_qualifier to skip functions with
>>>>>> +// "Error *const *errp" parameter.
>>>>>> +//
>>>>>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>>>>>> +// that signals unusual semantics, and the parameter name may well
>>>>>> +// serve a purpose. (like nbd_iter_channel_error()).
>>>>>> +//
>>>>>> +// Skip util/error.c to not touch, for example, error_propagate() and
>>>>>> +// error_propagate_prepend().
>>>>>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>>>>>> +identifier fn;
>>>>>> +identifier _errp != errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(...,
>>>>>> +-   Error **_errp
>>>>>> ++   Error **errp
>>>>>> +    ,...)
>>>>>> + {
>>>>>> +(
>>>>>> +     ... when != assert(_errp && *_errp)
>>>>>> +&
>>>>>> +     <...
>>>>>> +-    _errp
>>>>>> ++    errp
>>>>>> +     ...>
>>>>>> +)
>>>>>> + }
>>>>>> +
>>>>>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>>>>> +// necessary
>>>>>> +//
>>>>>> +// Note, that without "when any" the final "..." does not mach
>>>>>> +// something matched by previous pattern, i.e. the rule will not match
>>>>>> +// double error_prepend in control flow like in
>>>>>> +// vfio_set_irq_signaling().
>>>>>> +//
>>>>>> +// Note, "exists" says that we want apply rule even if it matches not
>>>>>> +// on all possible control flows (otherwise, it will not match
>>>>>> +// standard pattern when error_propagate() call is in if branch).
>>>>>> +@ disable optional_qualifier exists@
>>>>>> +identifier fn, local_err;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error **errp, ...)
>>>>>> + {
>>>>>> ++   ERRP_AUTO_PROPAGATE();
>>>>>> +    ...  when != ERRP_AUTO_PROPAGATE();
>>>>>> +(
>>>>>> +(
>>>>>> +    error_append_hint(errp, ...);
>>>>>> +|
>>>>>> +    error_prepend(errp, ...);
>>>>>> +|
>>>>>> +    error_vprepend(errp, ...);
>>>>>> +)
>>>>>> +    ... when any
>>>>>> +|
>>>>>> +    Error *local_err = NULL;
>>>>>> +    ...
>>>>>> +(
>>>>>> +    error_propagate_prepend(errp, local_err, ...);
>>>>>> +|
>>>>>> +    error_propagate(errp, local_err);
>>>>>> +)
>>>>>> +    ...
>>>>>> +)
>>>>>> + }
>>>>>> +
>>>>>> +
>>>>>> +// Match functions with propagation of local error to errp.
>>>>>> +// We want to refer these functions in several following rules, but I
>>>>>> +// don't know a proper way to inherit a function, not just its name
>>>>>> +// (to not match another functions with same name in following rules).
>>>>>> +// Not-proper way is as follows: rename errp parameter in functions
>>>>>> +// header and match it in following rules. Rename it back after all
>>>>>> +// transformations.
>>>>>> +//
>>>>>> +// The simplest case of propagation scheme is single definition of
>>>>>> +// local_err with at most one error_propagate_prepend or
>>>>>> +// error_propagate on each control-flow. Still, we want to match more
>>>>>> +// complex schemes too. We'll warn them with help of further rules.
>>>>>
>>>>> I think what we actually want is to examine instances of this pattern to
>>>>> figure out whether and how we want to transform them.  Perhaps:
>>>>>
>>>>>        // The common case is a single definition of local_err with at most one
>>>>>        // error_propagate_prepend() or error_propagate() on each control-flow
>>>>>        // path. Instances of this case we convert with this script. Functions
>>>>
>>>> For me, sounds a bit like "other things we don't convert".
>>>> Actually we convert other things too.
>>>
>>> What other patterns of error propagation do we convert?
>>
>> Something like in xen_block_device_destroy, why not? Otherwise, it's better to avoid
>> matching things like xen_block_device_destroy, not just warn them.
>> But I'd prefer to proceed now as is to fit into 5.0.. Too much time already
>> spent on this. So, I'm OK with your wording too.
> 
> Let's scratch "Instances of this case we convert with this script."

OK

> 
>>>>>        // with multiple definitions or propagates we want to examine
>>>>>        // manually. Later rules emit warnings to guide us to them.
>>>>>
>>>>>> +@rule1 disable optional_qualifier exists@
>>>>>> +identifier fn, local_err;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error **
>>>>>> +-    errp
>>>>>> ++    ____
>>>>>> +    , ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> +     Error *local_err = NULL;
>>>>>> +     ...
>>>>>> +(
>>>>>> +     error_propagate_prepend(errp, local_err, ...);
>>>>>> +|
>>>>>> +     error_propagate(errp, local_err);
>>>>>> +)
>>>>>> +     ...
>>>>>> + }
>>>>>> +
>>>>>> +
>>>>>> +// Warn several Error * definitions.
>>>>>> +@check1 disable optional_qualifier exists@
>>>>>> +identifier fn = rule1.fn, local_err, local_err2;
>>>>>
>>>>> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
>>>>> particular reason for the difference?
>>>>
>>>> I didn't find other way to ref check1.fn in next python rule. It just don't
>>>> work if I write here just rule1.fn.
>>>>
>>>>>
>>>>> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
>>>>> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
>>>>> everywhere, then apply the script to the complete tree, I get the same
>>>>> result.
>>>>
>>>> I think, it's more efficient to reuse names from previous rules. I think it should
>>>> work faster (more information, less extra matching).
>>>
>>> Nope.  With my hacked up script (patch appended) Coccinelle is actually
>>> *faster* for the .[ch] touched by this series: with your unmodified
>>> script, it takes a bit over 12s on my box, with mine around 7s.  Output
>>> is identical.
>>>
>>> Never guess performance, always measure it :)
>>
>> Hmm, whole tree results would be better proof
>>
>>>
>>> Two notes on my script:
>>>
>>> * Unlike yours, it recognizes double-propagation in my test case.
>>>     Discussed below.
>>>
>>> * Its "several definitions of" warning includes positions.  That turned
>>>     out to be useless, but I've been too lazy to take that out again.
>>>
>>>>>
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> +     Error *local_err = NULL;
>>>>>> +     ... when any
>>>>>> +     Error *local_err2 = NULL;
>>>>>> +     ... when any
>>>>>> + }
> 
> This flags functions that have more than one declaration along any
> control flow path.  It doesn't flag this one:
> 
>      void gnat(bool b, Error **errp)
>      {
>          if (b) {
>              Error *local_err = NULL;
>              foo(arg, &local_err);
>              error_propagate(errp, local_err);
>          } else {
>              Error *local_err = NULL;
>              bar(arg, &local_err);
>              error_propagate(errp, local_err);
>          }
>      }
> 
> The Coccinelle script does the right thing for this one regardless.
> 
> I'd prefer to have such functions flagged, too.  But spending time on
> convincing Coccinelle to do it for me is not worthwhile; I can simply
> search the diff produced by Coccinelle for deletions of declarations
> that are not indented exactly four spaces.
> 
> But if we keep this rule, we should adjust its comment
> 
>      // Warn several Error * definitions.
> 
> because it sure suggests it also catches functions like the one I gave
> above.

Hmm, yes.. We can write "Warn several Error * definitions in _one_ 
control flow (it's not so trivial to match _any_ case with several 
definitions with coccinelle)" or something like this.

> 
>>>>>> +
>>>>>> +@ script:python @
>>>>>> +fn << check1.fn;
>>>>>> +@@
>>>>>> +
>>>>>> +print('Warning: function {} has several definitions of '
>>>>>> +      'Error * local variable'.format(fn))
>>>>>> +
>>>>>> +// Warn several propagations in control flow.
>>>>>> +@check2 disable optional_qualifier exists@
>>>>>> +identifier fn = rule1.fn;
>>>>>> +symbol errp;
>>>>>> +position p1, p2;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> +(
>>>>>> +     error_propagate_prepend(errp, ...);@p1
>>>>>> +|
>>>>>> +     error_propagate(errp, ...);@p1
>>>>>> +)
>>>>>> +     ...
>>>>>> +(
>>>>>> +     error_propagate_prepend(errp, ...);@p2
>>>>>> +|
>>>>>> +     error_propagate(errp, ...);@p2
>>>>>> +)
>>>>>> +     ... when any
>>>>>> + }
>>>>>> +
>>>>>
>>>>> Hmm, we don't catch the example I used in review of v8:
>>>>>
>>>>>        extern foo(int, Error **);
>>>>>        extern bar(int, Error **);
>>>>>
>>>>>        void frob(Error **errp)
>>>>>        {
>>>>>            Error *local_err = NULL;
>>>>>            int arg;
>>>>>
>>>>>            foo(arg, errp);
>>>>>            bar(arg, &local_err);
>>>>>            error_propagate(errp, local_err);
>>>>>            bar(arg + 1, &local_err);
>>>>>            error_propagate(errp, local_err);
>>>>>        }
>>>>>
>>>>> I believe this is because rule1 does not match here.
>>>>
>>>> Yes, rule1 wants at least one code flow with non-doubled propagation.
>>>>
>>>>>
>>>>> If I change the rule as follows, it catches the example:
>>>>>
>>>>>        @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
>>>>>
>>>>>         // Warn several propagations in control flow.
>>>>>         @check2 disable optional_qualifier exists@
>>>>>        -identifier fn = rule1.fn;
>>>>>        -symbol errp;
>>>>>        +identifier fn, _errp;
>>>>>         position p1, p2;
>>>>>         @@
>>>>>
>>>>>        - fn(..., Error ** ____, ...)
>>>>>        + fn(..., Error **_errp, ...)
>>>>>          {
>>>>>              ...
>>>>>         (
>>>>>        -     error_propagate_prepend(errp, ...);@p1
>>>>>        +     error_propagate_prepend(_errp, ...);@p1
>>>>>         |
>>>>>        -     error_propagate(errp, ...);@p1
>>>>>        +     error_propagate(_errp, ...);@p1
>>>>>         )
>>>>>              ...
>>>>>         (
>>>>>        -     error_propagate_prepend(errp, ...);@p2
>>>>>        +     error_propagate_prepend(_errp, ...);@p2
>>>>>         |
>>>>>        -     error_propagate(errp, ...);@p2
>>>>>        +     error_propagate(_errp, ...);@p2
>>>>>         )
>>>>>              ... when any
>>>>>          }
>>>>>
>>>>> To my mild surprise, it still doesn't find anything in our tree.
>>>>>
>>>>> Should we decouple the previous rule from rule1, too?  I tested the
>>>>> following on the whole tree:
>>>>
>>>> I don't think so. Why to check what we are not going to convert? If we want
>>>> to check side things, it's better to do it in other coccinelle script..
>>>
>>> Misunderstanding?  The rules are still chained together via the ___
>>> hack, just not via function name, because that's unreliable and
>>> redundant.
>>
>> Strange.. Then, how can it match something not matched by rule1?
> 
> I think I got confused when I wrote the "Misunderstanding?" paragraph.
> 
> Let me try again.
> 
> First rule check2.
> 
> The common case is a at most one propagation to @errp along any control
> flow path.  We trust your Coccinelle script to convert that alright.
> 
> Any other propagation to @errp I want to review.  Whether the script
> attempts a conversion or not is unimportant, as long as it points me to
> the function to review.
> 
> Rule rule1 matches functions that propagate to @errp once along at least
> one control flow path.
> 
> Unchained from rule rule1, rule check2 flags any function that
> propagates to @errp multiple times along any control flow path.
> 
> Chained to rule1, it flags only functions that also have a path with
> single propagation.
> 
> In other words, the unchained rule flags *all* multi-propagations to
> @errp, while the chained rule flags only the ones the script attempts to
> convert.  The former is much more useful to me.
> 
> Now rule check1.  It flags functions with multiple declarations along
> any control flow path.  Again, chaining it to rule1 restricts it to the
> functions we attempt to convert.  Makes it less useful to me.  However,
> because my desire to review multiple declarations in function we don't
> attempt to convert is lower than my desire to review multiple
> propagations to @errp in such functions, chaining check1 is tolerable
> for me.  But why chain check1 if we don't chain check2?
> 

OK, let's unchain them.

>>
>>>
>>>>>
>>>>>        @@ -136,10 +136,10 @@ symbol errp;
>>>>>
>>>>>         // Warn several Error * definitions.
>>>>>         @check1 disable optional_qualifier exists@
>>>>>        -identifier fn = rule1.fn, local_err, local_err2;
>>>>>        +identifier fn, _errp, local_err, local_err2;
>>>>>         @@
>>>>>
>>>>>        - fn(..., Error ** ____, ...)
>>>>>        + fn(..., Error **_errp, ...)
>>>>>          {
>>>>>              ...
>>>>>              Error *local_err = NULL;
>>>>>
>>>>> Warnings remain unchanged.
>>>>>
>>>>>> +@ script:python @
>>>>>> +fn << check2.fn;
>>>>>> +p1 << check2.p1;
>>>>>> +p2 << check2.p2;
>>>>>> +@@
>>>>>> +
>>>>>> +print('Warning: function {} propagates to errp several times in '
>>>>>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>>>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>>>> +
>>>>>> +// Convert special case with goto separately.
>>>>>> +// I tried merging this into the following rule the obvious way, but
>>>>>> +// it made Coccinelle hang on block.c
>>>>>> +//
>>>>>> +// Note interesting thing: if we don't do it here, and try to fixup
>>>>>> +// "out: }" things later after all transformations (the rule will be
>>>>>> +// the same, just without error_propagate() call), coccinelle fails to
>>>>>> +// match this "out: }".
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn, rule1.local_err, out;
>>>>>
>>>>> As explained above, I doubt the need for rule1.fn.  We do need
>>>>> rule1.local_err to avoid unwanted transformations.  More of the same
>>>>> below.
>>>>
>>>> Logically, I want to inherit from rule1. So why not to stress it by inheriting
>>>> fn variable? It's just a correct thing to do.
>>>> And I hope it helps coccinelle to work more efficiently.
>>>>
>>>>>
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +-    goto out;
>>>>>> ++    return;
>>>>>> +     ...>
>>>>>> +- out:
>>>>>> +-    error_propagate(errp, local_err);
>>>>>> + }
>>>>>> +
>>>>>> +// Convert most of local_err related stuff.
>>>>>> +//
>>>>>> +// Note, that we update everything related to matched by rule1
>>>>>> +// function name and local_err name. We may match something not
>>>>>> +// related to the pattern matched by rule1. For example, local_err may
>>>>>> +// be defined with the same name in different blocks inside one
>>>>>> +// function, and in one block follow the propagation pattern and in
>>>>>> +// other block doesn't. Or we may have several functions with the same
>>>>>> +// name (for different configurations).
>>>>>> +//
>>>>>> +// Note also that errp-cleaning functions
>>>>>> +//   error_free_errp
>>>>>> +//   error_report_errp
>>>>>> +//   error_reportf_errp
>>>>>> +//   warn_report_errp
>>>>>> +//   warn_reportf_errp
>>>>>> +// are not yet implemented. They must call corresponding Error* -
>>>>>> +// freeing function and then set *errp to NULL, to avoid further
>>>>>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>>>>> +// For example, error_free_errp may look like this:
>>>>>> +//
>>>>>> +//    void error_free_errp(Error **errp)
>>>>>> +//    {
>>>>>> +//        error_free(*errp);
>>>>>> +//        *errp = NULL;
>>>>>> +//    }
>>>>>> +@ disable optional_qualifier exists@
>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>> +expression list args;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +(
>>>>>> +-    Error *local_err = NULL;
>>>>>> +|
>>>>>> +
>>>>>> +// Convert error clearing functions
>>>>>> +(
>>>>>> +-    error_free(local_err);
>>>>>> ++    error_free_errp(errp);
>>>>>> +|
>>>>>> +-    error_report_err(local_err);
>>>>>> ++    error_report_errp(errp);
>>>>>> +|
>>>>>> +-    error_reportf_err(local_err, args);
>>>>>> ++    error_reportf_errp(errp, args);
>>>>>> +|
>>>>>> +-    warn_report_err(local_err);
>>>>>> ++    warn_report_errp(errp);
>>>>>> +|
>>>>>> +-    warn_reportf_err(local_err, args);
>>>>>> ++    warn_reportf_errp(errp, args);
>>>>>> +)
>>>>>> +?-    local_err = NULL;
>>>>>> +
>>>>>> +|
>>>>>> +-    error_propagate_prepend(errp, local_err, args);
>>>>>> ++    error_prepend(errp, args);
>>>>>> +|
>>>>>> +-    error_propagate(errp, local_err);
>>>>>> +|
>>>>>> +-    &local_err
>>>>>> ++    errp
>>>>>> +)
>>>>>> +     ...>
>>>>>> + }
>>>>>> +
>>>>>> +// Convert remaining local_err usage. For example, different kinds of
>>>>>> +// error checking in if conditionals. We can't merge this into
>>>>>> +// previous hunk, as this conflicts with other substitutions in it (at
>>>>>> +// least with "- local_err = NULL").
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +-    local_err
>>>>>> ++    *errp
>>>>>> +     ...>
>>>>>> + }
>>>>>> +
>>>>>> +// Always use the same pattern for checking error
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +-    *errp != NULL
>>>>>> ++    *errp
>>>>>> +     ...>
>>>>>> + }
>>>>>> +
>>>>>> +// Revert temporary ___ identifier.
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error **
>>>>>> +-   ____
>>>>>> ++   errp
>>>>>> +    , ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> + }
>>>>>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>>>>>> index 30140d9bfe..56c133520d 100644
>>>>>> --- a/include/qapi/error.h
>>>>>> +++ b/include/qapi/error.h
>>>>>> @@ -214,6 +214,9 @@
>>>>>>      *         }
>>>>>>      *         ...
>>>>>>      *     }
>>>>>> + *
>>>>>> + * For mass-conversion use script
>>>>>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>      */
>>>>>>       #ifndef ERROR_H
>>>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>>>> index 857f969aa1..047f1b9714 100644
>>>>>> --- a/MAINTAINERS
>>>>>> +++ b/MAINTAINERS
>>>>>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>>>>>     F: qapi/error.json
>>>>>>     F: util/error.c
>>>>>>     F: util/qemu-error.c
>>>>>> +F: scripts/coccinelle/*err*.cocci
>>>>>>       GDB stub
>>>>>>     M: Alex Bennée <alex.bennee@linaro.org>
>>>>>
>>>
>>>
>>>   From 42a08c529024337d1b859839c9ce7f797f784555 Mon Sep 17 00:00:00 2001
>>> From: Markus Armbruster <armbru@redhat.com>
>>> Date: Fri, 13 Mar 2020 14:27:57 +0100
>>> Subject: [PATCH] fixup! scripts: Coccinelle script to use
>>>    ERRP_AUTO_PROPAGATE()
>>>
>>> ---
>>>    scripts/coccinelle/auto-propagated-errp.cocci | 37 ++++++++++---------
>>>    1 file changed, 20 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>> index 7dac2dcfa4..43b0b0e63b 100644
>>> --- a/scripts/coccinelle/auto-propagated-errp.cocci
>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>> @@ -136,45 +136,48 @@ symbol errp;
>>>      // Warn several Error * definitions.
>>>    @check1 disable optional_qualifier exists@
>>> -identifier fn = rule1.fn, local_err, local_err2;
>>> +identifier fn, _errp, local_err, local_err2;
>>> +position p1, p2;
>>
>>
>> Hmm, seems like I forget to define ____ as symbol in my patch
> 
> Coccinelle defaults to symbol.

But for errp we saw warnings simetimes.

> 
>>>    @@
>>>    - fn(..., Error ** ____, ...)
>>> + fn(..., Error **_errp, ...)
>>
>> Ahmm.. it will break compilation?
>>
>> Or, how will it work when _errp defined as meta variable is only in "+..." line? Should it be symbol instead, or just not defined?
> 
> Misunderstanding?  It's a diff between your .cocci and mine. 

Oops, yes, sorry. Patches to coccinelle scripts are tricky thing.

> My version
> is
> 
>      // Warn several Error * definitions.
>      @check1 disable optional_qualifier exists@
>      identifier fn, _errp, local_err, local_err2;
>      position p1, p2;
>      @@
> 
>       fn(..., Error **_errp, ...)
>       {
>           ...
>           Error *local_err = NULL;@p1
>           ... when any
>           Error *local_err2 = NULL;@p2
>           ... when any
>       }
> 
>      @ script:python @
>      fn << check1.fn;
>      p1 << check1.p1;
>      p2 << check1.p2;
>      @@
> 
>>>     {
>>>         ...
>>> -     Error *local_err = NULL;
>>> +     Error *local_err = NULL;@p1
>>
>> Why to do -/+ here? Nothing changed..
>>
>>>         ... when any
>>> -     Error *local_err2 = NULL;
>>> +     Error *local_err2 = NULL;@p2
>>>         ... when any
>>>     }
>>>      @ script:python @
>>>    fn << check1.fn;
>>> +p1 << check1.p1;
>>> +p2 << check1.p2;
>>>    @@
>>>      print('Warning: function {} has several definitions of '
>>> -      'Error * local variable'.format(fn))
>>> +      'Error * local variable: at {}:{} and then at {}:{}'.format(
>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>      // Warn several propagations in control flow.
>>>    @check2 disable optional_qualifier exists@
>>> -identifier fn = rule1.fn;
>>> -symbol errp;
>>> +identifier fn, _errp;
>>>    position p1, p2;
>>>    @@
>>>    - fn(..., Error ** ____, ...)
>>> + fn(..., Error **_errp, ...)
>>>     {
>>>         ...
>>>    (
>>> -     error_propagate_prepend(errp, ...);@p1
>>> +     error_propagate_prepend(_errp, ...);@p1
>>>    |
>>> -     error_propagate(errp, ...);@p1
>>> +     error_propagate(_errp, ...);@p1
>>>    )
>>>         ...
>>>    (
>>> -     error_propagate_prepend(errp, ...);@p2
>>> +     error_propagate_prepend(_errp, ...);@p2
>>>    |
>>> -     error_propagate(errp, ...);@p2
>>> +     error_propagate(_errp, ...);@p2
>>>    )
>>
>> You change some occurrences of errp to _errp, but not all. It breaks compilation.
>>
>>>         ... when any
>>>     }
>>> @@ -198,7 +201,7 @@ print('Warning: function {} propagates to errp several times in '
>>>    // the same, just without error_propagate() call), coccinelle fails to
>>>    // match this "out: }".
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn, rule1.local_err, out;
>>> +identifier fn, rule1.local_err, out;
>>
>> Hmm. If it improves performance it is strange.. But I can live with this change.
>>
>>>    symbol errp;
>>>    @@
>>>    @@ -239,7 +242,7 @@ symbol errp;
>>>    //        *errp = NULL;
>>>    //    }
>>>    @ disable optional_qualifier exists@
>>> -identifier rule1.fn, rule1.local_err;
>>> +identifier fn, rule1.local_err;
>>>    expression list args;
>>>    symbol errp;
>>>    @@
>>> @@ -287,7 +290,7 @@ symbol errp;
>>>    // previous hunk, as this conflicts with other substitutions in it (at
>>>    // least with "- local_err = NULL").
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn, rule1.local_err;
>>> +identifier fn, rule1.local_err;
>>>    symbol errp;
>>>    @@
>>>    @@ -301,7 +304,7 @@ symbol errp;
>>>      // Always use the same pattern for checking error
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn;
>>> +identifier fn;
>>>    symbol errp;
>>>    @@
>>>    @@ -315,7 +318,7 @@ symbol errp;
>>>      // Revert temporary ___ identifier.
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn;
>>> +identifier fn;
>>>    @@
>>>       fn(..., Error **
>>>
> 
> I append my hacked up version of auto-propagated-errp.cocci.  It
> produces the same patch as yours for the complete tree.
> 
> 
> 
> // Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
> //
> // Copyright (c) 2020 Virtuozzo International GmbH.
> //
> // This program is free software; you can redistribute it and/or
> // modify it under the terms of the GNU General Public License as
> // published by the Free Software Foundation; either version 2 of the
> // License, or (at your option) any later version.
> //
> // This program is distributed in the hope that it will be useful,
> // but WITHOUT ANY WARRANTY; without even the implied warranty of
> // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> // GNU General Public License for more details.
> //
> // You should have received a copy of the GNU General Public License
> // along with this program.  If not, see
> // <http://www.gnu.org/licenses/>.
> //
> // Usage example:
> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
> //  --macro-file scripts/cocci-macro-file.h --in-place \
> //  --no-show-diff --max-width 80 FILES...
> //
> // Note: --max-width 80 is needed because coccinelle default is less
> // than 80, and without this parameter coccinelle may reindent some
> // lines which fit into 80 characters but not to coccinelle default,
> // which in turn produces extra patch hunks for no reason.
> 
> // Switch unusual Error ** parameter names to errp
> // (this is necessary to use ERRP_AUTO_PROPAGATE).
> //
> // Disable optional_qualifier to skip functions with
> // "Error *const *errp" parameter.
> //
> // Skip functions with "assert(_errp && *_errp)" statement, because
> // that signals unusual semantics, and the parameter name may well
> // serve a purpose. (like nbd_iter_channel_error()).
> //
> // Skip util/error.c to not touch, for example, error_propagate() and
> // error_propagate_prepend().
> @ depends on !(file in "util/error.c") disable optional_qualifier@
> identifier fn;
> identifier _errp != errp;
> @@
> 
>   fn(...,
> -   Error **_errp
> +   Error **errp
>      ,...)
>   {
> (
>       ... when != assert(_errp && *_errp)
> &
>       <...
> -    _errp
> +    errp
>       ...>
> )
>   }
> 
> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
> // necessary
> //
> // Note, that without "when any" the final "..." does not mach
> // something matched by previous pattern, i.e. the rule will not match
> // double error_prepend in control flow like in
> // vfio_set_irq_signaling().
> //
> // Note, "exists" says that we want apply rule even if it matches not
> // on all possible control flows (otherwise, it will not match
> // standard pattern when error_propagate() call is in if branch).
> @ disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
> 
>   fn(..., Error **errp, ...)
>   {
> +   ERRP_AUTO_PROPAGATE();
>      ...  when != ERRP_AUTO_PROPAGATE();
> (
> (
>      error_append_hint(errp, ...);
> |
>      error_prepend(errp, ...);
> |
>      error_vprepend(errp, ...);
> )
>      ... when any
> |
>      Error *local_err = NULL;
>      ...
> (
>      error_propagate_prepend(errp, local_err, ...);
> |
>      error_propagate(errp, local_err);
> )
>      ...
> )
>   }
> 
> 
> // Match functions with propagation of local error to errp.
> // We want to refer these functions in several following rules, but I
> // don't know a proper way to inherit a function, not just its name
> // (to not match another functions with same name in following rules).
> // Not-proper way is as follows: rename errp parameter in functions
> // header and match it in following rules. Rename it back after all
> // transformations.
> //
> // The simplest case of propagation scheme is single definition of
> // local_err with at most one error_propagate_prepend or
> // error_propagate on each control-flow. Still, we want to match more
> // complex schemes too. We'll warn them with help of further rules.
> @rule1 disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
> 
>   fn(..., Error **
> -    errp
> +    ____
>      , ...)
>   {
>       ...
>       Error *local_err = NULL;
>       ...
> (
>       error_propagate_prepend(errp, local_err, ...);
> |
>       error_propagate(errp, local_err);
> )
>       ...
>   }
> 
> 
> // Warn several Error * definitions.
> @check1 disable optional_qualifier exists@
> identifier fn, _errp, local_err, local_err2;
> position p1, p2;
> @@
> 
>   fn(..., Error **_errp, ...)
>   {
>       ...
>       Error *local_err = NULL;@p1
>       ... when any
>       Error *local_err2 = NULL;@p2
>       ... when any
>   }
> 
> @ script:python @
> fn << check1.fn;
> p1 << check1.p1;
> p2 << check1.p2;
> @@
> 
> print('Warning: function {} has several definitions of '
>        'Error * local variable: at {}:{} and then at {}:{}'.format(
>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> 
> // Warn several propagations in control flow.
> @check2 disable optional_qualifier exists@
> identifier fn, _errp;
> position p1, p2;
> @@
> 
>   fn(..., Error **_errp, ...)
>   {
>       ...
> (
>       error_propagate_prepend(_errp, ...);@p1
> |
>       error_propagate(_errp, ...);@p1
> )
>       ...
> (
>       error_propagate_prepend(_errp, ...);@p2
> |
>       error_propagate(_errp, ...);@p2
> )
>       ... when any
>   }
> 
> @ script:python @
> fn << check2.fn;
> p1 << check2.p1;
> p2 << check2.p2;
> @@
> 
> print('Warning: function {} propagates to errp several times in '
>        'one control flow: at {}:{} and then at {}:{}'.format(
>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> 
> // Convert special case with goto separately.
> // I tried merging this into the following rule the obvious way, but
> // it made Coccinelle hang on block.c
> //
> // Note interesting thing: if we don't do it here, and try to fixup
> // "out: }" things later after all transformations (the rule will be
> // the same, just without error_propagate() call), coccinelle fails to
> // match this "out: }".
> @ disable optional_qualifier@
> identifier fn, rule1.local_err, out;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    goto out;
> +    return;
>       ...>
> - out:
> -    error_propagate(errp, local_err);
>   }
> 
> // Convert most of local_err related stuff.
> //
> // Note, that we update everything related to matched by rule1
> // function name and local_err name. We may match something not
> // related to the pattern matched by rule1. For example, local_err may
> // be defined with the same name in different blocks inside one
> // function, and in one block follow the propagation pattern and in
> // other block doesn't. Or we may have several functions with the same
> // name (for different configurations).
> //
> // Note also that errp-cleaning functions
> //   error_free_errp
> //   error_report_errp
> //   error_reportf_errp
> //   warn_report_errp
> //   warn_reportf_errp
> // are not yet implemented. They must call corresponding Error* -
> // freeing function and then set *errp to NULL, to avoid further
> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
> // For example, error_free_errp may look like this:
> //
> //    void error_free_errp(Error **errp)
> //    {
> //        error_free(*errp);
> //        *errp = NULL;
> //    }
> @ disable optional_qualifier exists@
> identifier fn, rule1.local_err;
> expression list args;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> (
> -    Error *local_err = NULL;
> |
> 
> // Convert error clearing functions
> (
> -    error_free(local_err);
> +    error_free_errp(errp);
> |
> -    error_report_err(local_err);
> +    error_report_errp(errp);
> |
> -    error_reportf_err(local_err, args);
> +    error_reportf_errp(errp, args);
> |
> -    warn_report_err(local_err);
> +    warn_report_errp(errp);
> |
> -    warn_reportf_err(local_err, args);// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
//
// Copyright (c) 2020 Virtuozzo International GmbH.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see
// <http://www.gnu.org/licenses/>.
//
// Usage example:
// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
//  --macro-file scripts/cocci-macro-file.h --in-place \
//  --no-show-diff --max-width 80 FILES...
//
// Note: --max-width 80 is needed because coccinelle default is less
// than 80, and without this parameter coccinelle may reindent some
// lines which fit into 80 characters but not to coccinelle default,
// which in turn produces extra patch hunks for no reason.

// Switch unusual Error ** parameter names to errp
// (this is necessary to use ERRP_AUTO_PROPAGATE).
//
// Disable optional_qualifier to skip functions with
// "Error *const *errp" parameter.
//
// Skip functions with "assert(_errp && *_errp)" statement, because
// that signals unusual semantics, and the parameter name may well
// serve a purpose. (like nbd_iter_channel_error()).
//
// Skip util/error.c to not touch, for example, error_propagate() and
// error_propagate_prepend().
@ depends on !(file in "util/error.c") disable optional_qualifier@
identifier fn;
identifier _errp != errp;
@@

  fn(...,
-   Error **_errp
+   Error **errp
     ,...)
  {
(
      ... when != assert(_errp && *_errp)
&
      <...
-    _errp
+    errp
      ...>
)
  }

// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
// necessary
//
// Note, that without "when any" the final "..." does not mach
// something matched by previous pattern, i.e. the rule will not match
// double error_prepend in control flow like in
// vfio_set_irq_signaling().
//
// Note, "exists" says that we want apply rule even if it matches not
// on all possible control flows (otherwise, it will not match
// standard pattern when error_propagate() call is in if branch).
@ disable optional_qualifier exists@
identifier fn, local_err;
symbol errp;
@@

  fn(..., Error **errp, ...)
  {
+   ERRP_AUTO_PROPAGATE();
     ...  when != ERRP_AUTO_PROPAGATE();
(
(
     error_append_hint(errp, ...);
|
     error_prepend(errp, ...);
|
     error_vprepend(errp, ...);
)
     ... when any
|
     Error *local_err = NULL;
     ...
(
     error_propagate_prepend(errp, local_err, ...);
|
     error_propagate(errp, local_err);
)
     ...
)
  }


// Match functions with propagation of local error to errp.
// We want to refer these functions in several following rules, but I
// don't know a proper way to inherit a function, not just its name
// (to not match another functions with same name in following rules).
// Not-proper way is as follows: rename errp parameter in functions
// header and match it in following rules. Rename it back after all
// transformations.
//
// The simplest case of propagation scheme is single definition of
// local_err with at most one error_propagate_prepend or
// error_propagate on each control-flow. Still, we want to match more
// complex schemes too. We'll warn them with help of further rules.
@rule1 disable optional_qualifier exists@
identifier fn, local_err;
symbol errp;
@@

  fn(..., Error **
-    errp
+    ____
     , ...)
  {
      ...
      Error *local_err = NULL;
      ...
(
      error_propagate_prepend(errp, local_err, ...);
|
      error_propagate(errp, local_err);
)
      ...
  }


// Warn several Error * definitions.
@check1 disable optional_qualifier exists@
identifier fn, _errp, local_err, local_err2;
position p1, p2;
@@

  fn(..., Error **_errp, ...)
  {
      ...
      Error *local_err = NULL;@p1
      ... when any
      Error *local_err2 = NULL;@p2
      ... when any
  }

@ script:python @
fn << check1.fn;
p1 << check1.p1;
p2 << check1.p2;
@@

print('Warning: function {} has several definitions of '
       'Error * local variable: at {}:{} and then at {}:{}'.format(
           fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))

// Warn several propagations in control flow.
@check2 disable optional_qualifier exists@
identifier fn, _errp;
position p1, p2;
@@

  fn(..., Error **_errp, ...)
  {
      ...
(
      error_propagate_prepend(_errp, ...);@p1
|
      error_propagate(_errp, ...);@p1
)
      ...
(
      error_propagate_prepend(_errp, ...);@p2
|
      error_propagate(_errp, ...);@p2
)
      ... when any
  }

@ script:python @
fn << check2.fn;
p1 << check2.p1;
p2 << check2.p2;
@@

print('Warning: function {} propagates to errp several times in '
       'one control flow: at {}:{} and then at {}:{}'.format(
           fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))

// Convert special case with goto separately.
// I tried merging this into the following rule the obvious way, but
// it made Coccinelle hang on block.c
//
// Note interesting thing: if we don't do it here, and try to fixup
// "out: }" things later after all transformations (the rule will be
// the same, just without error_propagate() call), coccinelle fails to
// match this "out: }".
@ disable optional_qualifier@
identifier fn, rule1.local_err, out;
symbol errp;
@@

  fn(..., Error ** ____, ...)
  {
      <...
-    goto out;
+    return;
      ...>
- out:
-    error_propagate(errp, local_err);
  }

// Convert most of local_err related stuff.
//
// Note, that we update everything related to matched by rule1
// function name and local_err name. We may match something not
// related to the pattern matched by rule1. For example, local_err may
// be defined with the same name in different blocks inside one
// function, and in one block follow the propagation pattern and in
// other block doesn't. Or we may have several functions with the same
// name (for different configurations).
//
// Note also that errp-cleaning functions
//   error_free_errp
//   error_report_errp
//   error_reportf_errp
//   warn_report_errp
//   warn_reportf_errp
// are not yet implemented. They must call corresponding Error* -
// freeing function and then set *errp to NULL, to avoid further
// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
// For example, error_free_errp may look like this:
//
//    void error_free_errp(Error **errp)
//    {
//        error_free(*errp);
//        *errp = NULL;
//    }
@ disable optional_qualifier exists@
identifier fn, rule1.local_err;
expression list args;
symbol errp;
@@

  fn(..., Error ** ____, ...)
  {
      <...
(
-    Error *local_err = NULL;
|

// Convert error clearing functions
(
-    error_free(local_err);
+    error_free_errp(errp);
|
-    error_report_err(local_err);
+    error_report_errp(errp);
|
-    error_reportf_err(local_err, args);
+    error_reportf_errp(errp, args);
|
-    warn_report_err(local_err);
+    warn_report_errp(errp);
|
-    warn_reportf_err(local_err, args);
+    warn_reportf_errp(errp, args);
)
?-    local_err = NULL;

|
-    error_propagate_prepend(errp, local_err, args);
+    error_prepend(errp, args);
|
-    error_propagate(errp, local_err);
|
-    &local_err
+    errp
)
      ...>
  }

// Convert remaining local_err usage. For example, different kinds of
// error checking in if conditionals. We can't merge this into
// previous hunk, as this conflicts with other substitutions in it (at
// least with "- local_err = NULL").
@ disable optional_qualifier@
identifier fn, rule1.local_err;
symbol errp;
@@

  fn(..., Error ** ____, ...)
  {
      <...
-    local_err
+    *errp
      ...>
  }

// Always use the same pattern for checking error
@ disable optional_qualifier@
identifier fn;
symbol errp;
@@

  fn(..., Error ** ____, ...)
  {
      <...
-    *errp != NULL
+    *errp
      ...>
  }

// Revert temporary ___ identifier.
@ disable optional_qualifier@
identifier fn;
@@

  fn(..., Error **
-   ____
+   errp
     , ...)
  {
      ...
  }

> +    warn_reportf_errp(errp, args);
> )
> ?-    local_err = NULL;
> 
> |
> -    error_propagate_prepend(errp, local_err, args);
> +    error_prepend(errp, args);
> |
> -    error_propagate(errp, local_err);
> |
> -    &local_err
> +    errp
> )
>       ...>
>   }
> 
> // Convert remaining local_err usage. For example, different kinds of
> // error checking in if conditionals. We can't merge this into
> // previous hunk, as this conflicts with other substitutions in it (at
> // least with "- local_err = NULL").
> @ disable optional_qualifier@
> identifier fn, rule1.local_err;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    local_err
> +    *errp
>       ...>
>   }
> 
> // Always use the same pattern for checking error
> @ disable optional_qualifier@
> identifier fn;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    *errp != NULL
> +    *errp
>       ...>
>   }
> 
> // Revert temporary ___ identifier.
> @ disable optional_qualifier@
> identifier fn;
> @@
> 
>   fn(..., Error **
> -   ____
> +   errp
>      , ...)
>   {
>       ...
>   }
> 

OK, I almost OK with it, the only thing I doubt a bit is the following:

We want to keep rule1.local_err inheritance to keep connection with
local_err definition.

Interesting, when we have both rule1.fn and rule1.local_err inherited,
do we inherit them in separate (i.e. all possible combinations of fn
and local_err symbols from rule1) or do we inherit a pair, i.e. only
fn/local_err pairs, found by rule1? If the latter is correct, that
with your script we loss this pair inheritance, and go to all possible
combinations of fn and local_err from rule1, possibly adding some wrong
conversion (OK, you've checked that no such cases in current code tree).

So, dropping inheritance in check-rules makes sence, as it may match 
(and warn) more interesting cases.

But for other rules, I'd prefere to be safer, and explictly inherit all
actually inherited identifiers.. Still, I feel, we'll never be 
absolutely safe with coccinelle :)

--
Best regrads,
Vladimir


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-16  7:12               ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-16  7:12 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Laszlo Ersek, Christian Schoenebeck, Michael Roth, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger



On 14.03.2020 00:54, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> 13.03.2020 18:42, Markus Armbruster wrote:
>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>
>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>> out now as is.
>>>>>
>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>
>>>>>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>>>>>> does corresponding changes in code (look for details in
>>>>>> include/qapi/error.h)
>>>>>>
>>>>>> Usage example:
>>>>>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>>     --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>>>>>     --max-width 80 FILES...
>>>>>>
>>>>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>>>>> ---
>>>>>>
>>>>>> Cc: Eric Blake <eblake@redhat.com>
>>>>>> Cc: Kevin Wolf <kwolf@redhat.com>
>>>>>> Cc: Max Reitz <mreitz@redhat.com>
>>>>>> Cc: Greg Kurz <groug@kaod.org>
>>>>>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>>>>>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>>>>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>>>>> Cc: Paul Durrant <paul@xen.org>
>>>>>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>>>>>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>>>>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>>>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>>>>>> Cc: Markus Armbruster <armbru@redhat.com>
>>>>>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>>>>>> Cc: qemu-devel@nongnu.org
>>>>>> Cc: qemu-block@nongnu.org
>>>>>> Cc: xen-devel@lists.xenproject.org
>>>>>>
>>>>>>     scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>>>>>     include/qapi/error.h                          |   3 +
>>>>>>     MAINTAINERS                                   |   1 +
>>>>>>     3 files changed, 331 insertions(+)
>>>>>>     create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>
>>>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>> new file mode 100644
>>>>>> index 0000000000..7dac2dcfa4
>>>>>> --- /dev/null
>>>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>> @@ -0,0 +1,327 @@
>>>>>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>>>>> +//
>>>>>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>>>>>> +//
>>>>>> +// This program is free software; you can redistribute it and/or
>>>>>> +// modify it under the terms of the GNU General Public License as
>>>>>> +// published by the Free Software Foundation; either version 2 of the
>>>>>> +// License, or (at your option) any later version.
>>>>>> +//
>>>>>> +// This program is distributed in the hope that it will be useful,
>>>>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>>>> +// GNU General Public License for more details.
>>>>>> +//
>>>>>> +// You should have received a copy of the GNU General Public License
>>>>>> +// along with this program.  If not, see
>>>>>> +// <http://www.gnu.org/licenses/>.
>>>>>> +//
>>>>>> +// Usage example:
>>>>>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>>>>>> +//  --no-show-diff --max-width 80 FILES...
>>>>>> +//
>>>>>> +// Note: --max-width 80 is needed because coccinelle default is less
>>>>>> +// than 80, and without this parameter coccinelle may reindent some
>>>>>> +// lines which fit into 80 characters but not to coccinelle default,
>>>>>> +// which in turn produces extra patch hunks for no reason.
>>>>>
>>>>> This is about unwanted reformatting of parameter lists due to the ___
>>>>> chaining hack.  --max-width 80 makes that less likely, but not
>>>>> impossible.
>>>>>
>>>>> We can search for unwanted reformatting of parameter lists.  I think
>>>>> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
>>>>> tree, I get one false positive (not a parameter list), and one hit:
>>>>>
>>>>>        @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>>>>>             }
>>>>>         }
>>>>>
>>>>>        -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>>>>>        +void object_apply_global_props(Object *obj, const GPtrArray *props,
>>>>>        +                               Error **errp)
>>>>>         {
>>>>>        +    ERRP_AUTO_PROPAGATE();
>>>>>             int i;
>>>>>
>>>>>             if (!props) {
>>>>>
>>>>> Reformatting, but not unwanted.
>>>>
>>>> Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
>>>> ERRP_AUTO_PROPAGATE addition even for non-automatic patch.
>>>
>>> Agree.
>>>
>>>>>
>>>>> The --max-width 80 hack is good enough for me.
>>>>>
>>>>> It does result in slightly long transformed lines, e.g. this one in
>>>>> replication.c:
>>>>>
>>>>>        @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>>>>>                 s->mode = REPLICATION_MODE_PRIMARY;
>>>>>                 top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>>>>>                 if (top_id) {
>>>>>        -            error_setg(&local_err, "The primary side does not support option top-id");
>>>>>        +            error_setg(errp, "The primary side does not support option top-id");
>>>>>                     goto fail;
>>>>>                 }
>>>>>             } else if (!strcmp(mode, "secondary")) {
>>>>>
>>>>> v8 did break this line (that's how I found it).  However, v9 still
>>>>> shortens the line, just not below the target.  All your + lines look
>>>>> quite unlikely to lengthen lines.  Let's not worry about this.
>>>>>
>>>>>> +// Switch unusual Error ** parameter names to errp
>>>>>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>>>>>> +//
>>>>>> +// Disable optional_qualifier to skip functions with
>>>>>> +// "Error *const *errp" parameter.
>>>>>> +//
>>>>>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>>>>>> +// that signals unusual semantics, and the parameter name may well
>>>>>> +// serve a purpose. (like nbd_iter_channel_error()).
>>>>>> +//
>>>>>> +// Skip util/error.c to not touch, for example, error_propagate() and
>>>>>> +// error_propagate_prepend().
>>>>>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>>>>>> +identifier fn;
>>>>>> +identifier _errp != errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(...,
>>>>>> +-   Error **_errp
>>>>>> ++   Error **errp
>>>>>> +    ,...)
>>>>>> + {
>>>>>> +(
>>>>>> +     ... when != assert(_errp && *_errp)
>>>>>> +&
>>>>>> +     <...
>>>>>> +-    _errp
>>>>>> ++    errp
>>>>>> +     ...>
>>>>>> +)
>>>>>> + }
>>>>>> +
>>>>>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>>>>> +// necessary
>>>>>> +//
>>>>>> +// Note, that without "when any" the final "..." does not mach
>>>>>> +// something matched by previous pattern, i.e. the rule will not match
>>>>>> +// double error_prepend in control flow like in
>>>>>> +// vfio_set_irq_signaling().
>>>>>> +//
>>>>>> +// Note, "exists" says that we want apply rule even if it matches not
>>>>>> +// on all possible control flows (otherwise, it will not match
>>>>>> +// standard pattern when error_propagate() call is in if branch).
>>>>>> +@ disable optional_qualifier exists@
>>>>>> +identifier fn, local_err;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error **errp, ...)
>>>>>> + {
>>>>>> ++   ERRP_AUTO_PROPAGATE();
>>>>>> +    ...  when != ERRP_AUTO_PROPAGATE();
>>>>>> +(
>>>>>> +(
>>>>>> +    error_append_hint(errp, ...);
>>>>>> +|
>>>>>> +    error_prepend(errp, ...);
>>>>>> +|
>>>>>> +    error_vprepend(errp, ...);
>>>>>> +)
>>>>>> +    ... when any
>>>>>> +|
>>>>>> +    Error *local_err = NULL;
>>>>>> +    ...
>>>>>> +(
>>>>>> +    error_propagate_prepend(errp, local_err, ...);
>>>>>> +|
>>>>>> +    error_propagate(errp, local_err);
>>>>>> +)
>>>>>> +    ...
>>>>>> +)
>>>>>> + }
>>>>>> +
>>>>>> +
>>>>>> +// Match functions with propagation of local error to errp.
>>>>>> +// We want to refer these functions in several following rules, but I
>>>>>> +// don't know a proper way to inherit a function, not just its name
>>>>>> +// (to not match another functions with same name in following rules).
>>>>>> +// Not-proper way is as follows: rename errp parameter in functions
>>>>>> +// header and match it in following rules. Rename it back after all
>>>>>> +// transformations.
>>>>>> +//
>>>>>> +// The simplest case of propagation scheme is single definition of
>>>>>> +// local_err with at most one error_propagate_prepend or
>>>>>> +// error_propagate on each control-flow. Still, we want to match more
>>>>>> +// complex schemes too. We'll warn them with help of further rules.
>>>>>
>>>>> I think what we actually want is to examine instances of this pattern to
>>>>> figure out whether and how we want to transform them.  Perhaps:
>>>>>
>>>>>        // The common case is a single definition of local_err with at most one
>>>>>        // error_propagate_prepend() or error_propagate() on each control-flow
>>>>>        // path. Instances of this case we convert with this script. Functions
>>>>
>>>> For me, sounds a bit like "other things we don't convert".
>>>> Actually we convert other things too.
>>>
>>> What other patterns of error propagation do we convert?
>>
>> Something like in xen_block_device_destroy, why not? Otherwise, it's better to avoid
>> matching things like xen_block_device_destroy, not just warn them.
>> But I'd prefer to proceed now as is to fit into 5.0.. Too much time already
>> spent on this. So, I'm OK with your wording too.
> 
> Let's scratch "Instances of this case we convert with this script."

OK

> 
>>>>>        // with multiple definitions or propagates we want to examine
>>>>>        // manually. Later rules emit warnings to guide us to them.
>>>>>
>>>>>> +@rule1 disable optional_qualifier exists@
>>>>>> +identifier fn, local_err;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error **
>>>>>> +-    errp
>>>>>> ++    ____
>>>>>> +    , ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> +     Error *local_err = NULL;
>>>>>> +     ...
>>>>>> +(
>>>>>> +     error_propagate_prepend(errp, local_err, ...);
>>>>>> +|
>>>>>> +     error_propagate(errp, local_err);
>>>>>> +)
>>>>>> +     ...
>>>>>> + }
>>>>>> +
>>>>>> +
>>>>>> +// Warn several Error * definitions.
>>>>>> +@check1 disable optional_qualifier exists@
>>>>>> +identifier fn = rule1.fn, local_err, local_err2;
>>>>>
>>>>> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
>>>>> particular reason for the difference?
>>>>
>>>> I didn't find other way to ref check1.fn in next python rule. It just don't
>>>> work if I write here just rule1.fn.
>>>>
>>>>>
>>>>> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
>>>>> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
>>>>> everywhere, then apply the script to the complete tree, I get the same
>>>>> result.
>>>>
>>>> I think, it's more efficient to reuse names from previous rules. I think it should
>>>> work faster (more information, less extra matching).
>>>
>>> Nope.  With my hacked up script (patch appended) Coccinelle is actually
>>> *faster* for the .[ch] touched by this series: with your unmodified
>>> script, it takes a bit over 12s on my box, with mine around 7s.  Output
>>> is identical.
>>>
>>> Never guess performance, always measure it :)
>>
>> Hmm, whole tree results would be better proof
>>
>>>
>>> Two notes on my script:
>>>
>>> * Unlike yours, it recognizes double-propagation in my test case.
>>>     Discussed below.
>>>
>>> * Its "several definitions of" warning includes positions.  That turned
>>>     out to be useless, but I've been too lazy to take that out again.
>>>
>>>>>
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> +     Error *local_err = NULL;
>>>>>> +     ... when any
>>>>>> +     Error *local_err2 = NULL;
>>>>>> +     ... when any
>>>>>> + }
> 
> This flags functions that have more than one declaration along any
> control flow path.  It doesn't flag this one:
> 
>      void gnat(bool b, Error **errp)
>      {
>          if (b) {
>              Error *local_err = NULL;
>              foo(arg, &local_err);
>              error_propagate(errp, local_err);
>          } else {
>              Error *local_err = NULL;
>              bar(arg, &local_err);
>              error_propagate(errp, local_err);
>          }
>      }
> 
> The Coccinelle script does the right thing for this one regardless.
> 
> I'd prefer to have such functions flagged, too.  But spending time on
> convincing Coccinelle to do it for me is not worthwhile; I can simply
> search the diff produced by Coccinelle for deletions of declarations
> that are not indented exactly four spaces.
> 
> But if we keep this rule, we should adjust its comment
> 
>      // Warn several Error * definitions.
> 
> because it sure suggests it also catches functions like the one I gave
> above.

Hmm, yes.. We can write "Warn several Error * definitions in _one_ 
control flow (it's not so trivial to match _any_ case with several 
definitions with coccinelle)" or something like this.

> 
>>>>>> +
>>>>>> +@ script:python @
>>>>>> +fn << check1.fn;
>>>>>> +@@
>>>>>> +
>>>>>> +print('Warning: function {} has several definitions of '
>>>>>> +      'Error * local variable'.format(fn))
>>>>>> +
>>>>>> +// Warn several propagations in control flow.
>>>>>> +@check2 disable optional_qualifier exists@
>>>>>> +identifier fn = rule1.fn;
>>>>>> +symbol errp;
>>>>>> +position p1, p2;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> +(
>>>>>> +     error_propagate_prepend(errp, ...);@p1
>>>>>> +|
>>>>>> +     error_propagate(errp, ...);@p1
>>>>>> +)
>>>>>> +     ...
>>>>>> +(
>>>>>> +     error_propagate_prepend(errp, ...);@p2
>>>>>> +|
>>>>>> +     error_propagate(errp, ...);@p2
>>>>>> +)
>>>>>> +     ... when any
>>>>>> + }
>>>>>> +
>>>>>
>>>>> Hmm, we don't catch the example I used in review of v8:
>>>>>
>>>>>        extern foo(int, Error **);
>>>>>        extern bar(int, Error **);
>>>>>
>>>>>        void frob(Error **errp)
>>>>>        {
>>>>>            Error *local_err = NULL;
>>>>>            int arg;
>>>>>
>>>>>            foo(arg, errp);
>>>>>            bar(arg, &local_err);
>>>>>            error_propagate(errp, local_err);
>>>>>            bar(arg + 1, &local_err);
>>>>>            error_propagate(errp, local_err);
>>>>>        }
>>>>>
>>>>> I believe this is because rule1 does not match here.
>>>>
>>>> Yes, rule1 wants at least one code flow with non-doubled propagation.
>>>>
>>>>>
>>>>> If I change the rule as follows, it catches the example:
>>>>>
>>>>>        @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
>>>>>
>>>>>         // Warn several propagations in control flow.
>>>>>         @check2 disable optional_qualifier exists@
>>>>>        -identifier fn = rule1.fn;
>>>>>        -symbol errp;
>>>>>        +identifier fn, _errp;
>>>>>         position p1, p2;
>>>>>         @@
>>>>>
>>>>>        - fn(..., Error ** ____, ...)
>>>>>        + fn(..., Error **_errp, ...)
>>>>>          {
>>>>>              ...
>>>>>         (
>>>>>        -     error_propagate_prepend(errp, ...);@p1
>>>>>        +     error_propagate_prepend(_errp, ...);@p1
>>>>>         |
>>>>>        -     error_propagate(errp, ...);@p1
>>>>>        +     error_propagate(_errp, ...);@p1
>>>>>         )
>>>>>              ...
>>>>>         (
>>>>>        -     error_propagate_prepend(errp, ...);@p2
>>>>>        +     error_propagate_prepend(_errp, ...);@p2
>>>>>         |
>>>>>        -     error_propagate(errp, ...);@p2
>>>>>        +     error_propagate(_errp, ...);@p2
>>>>>         )
>>>>>              ... when any
>>>>>          }
>>>>>
>>>>> To my mild surprise, it still doesn't find anything in our tree.
>>>>>
>>>>> Should we decouple the previous rule from rule1, too?  I tested the
>>>>> following on the whole tree:
>>>>
>>>> I don't think so. Why to check what we are not going to convert? If we want
>>>> to check side things, it's better to do it in other coccinelle script..
>>>
>>> Misunderstanding?  The rules are still chained together via the ___
>>> hack, just not via function name, because that's unreliable and
>>> redundant.
>>
>> Strange.. Then, how can it match something not matched by rule1?
> 
> I think I got confused when I wrote the "Misunderstanding?" paragraph.
> 
> Let me try again.
> 
> First rule check2.
> 
> The common case is a at most one propagation to @errp along any control
> flow path.  We trust your Coccinelle script to convert that alright.
> 
> Any other propagation to @errp I want to review.  Whether the script
> attempts a conversion or not is unimportant, as long as it points me to
> the function to review.
> 
> Rule rule1 matches functions that propagate to @errp once along at least
> one control flow path.
> 
> Unchained from rule rule1, rule check2 flags any function that
> propagates to @errp multiple times along any control flow path.
> 
> Chained to rule1, it flags only functions that also have a path with
> single propagation.
> 
> In other words, the unchained rule flags *all* multi-propagations to
> @errp, while the chained rule flags only the ones the script attempts to
> convert.  The former is much more useful to me.
> 
> Now rule check1.  It flags functions with multiple declarations along
> any control flow path.  Again, chaining it to rule1 restricts it to the
> functions we attempt to convert.  Makes it less useful to me.  However,
> because my desire to review multiple declarations in function we don't
> attempt to convert is lower than my desire to review multiple
> propagations to @errp in such functions, chaining check1 is tolerable
> for me.  But why chain check1 if we don't chain check2?
> 

OK, let's unchain them.

>>
>>>
>>>>>
>>>>>        @@ -136,10 +136,10 @@ symbol errp;
>>>>>
>>>>>         // Warn several Error * definitions.
>>>>>         @check1 disable optional_qualifier exists@
>>>>>        -identifier fn = rule1.fn, local_err, local_err2;
>>>>>        +identifier fn, _errp, local_err, local_err2;
>>>>>         @@
>>>>>
>>>>>        - fn(..., Error ** ____, ...)
>>>>>        + fn(..., Error **_errp, ...)
>>>>>          {
>>>>>              ...
>>>>>              Error *local_err = NULL;
>>>>>
>>>>> Warnings remain unchanged.
>>>>>
>>>>>> +@ script:python @
>>>>>> +fn << check2.fn;
>>>>>> +p1 << check2.p1;
>>>>>> +p2 << check2.p2;
>>>>>> +@@
>>>>>> +
>>>>>> +print('Warning: function {} propagates to errp several times in '
>>>>>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>>>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>>>> +
>>>>>> +// Convert special case with goto separately.
>>>>>> +// I tried merging this into the following rule the obvious way, but
>>>>>> +// it made Coccinelle hang on block.c
>>>>>> +//
>>>>>> +// Note interesting thing: if we don't do it here, and try to fixup
>>>>>> +// "out: }" things later after all transformations (the rule will be
>>>>>> +// the same, just without error_propagate() call), coccinelle fails to
>>>>>> +// match this "out: }".
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn, rule1.local_err, out;
>>>>>
>>>>> As explained above, I doubt the need for rule1.fn.  We do need
>>>>> rule1.local_err to avoid unwanted transformations.  More of the same
>>>>> below.
>>>>
>>>> Logically, I want to inherit from rule1. So why not to stress it by inheriting
>>>> fn variable? It's just a correct thing to do.
>>>> And I hope it helps coccinelle to work more efficiently.
>>>>
>>>>>
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +-    goto out;
>>>>>> ++    return;
>>>>>> +     ...>
>>>>>> +- out:
>>>>>> +-    error_propagate(errp, local_err);
>>>>>> + }
>>>>>> +
>>>>>> +// Convert most of local_err related stuff.
>>>>>> +//
>>>>>> +// Note, that we update everything related to matched by rule1
>>>>>> +// function name and local_err name. We may match something not
>>>>>> +// related to the pattern matched by rule1. For example, local_err may
>>>>>> +// be defined with the same name in different blocks inside one
>>>>>> +// function, and in one block follow the propagation pattern and in
>>>>>> +// other block doesn't. Or we may have several functions with the same
>>>>>> +// name (for different configurations).
>>>>>> +//
>>>>>> +// Note also that errp-cleaning functions
>>>>>> +//   error_free_errp
>>>>>> +//   error_report_errp
>>>>>> +//   error_reportf_errp
>>>>>> +//   warn_report_errp
>>>>>> +//   warn_reportf_errp
>>>>>> +// are not yet implemented. They must call corresponding Error* -
>>>>>> +// freeing function and then set *errp to NULL, to avoid further
>>>>>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>>>>> +// For example, error_free_errp may look like this:
>>>>>> +//
>>>>>> +//    void error_free_errp(Error **errp)
>>>>>> +//    {
>>>>>> +//        error_free(*errp);
>>>>>> +//        *errp = NULL;
>>>>>> +//    }
>>>>>> +@ disable optional_qualifier exists@
>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>> +expression list args;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +(
>>>>>> +-    Error *local_err = NULL;
>>>>>> +|
>>>>>> +
>>>>>> +// Convert error clearing functions
>>>>>> +(
>>>>>> +-    error_free(local_err);
>>>>>> ++    error_free_errp(errp);
>>>>>> +|
>>>>>> +-    error_report_err(local_err);
>>>>>> ++    error_report_errp(errp);
>>>>>> +|
>>>>>> +-    error_reportf_err(local_err, args);
>>>>>> ++    error_reportf_errp(errp, args);
>>>>>> +|
>>>>>> +-    warn_report_err(local_err);
>>>>>> ++    warn_report_errp(errp);
>>>>>> +|
>>>>>> +-    warn_reportf_err(local_err, args);
>>>>>> ++    warn_reportf_errp(errp, args);
>>>>>> +)
>>>>>> +?-    local_err = NULL;
>>>>>> +
>>>>>> +|
>>>>>> +-    error_propagate_prepend(errp, local_err, args);
>>>>>> ++    error_prepend(errp, args);
>>>>>> +|
>>>>>> +-    error_propagate(errp, local_err);
>>>>>> +|
>>>>>> +-    &local_err
>>>>>> ++    errp
>>>>>> +)
>>>>>> +     ...>
>>>>>> + }
>>>>>> +
>>>>>> +// Convert remaining local_err usage. For example, different kinds of
>>>>>> +// error checking in if conditionals. We can't merge this into
>>>>>> +// previous hunk, as this conflicts with other substitutions in it (at
>>>>>> +// least with "- local_err = NULL").
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +-    local_err
>>>>>> ++    *errp
>>>>>> +     ...>
>>>>>> + }
>>>>>> +
>>>>>> +// Always use the same pattern for checking error
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +-    *errp != NULL
>>>>>> ++    *errp
>>>>>> +     ...>
>>>>>> + }
>>>>>> +
>>>>>> +// Revert temporary ___ identifier.
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error **
>>>>>> +-   ____
>>>>>> ++   errp
>>>>>> +    , ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> + }
>>>>>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>>>>>> index 30140d9bfe..56c133520d 100644
>>>>>> --- a/include/qapi/error.h
>>>>>> +++ b/include/qapi/error.h
>>>>>> @@ -214,6 +214,9 @@
>>>>>>      *         }
>>>>>>      *         ...
>>>>>>      *     }
>>>>>> + *
>>>>>> + * For mass-conversion use script
>>>>>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>      */
>>>>>>       #ifndef ERROR_H
>>>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>>>> index 857f969aa1..047f1b9714 100644
>>>>>> --- a/MAINTAINERS
>>>>>> +++ b/MAINTAINERS
>>>>>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>>>>>     F: qapi/error.json
>>>>>>     F: util/error.c
>>>>>>     F: util/qemu-error.c
>>>>>> +F: scripts/coccinelle/*err*.cocci
>>>>>>       GDB stub
>>>>>>     M: Alex Bennée <alex.bennee@linaro.org>
>>>>>
>>>
>>>
>>>   From 42a08c529024337d1b859839c9ce7f797f784555 Mon Sep 17 00:00:00 2001
>>> From: Markus Armbruster <armbru@redhat.com>
>>> Date: Fri, 13 Mar 2020 14:27:57 +0100
>>> Subject: [PATCH] fixup! scripts: Coccinelle script to use
>>>    ERRP_AUTO_PROPAGATE()
>>>
>>> ---
>>>    scripts/coccinelle/auto-propagated-errp.cocci | 37 ++++++++++---------
>>>    1 file changed, 20 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>> index 7dac2dcfa4..43b0b0e63b 100644
>>> --- a/scripts/coccinelle/auto-propagated-errp.cocci
>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>> @@ -136,45 +136,48 @@ symbol errp;
>>>      // Warn several Error * definitions.
>>>    @check1 disable optional_qualifier exists@
>>> -identifier fn = rule1.fn, local_err, local_err2;
>>> +identifier fn, _errp, local_err, local_err2;
>>> +position p1, p2;
>>
>>
>> Hmm, seems like I forget to define ____ as symbol in my patch
> 
> Coccinelle defaults to symbol.

But for errp we saw warnings simetimes.

> 
>>>    @@
>>>    - fn(..., Error ** ____, ...)
>>> + fn(..., Error **_errp, ...)
>>
>> Ahmm.. it will break compilation?
>>
>> Or, how will it work when _errp defined as meta variable is only in "+..." line? Should it be symbol instead, or just not defined?
> 
> Misunderstanding?  It's a diff between your .cocci and mine. 

Oops, yes, sorry. Patches to coccinelle scripts are tricky thing.

> My version
> is
> 
>      // Warn several Error * definitions.
>      @check1 disable optional_qualifier exists@
>      identifier fn, _errp, local_err, local_err2;
>      position p1, p2;
>      @@
> 
>       fn(..., Error **_errp, ...)
>       {
>           ...
>           Error *local_err = NULL;@p1
>           ... when any
>           Error *local_err2 = NULL;@p2
>           ... when any
>       }
> 
>      @ script:python @
>      fn << check1.fn;
>      p1 << check1.p1;
>      p2 << check1.p2;
>      @@
> 
>>>     {
>>>         ...
>>> -     Error *local_err = NULL;
>>> +     Error *local_err = NULL;@p1
>>
>> Why to do -/+ here? Nothing changed..
>>
>>>         ... when any
>>> -     Error *local_err2 = NULL;
>>> +     Error *local_err2 = NULL;@p2
>>>         ... when any
>>>     }
>>>      @ script:python @
>>>    fn << check1.fn;
>>> +p1 << check1.p1;
>>> +p2 << check1.p2;
>>>    @@
>>>      print('Warning: function {} has several definitions of '
>>> -      'Error * local variable'.format(fn))
>>> +      'Error * local variable: at {}:{} and then at {}:{}'.format(
>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>      // Warn several propagations in control flow.
>>>    @check2 disable optional_qualifier exists@
>>> -identifier fn = rule1.fn;
>>> -symbol errp;
>>> +identifier fn, _errp;
>>>    position p1, p2;
>>>    @@
>>>    - fn(..., Error ** ____, ...)
>>> + fn(..., Error **_errp, ...)
>>>     {
>>>         ...
>>>    (
>>> -     error_propagate_prepend(errp, ...);@p1
>>> +     error_propagate_prepend(_errp, ...);@p1
>>>    |
>>> -     error_propagate(errp, ...);@p1
>>> +     error_propagate(_errp, ...);@p1
>>>    )
>>>         ...
>>>    (
>>> -     error_propagate_prepend(errp, ...);@p2
>>> +     error_propagate_prepend(_errp, ...);@p2
>>>    |
>>> -     error_propagate(errp, ...);@p2
>>> +     error_propagate(_errp, ...);@p2
>>>    )
>>
>> You change some occurrences of errp to _errp, but not all. It breaks compilation.
>>
>>>         ... when any
>>>     }
>>> @@ -198,7 +201,7 @@ print('Warning: function {} propagates to errp several times in '
>>>    // the same, just without error_propagate() call), coccinelle fails to
>>>    // match this "out: }".
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn, rule1.local_err, out;
>>> +identifier fn, rule1.local_err, out;
>>
>> Hmm. If it improves performance it is strange.. But I can live with this change.
>>
>>>    symbol errp;
>>>    @@
>>>    @@ -239,7 +242,7 @@ symbol errp;
>>>    //        *errp = NULL;
>>>    //    }
>>>    @ disable optional_qualifier exists@
>>> -identifier rule1.fn, rule1.local_err;
>>> +identifier fn, rule1.local_err;
>>>    expression list args;
>>>    symbol errp;
>>>    @@
>>> @@ -287,7 +290,7 @@ symbol errp;
>>>    // previous hunk, as this conflicts with other substitutions in it (at
>>>    // least with "- local_err = NULL").
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn, rule1.local_err;
>>> +identifier fn, rule1.local_err;
>>>    symbol errp;
>>>    @@
>>>    @@ -301,7 +304,7 @@ symbol errp;
>>>      // Always use the same pattern for checking error
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn;
>>> +identifier fn;
>>>    symbol errp;
>>>    @@
>>>    @@ -315,7 +318,7 @@ symbol errp;
>>>      // Revert temporary ___ identifier.
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn;
>>> +identifier fn;
>>>    @@
>>>       fn(..., Error **
>>>
> 
> I append my hacked up version of auto-propagated-errp.cocci.  It
> produces the same patch as yours for the complete tree.
> 
> 
> 
> // Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
> //
> // Copyright (c) 2020 Virtuozzo International GmbH.
> //
> // This program is free software; you can redistribute it and/or
> // modify it under the terms of the GNU General Public License as
> // published by the Free Software Foundation; either version 2 of the
> // License, or (at your option) any later version.
> //
> // This program is distributed in the hope that it will be useful,
> // but WITHOUT ANY WARRANTY; without even the implied warranty of
> // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> // GNU General Public License for more details.
> //
> // You should have received a copy of the GNU General Public License
> // along with this program.  If not, see
> // <http://www.gnu.org/licenses/>.
> //
> // Usage example:
> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
> //  --macro-file scripts/cocci-macro-file.h --in-place \
> //  --no-show-diff --max-width 80 FILES...
> //
> // Note: --max-width 80 is needed because coccinelle default is less
> // than 80, and without this parameter coccinelle may reindent some
> // lines which fit into 80 characters but not to coccinelle default,
> // which in turn produces extra patch hunks for no reason.
> 
> // Switch unusual Error ** parameter names to errp
> // (this is necessary to use ERRP_AUTO_PROPAGATE).
> //
> // Disable optional_qualifier to skip functions with
> // "Error *const *errp" parameter.
> //
> // Skip functions with "assert(_errp && *_errp)" statement, because
> // that signals unusual semantics, and the parameter name may well
> // serve a purpose. (like nbd_iter_channel_error()).
> //
> // Skip util/error.c to not touch, for example, error_propagate() and
> // error_propagate_prepend().
> @ depends on !(file in "util/error.c") disable optional_qualifier@
> identifier fn;
> identifier _errp != errp;
> @@
> 
>   fn(...,
> -   Error **_errp
> +   Error **errp
>      ,...)
>   {
> (
>       ... when != assert(_errp && *_errp)
> &
>       <...
> -    _errp
> +    errp
>       ...>
> )
>   }
> 
> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
> // necessary
> //
> // Note, that without "when any" the final "..." does not mach
> // something matched by previous pattern, i.e. the rule will not match
> // double error_prepend in control flow like in
> // vfio_set_irq_signaling().
> //
> // Note, "exists" says that we want apply rule even if it matches not
> // on all possible control flows (otherwise, it will not match
> // standard pattern when error_propagate() call is in if branch).
> @ disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
> 
>   fn(..., Error **errp, ...)
>   {
> +   ERRP_AUTO_PROPAGATE();
>      ...  when != ERRP_AUTO_PROPAGATE();
> (
> (
>      error_append_hint(errp, ...);
> |
>      error_prepend(errp, ...);
> |
>      error_vprepend(errp, ...);
> )
>      ... when any
> |
>      Error *local_err = NULL;
>      ...
> (
>      error_propagate_prepend(errp, local_err, ...);
> |
>      error_propagate(errp, local_err);
> )
>      ...
> )
>   }
> 
> 
> // Match functions with propagation of local error to errp.
> // We want to refer these functions in several following rules, but I
> // don't know a proper way to inherit a function, not just its name
> // (to not match another functions with same name in following rules).
> // Not-proper way is as follows: rename errp parameter in functions
> // header and match it in following rules. Rename it back after all
> // transformations.
> //
> // The simplest case of propagation scheme is single definition of
> // local_err with at most one error_propagate_prepend or
> // error_propagate on each control-flow. Still, we want to match more
> // complex schemes too. We'll warn them with help of further rules.
> @rule1 disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
> 
>   fn(..., Error **
> -    errp
> +    ____
>      , ...)
>   {
>       ...
>       Error *local_err = NULL;
>       ...
> (
>       error_propagate_prepend(errp, local_err, ...);
> |
>       error_propagate(errp, local_err);
> )
>       ...
>   }
> 
> 
> // Warn several Error * definitions.
> @check1 disable optional_qualifier exists@
> identifier fn, _errp, local_err, local_err2;
> position p1, p2;
> @@
> 
>   fn(..., Error **_errp, ...)
>   {
>       ...
>       Error *local_err = NULL;@p1
>       ... when any
>       Error *local_err2 = NULL;@p2
>       ... when any
>   }
> 
> @ script:python @
> fn << check1.fn;
> p1 << check1.p1;
> p2 << check1.p2;
> @@
> 
> print('Warning: function {} has several definitions of '
>        'Error * local variable: at {}:{} and then at {}:{}'.format(
>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> 
> // Warn several propagations in control flow.
> @check2 disable optional_qualifier exists@
> identifier fn, _errp;
> position p1, p2;
> @@
> 
>   fn(..., Error **_errp, ...)
>   {
>       ...
> (
>       error_propagate_prepend(_errp, ...);@p1
> |
>       error_propagate(_errp, ...);@p1
> )
>       ...
> (
>       error_propagate_prepend(_errp, ...);@p2
> |
>       error_propagate(_errp, ...);@p2
> )
>       ... when any
>   }
> 
> @ script:python @
> fn << check2.fn;
> p1 << check2.p1;
> p2 << check2.p2;
> @@
> 
> print('Warning: function {} propagates to errp several times in '
>        'one control flow: at {}:{} and then at {}:{}'.format(
>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> 
> // Convert special case with goto separately.
> // I tried merging this into the following rule the obvious way, but
> // it made Coccinelle hang on block.c
> //
> // Note interesting thing: if we don't do it here, and try to fixup
> // "out: }" things later after all transformations (the rule will be
> // the same, just without error_propagate() call), coccinelle fails to
> // match this "out: }".
> @ disable optional_qualifier@
> identifier fn, rule1.local_err, out;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    goto out;
> +    return;
>       ...>
> - out:
> -    error_propagate(errp, local_err);
>   }
> 
> // Convert most of local_err related stuff.
> //
> // Note, that we update everything related to matched by rule1
> // function name and local_err name. We may match something not
> // related to the pattern matched by rule1. For example, local_err may
> // be defined with the same name in different blocks inside one
> // function, and in one block follow the propagation pattern and in
> // other block doesn't. Or we may have several functions with the same
> // name (for different configurations).
> //
> // Note also that errp-cleaning functions
> //   error_free_errp
> //   error_report_errp
> //   error_reportf_errp
> //   warn_report_errp
> //   warn_reportf_errp
> // are not yet implemented. They must call corresponding Error* -
> // freeing function and then set *errp to NULL, to avoid further
> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
> // For example, error_free_errp may look like this:
> //
> //    void error_free_errp(Error **errp)
> //    {
> //        error_free(*errp);
> //        *errp = NULL;
> //    }
> @ disable optional_qualifier exists@
> identifier fn, rule1.local_err;
> expression list args;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> (
> -    Error *local_err = NULL;
> |
> 
> // Convert error clearing functions
> (
> -    error_free(local_err);
> +    error_free_errp(errp);
> |
> -    error_report_err(local_err);
> +    error_report_errp(errp);
> |
> -    error_reportf_err(local_err, args);
> +    error_reportf_errp(errp, args);
> |
> -    warn_report_err(local_err);
> +    warn_report_errp(errp);
> |
> -    warn_reportf_err(local_err, args);// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
//
// Copyright (c) 2020 Virtuozzo International GmbH.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see
// <http://www.gnu.org/licenses/>.
//
// Usage example:
// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
//  --macro-file scripts/cocci-macro-file.h --in-place \
//  --no-show-diff --max-width 80 FILES...
//
// Note: --max-width 80 is needed because coccinelle default is less
// than 80, and without this parameter coccinelle may reindent some
// lines which fit into 80 characters but not to coccinelle default,
// which in turn produces extra patch hunks for no reason.

// Switch unusual Error ** parameter names to errp
// (this is necessary to use ERRP_AUTO_PROPAGATE).
//
// Disable optional_qualifier to skip functions with
// "Error *const *errp" parameter.
//
// Skip functions with "assert(_errp && *_errp)" statement, because
// that signals unusual semantics, and the parameter name may well
// serve a purpose. (like nbd_iter_channel_error()).
//
// Skip util/error.c to not touch, for example, error_propagate() and
// error_propagate_prepend().
@ depends on !(file in "util/error.c") disable optional_qualifier@
identifier fn;
identifier _errp != errp;
@@

  fn(...,
-   Error **_errp
+   Error **errp
     ,...)
  {
(
      ... when != assert(_errp && *_errp)
&
      <...
-    _errp
+    errp
      ...>
)
  }

// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
// necessary
//
// Note, that without "when any" the final "..." does not mach
// something matched by previous pattern, i.e. the rule will not match
// double error_prepend in control flow like in
// vfio_set_irq_signaling().
//
// Note, "exists" says that we want apply rule even if it matches not
// on all possible control flows (otherwise, it will not match
// standard pattern when error_propagate() call is in if branch).
@ disable optional_qualifier exists@
identifier fn, local_err;
symbol errp;
@@

  fn(..., Error **errp, ...)
  {
+   ERRP_AUTO_PROPAGATE();
     ...  when != ERRP_AUTO_PROPAGATE();
(
(
     error_append_hint(errp, ...);
|
     error_prepend(errp, ...);
|
     error_vprepend(errp, ...);
)
     ... when any
|
     Error *local_err = NULL;
     ...
(
     error_propagate_prepend(errp, local_err, ...);
|
     error_propagate(errp, local_err);
)
     ...
)
  }


// Match functions with propagation of local error to errp.
// We want to refer these functions in several following rules, but I
// don't know a proper way to inherit a function, not just its name
// (to not match another functions with same name in following rules).
// Not-proper way is as follows: rename errp parameter in functions
// header and match it in following rules. Rename it back after all
// transformations.
//
// The simplest case of propagation scheme is single definition of
// local_err with at most one error_propagate_prepend or
// error_propagate on each control-flow. Still, we want to match more
// complex schemes too. We'll warn them with help of further rules.
@rule1 disable optional_qualifier exists@
identifier fn, local_err;
symbol errp;
@@

  fn(..., Error **
-    errp
+    ____
     , ...)
  {
      ...
      Error *local_err = NULL;
      ...
(
      error_propagate_prepend(errp, local_err, ...);
|
      error_propagate(errp, local_err);
)
      ...
  }


// Warn several Error * definitions.
@check1 disable optional_qualifier exists@
identifier fn, _errp, local_err, local_err2;
position p1, p2;
@@

  fn(..., Error **_errp, ...)
  {
      ...
      Error *local_err = NULL;@p1
      ... when any
      Error *local_err2 = NULL;@p2
      ... when any
  }

@ script:python @
fn << check1.fn;
p1 << check1.p1;
p2 << check1.p2;
@@

print('Warning: function {} has several definitions of '
       'Error * local variable: at {}:{} and then at {}:{}'.format(
           fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))

// Warn several propagations in control flow.
@check2 disable optional_qualifier exists@
identifier fn, _errp;
position p1, p2;
@@

  fn(..., Error **_errp, ...)
  {
      ...
(
      error_propagate_prepend(_errp, ...);@p1
|
      error_propagate(_errp, ...);@p1
)
      ...
(
      error_propagate_prepend(_errp, ...);@p2
|
      error_propagate(_errp, ...);@p2
)
      ... when any
  }

@ script:python @
fn << check2.fn;
p1 << check2.p1;
p2 << check2.p2;
@@

print('Warning: function {} propagates to errp several times in '
       'one control flow: at {}:{} and then at {}:{}'.format(
           fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))

// Convert special case with goto separately.
// I tried merging this into the following rule the obvious way, but
// it made Coccinelle hang on block.c
//
// Note interesting thing: if we don't do it here, and try to fixup
// "out: }" things later after all transformations (the rule will be
// the same, just without error_propagate() call), coccinelle fails to
// match this "out: }".
@ disable optional_qualifier@
identifier fn, rule1.local_err, out;
symbol errp;
@@

  fn(..., Error ** ____, ...)
  {
      <...
-    goto out;
+    return;
      ...>
- out:
-    error_propagate(errp, local_err);
  }

// Convert most of local_err related stuff.
//
// Note, that we update everything related to matched by rule1
// function name and local_err name. We may match something not
// related to the pattern matched by rule1. For example, local_err may
// be defined with the same name in different blocks inside one
// function, and in one block follow the propagation pattern and in
// other block doesn't. Or we may have several functions with the same
// name (for different configurations).
//
// Note also that errp-cleaning functions
//   error_free_errp
//   error_report_errp
//   error_reportf_errp
//   warn_report_errp
//   warn_reportf_errp
// are not yet implemented. They must call corresponding Error* -
// freeing function and then set *errp to NULL, to avoid further
// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
// For example, error_free_errp may look like this:
//
//    void error_free_errp(Error **errp)
//    {
//        error_free(*errp);
//        *errp = NULL;
//    }
@ disable optional_qualifier exists@
identifier fn, rule1.local_err;
expression list args;
symbol errp;
@@

  fn(..., Error ** ____, ...)
  {
      <...
(
-    Error *local_err = NULL;
|

// Convert error clearing functions
(
-    error_free(local_err);
+    error_free_errp(errp);
|
-    error_report_err(local_err);
+    error_report_errp(errp);
|
-    error_reportf_err(local_err, args);
+    error_reportf_errp(errp, args);
|
-    warn_report_err(local_err);
+    warn_report_errp(errp);
|
-    warn_reportf_err(local_err, args);
+    warn_reportf_errp(errp, args);
)
?-    local_err = NULL;

|
-    error_propagate_prepend(errp, local_err, args);
+    error_prepend(errp, args);
|
-    error_propagate(errp, local_err);
|
-    &local_err
+    errp
)
      ...>
  }

// Convert remaining local_err usage. For example, different kinds of
// error checking in if conditionals. We can't merge this into
// previous hunk, as this conflicts with other substitutions in it (at
// least with "- local_err = NULL").
@ disable optional_qualifier@
identifier fn, rule1.local_err;
symbol errp;
@@

  fn(..., Error ** ____, ...)
  {
      <...
-    local_err
+    *errp
      ...>
  }

// Always use the same pattern for checking error
@ disable optional_qualifier@
identifier fn;
symbol errp;
@@

  fn(..., Error ** ____, ...)
  {
      <...
-    *errp != NULL
+    *errp
      ...>
  }

// Revert temporary ___ identifier.
@ disable optional_qualifier@
identifier fn;
@@

  fn(..., Error **
-   ____
+   errp
     , ...)
  {
      ...
  }

> +    warn_reportf_errp(errp, args);
> )
> ?-    local_err = NULL;
> 
> |
> -    error_propagate_prepend(errp, local_err, args);
> +    error_prepend(errp, args);
> |
> -    error_propagate(errp, local_err);
> |
> -    &local_err
> +    errp
> )
>       ...>
>   }
> 
> // Convert remaining local_err usage. For example, different kinds of
> // error checking in if conditionals. We can't merge this into
> // previous hunk, as this conflicts with other substitutions in it (at
> // least with "- local_err = NULL").
> @ disable optional_qualifier@
> identifier fn, rule1.local_err;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    local_err
> +    *errp
>       ...>
>   }
> 
> // Always use the same pattern for checking error
> @ disable optional_qualifier@
> identifier fn;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    *errp != NULL
> +    *errp
>       ...>
>   }
> 
> // Revert temporary ___ identifier.
> @ disable optional_qualifier@
> identifier fn;
> @@
> 
>   fn(..., Error **
> -   ____
> +   errp
>      , ...)
>   {
>       ...
>   }
> 

OK, I almost OK with it, the only thing I doubt a bit is the following:

We want to keep rule1.local_err inheritance to keep connection with
local_err definition.

Interesting, when we have both rule1.fn and rule1.local_err inherited,
do we inherit them in separate (i.e. all possible combinations of fn
and local_err symbols from rule1) or do we inherit a pair, i.e. only
fn/local_err pairs, found by rule1? If the latter is correct, that
with your script we loss this pair inheritance, and go to all possible
combinations of fn and local_err from rule1, possibly adding some wrong
conversion (OK, you've checked that no such cases in current code tree).

So, dropping inheritance in check-rules makes sence, as it may match 
(and warn) more interesting cases.

But for other rules, I'd prefere to be safer, and explictly inherit all
actually inherited identifiers.. Still, I feel, we'll never be 
absolutely safe with coccinelle :)

--
Best regrads,
Vladimir

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-16  7:12               ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-16  8:21                 ` Markus Armbruster
  -1 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-16  8:21 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> On 14.03.2020 00:54, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>
>>> 13.03.2020 18:42, Markus Armbruster wrote:
>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>
>>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>>> out now as is.
>>>>>>
>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>
>>>>>>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>>>>>>> does corresponding changes in code (look for details in
>>>>>>> include/qapi/error.h)
>>>>>>>
>>>>>>> Usage example:
>>>>>>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>>>     --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>>>>>>     --max-width 80 FILES...
>>>>>>>
>>>>>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>>>>>> ---
>>>>>>>
>>>>>>> Cc: Eric Blake <eblake@redhat.com>
>>>>>>> Cc: Kevin Wolf <kwolf@redhat.com>
>>>>>>> Cc: Max Reitz <mreitz@redhat.com>
>>>>>>> Cc: Greg Kurz <groug@kaod.org>
>>>>>>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>>>>>>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>>>>>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>>>>>> Cc: Paul Durrant <paul@xen.org>
>>>>>>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>>>>>>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>>>>>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>>>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>>>>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>>>>>>> Cc: Markus Armbruster <armbru@redhat.com>
>>>>>>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>>>>>>> Cc: qemu-devel@nongnu.org
>>>>>>> Cc: qemu-block@nongnu.org
>>>>>>> Cc: xen-devel@lists.xenproject.org
>>>>>>>
>>>>>>>     scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>>>>>>     include/qapi/error.h                          |   3 +
>>>>>>>     MAINTAINERS                                   |   1 +
>>>>>>>     3 files changed, 331 insertions(+)
>>>>>>>     create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>>
>>>>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>> new file mode 100644
>>>>>>> index 0000000000..7dac2dcfa4
>>>>>>> --- /dev/null
>>>>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>> @@ -0,0 +1,327 @@
>>>>>>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>>>>>> +//
>>>>>>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>>>>>>> +//
>>>>>>> +// This program is free software; you can redistribute it and/or
>>>>>>> +// modify it under the terms of the GNU General Public License as
>>>>>>> +// published by the Free Software Foundation; either version 2 of the
>>>>>>> +// License, or (at your option) any later version.
>>>>>>> +//
>>>>>>> +// This program is distributed in the hope that it will be useful,
>>>>>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>>>>> +// GNU General Public License for more details.
>>>>>>> +//
>>>>>>> +// You should have received a copy of the GNU General Public License
>>>>>>> +// along with this program.  If not, see
>>>>>>> +// <http://www.gnu.org/licenses/>.
>>>>>>> +//
>>>>>>> +// Usage example:
>>>>>>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>>>>>>> +//  --no-show-diff --max-width 80 FILES...
>>>>>>> +//
>>>>>>> +// Note: --max-width 80 is needed because coccinelle default is less
>>>>>>> +// than 80, and without this parameter coccinelle may reindent some
>>>>>>> +// lines which fit into 80 characters but not to coccinelle default,
>>>>>>> +// which in turn produces extra patch hunks for no reason.
>>>>>>
>>>>>> This is about unwanted reformatting of parameter lists due to the ___
>>>>>> chaining hack.  --max-width 80 makes that less likely, but not
>>>>>> impossible.
>>>>>>
>>>>>> We can search for unwanted reformatting of parameter lists.  I think
>>>>>> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
>>>>>> tree, I get one false positive (not a parameter list), and one hit:
>>>>>>
>>>>>>        @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>>>>>>             }
>>>>>>         }
>>>>>>
>>>>>>        -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>>>>>>        +void object_apply_global_props(Object *obj, const GPtrArray *props,
>>>>>>        +                               Error **errp)
>>>>>>         {
>>>>>>        +    ERRP_AUTO_PROPAGATE();
>>>>>>             int i;
>>>>>>
>>>>>>             if (!props) {
>>>>>>
>>>>>> Reformatting, but not unwanted.
>>>>>
>>>>> Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
>>>>> ERRP_AUTO_PROPAGATE addition even for non-automatic patch.
>>>>
>>>> Agree.
>>>>
>>>>>>
>>>>>> The --max-width 80 hack is good enough for me.
>>>>>>
>>>>>> It does result in slightly long transformed lines, e.g. this one in
>>>>>> replication.c:
>>>>>>
>>>>>>        @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>>>>>>                 s->mode = REPLICATION_MODE_PRIMARY;
>>>>>>                 top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>>>>>>                 if (top_id) {
>>>>>>        -            error_setg(&local_err, "The primary side does not support option top-id");
>>>>>>        +            error_setg(errp, "The primary side does not support option top-id");
>>>>>>                     goto fail;
>>>>>>                 }
>>>>>>             } else if (!strcmp(mode, "secondary")) {
>>>>>>
>>>>>> v8 did break this line (that's how I found it).  However, v9 still
>>>>>> shortens the line, just not below the target.  All your + lines look
>>>>>> quite unlikely to lengthen lines.  Let's not worry about this.
>>>>>>
>>>>>>> +// Switch unusual Error ** parameter names to errp
>>>>>>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>>>>>>> +//
>>>>>>> +// Disable optional_qualifier to skip functions with
>>>>>>> +// "Error *const *errp" parameter.
>>>>>>> +//
>>>>>>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>>>>>>> +// that signals unusual semantics, and the parameter name may well
>>>>>>> +// serve a purpose. (like nbd_iter_channel_error()).
>>>>>>> +//
>>>>>>> +// Skip util/error.c to not touch, for example, error_propagate() and
>>>>>>> +// error_propagate_prepend().
>>>>>>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>>>>>>> +identifier fn;
>>>>>>> +identifier _errp != errp;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(...,
>>>>>>> +-   Error **_errp
>>>>>>> ++   Error **errp
>>>>>>> +    ,...)
>>>>>>> + {
>>>>>>> +(
>>>>>>> +     ... when != assert(_errp && *_errp)
>>>>>>> +&
>>>>>>> +     <...
>>>>>>> +-    _errp
>>>>>>> ++    errp
>>>>>>> +     ...>
>>>>>>> +)
>>>>>>> + }
>>>>>>> +
>>>>>>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>>>>>> +// necessary
>>>>>>> +//
>>>>>>> +// Note, that without "when any" the final "..." does not mach
>>>>>>> +// something matched by previous pattern, i.e. the rule will not match
>>>>>>> +// double error_prepend in control flow like in
>>>>>>> +// vfio_set_irq_signaling().
>>>>>>> +//
>>>>>>> +// Note, "exists" says that we want apply rule even if it matches not
>>>>>>> +// on all possible control flows (otherwise, it will not match
>>>>>>> +// standard pattern when error_propagate() call is in if branch).
>>>>>>> +@ disable optional_qualifier exists@
>>>>>>> +identifier fn, local_err;
>>>>>>> +symbol errp;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error **errp, ...)
>>>>>>> + {
>>>>>>> ++   ERRP_AUTO_PROPAGATE();
>>>>>>> +    ...  when != ERRP_AUTO_PROPAGATE();
>>>>>>> +(
>>>>>>> +(
>>>>>>> +    error_append_hint(errp, ...);
>>>>>>> +|
>>>>>>> +    error_prepend(errp, ...);
>>>>>>> +|
>>>>>>> +    error_vprepend(errp, ...);
>>>>>>> +)
>>>>>>> +    ... when any
>>>>>>> +|
>>>>>>> +    Error *local_err = NULL;
>>>>>>> +    ...
>>>>>>> +(
>>>>>>> +    error_propagate_prepend(errp, local_err, ...);
>>>>>>> +|
>>>>>>> +    error_propagate(errp, local_err);
>>>>>>> +)
>>>>>>> +    ...
>>>>>>> +)
>>>>>>> + }
>>>>>>> +
>>>>>>> +
>>>>>>> +// Match functions with propagation of local error to errp.
>>>>>>> +// We want to refer these functions in several following rules, but I
>>>>>>> +// don't know a proper way to inherit a function, not just its name
>>>>>>> +// (to not match another functions with same name in following rules).
>>>>>>> +// Not-proper way is as follows: rename errp parameter in functions
>>>>>>> +// header and match it in following rules. Rename it back after all
>>>>>>> +// transformations.
>>>>>>> +//
>>>>>>> +// The simplest case of propagation scheme is single definition of
>>>>>>> +// local_err with at most one error_propagate_prepend or
>>>>>>> +// error_propagate on each control-flow. Still, we want to match more
>>>>>>> +// complex schemes too. We'll warn them with help of further rules.
>>>>>>
>>>>>> I think what we actually want is to examine instances of this pattern to
>>>>>> figure out whether and how we want to transform them.  Perhaps:
>>>>>>
>>>>>>        // The common case is a single definition of local_err with at most one
>>>>>>        // error_propagate_prepend() or error_propagate() on each control-flow
>>>>>>        // path. Instances of this case we convert with this script. Functions
>>>>>
>>>>> For me, sounds a bit like "other things we don't convert".
>>>>> Actually we convert other things too.
>>>>
>>>> What other patterns of error propagation do we convert?
>>>
>>> Something like in xen_block_device_destroy, why not? Otherwise, it's better to avoid
>>> matching things like xen_block_device_destroy, not just warn them.
>>> But I'd prefer to proceed now as is to fit into 5.0.. Too much time already
>>> spent on this. So, I'm OK with your wording too.
>>
>> Let's scratch "Instances of this case we convert with this script."
>
> OK
>
>>
>>>>>>        // with multiple definitions or propagates we want to examine
>>>>>>        // manually. Later rules emit warnings to guide us to them.
>>>>>>
>>>>>>> +@rule1 disable optional_qualifier exists@
>>>>>>> +identifier fn, local_err;
>>>>>>> +symbol errp;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error **
>>>>>>> +-    errp
>>>>>>> ++    ____
>>>>>>> +    , ...)
>>>>>>> + {
>>>>>>> +     ...
>>>>>>> +     Error *local_err = NULL;
>>>>>>> +     ...
>>>>>>> +(
>>>>>>> +     error_propagate_prepend(errp, local_err, ...);
>>>>>>> +|
>>>>>>> +     error_propagate(errp, local_err);
>>>>>>> +)
>>>>>>> +     ...
>>>>>>> + }
>>>>>>> +
>>>>>>> +
>>>>>>> +// Warn several Error * definitions.
>>>>>>> +@check1 disable optional_qualifier exists@
>>>>>>> +identifier fn = rule1.fn, local_err, local_err2;
>>>>>>
>>>>>> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
>>>>>> particular reason for the difference?
>>>>>
>>>>> I didn't find other way to ref check1.fn in next python rule. It just don't
>>>>> work if I write here just rule1.fn.
>>>>>
>>>>>>
>>>>>> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
>>>>>> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
>>>>>> everywhere, then apply the script to the complete tree, I get the same
>>>>>> result.
>>>>>
>>>>> I think, it's more efficient to reuse names from previous rules. I think it should
>>>>> work faster (more information, less extra matching).
>>>>
>>>> Nope.  With my hacked up script (patch appended) Coccinelle is actually
>>>> *faster* for the .[ch] touched by this series: with your unmodified
>>>> script, it takes a bit over 12s on my box, with mine around 7s.  Output
>>>> is identical.
>>>>
>>>> Never guess performance, always measure it :)
>>>
>>> Hmm, whole tree results would be better proof
>>>
>>>>
>>>> Two notes on my script:
>>>>
>>>> * Unlike yours, it recognizes double-propagation in my test case.
>>>>     Discussed below.
>>>>
>>>> * Its "several definitions of" warning includes positions.  That turned
>>>>     out to be useless, but I've been too lazy to take that out again.
>>>>
>>>>>>
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>> + {
>>>>>>> +     ...
>>>>>>> +     Error *local_err = NULL;
>>>>>>> +     ... when any
>>>>>>> +     Error *local_err2 = NULL;
>>>>>>> +     ... when any
>>>>>>> + }
>>
>> This flags functions that have more than one declaration along any
>> control flow path.  It doesn't flag this one:
>>
>>      void gnat(bool b, Error **errp)
>>      {
>>          if (b) {
>>              Error *local_err = NULL;
>>              foo(arg, &local_err);
>>              error_propagate(errp, local_err);
>>          } else {
>>              Error *local_err = NULL;
>>              bar(arg, &local_err);
>>              error_propagate(errp, local_err);
>>          }
>>      }
>>
>> The Coccinelle script does the right thing for this one regardless.
>>
>> I'd prefer to have such functions flagged, too.  But spending time on
>> convincing Coccinelle to do it for me is not worthwhile; I can simply
>> search the diff produced by Coccinelle for deletions of declarations
>> that are not indented exactly four spaces.
>>
>> But if we keep this rule, we should adjust its comment
>>
>>      // Warn several Error * definitions.
>>
>> because it sure suggests it also catches functions like the one I gave
>> above.
>
> Hmm, yes.. We can write "Warn several Error * definitions in _one_
> control flow (it's not so trivial to match _any_ case with several
> definitions with coccinelle)" or something like this.

Ha, "trivial" reminds me of a story.  The math professor, after having
spent a good chunk of his lecture developing a proof on the blackboad
turns to the audience to explain why this little part doesn't require
proof with the words familiar to any math student "and this is trivial."
Pause, puzzled look...  "Is it trivial?"  Pause, storms out of the
lecture hall.  A minute or three pass.  Professor comes back beaming,
"it is trivial!", and proceeds with the proof.

My point is: it might be trivial with Coccinelle once you know how to do
it.  We don't.

Suggest "(can't figure out how to match several definitions regardless
of control flow)".

>
>>
>>>>>>> +
>>>>>>> +@ script:python @
>>>>>>> +fn << check1.fn;
>>>>>>> +@@
>>>>>>> +
>>>>>>> +print('Warning: function {} has several definitions of '
>>>>>>> +      'Error * local variable'.format(fn))
>>>>>>> +
>>>>>>> +// Warn several propagations in control flow.
>>>>>>> +@check2 disable optional_qualifier exists@
>>>>>>> +identifier fn = rule1.fn;
>>>>>>> +symbol errp;
>>>>>>> +position p1, p2;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>> + {
>>>>>>> +     ...
>>>>>>> +(
>>>>>>> +     error_propagate_prepend(errp, ...);@p1
>>>>>>> +|
>>>>>>> +     error_propagate(errp, ...);@p1
>>>>>>> +)
>>>>>>> +     ...
>>>>>>> +(
>>>>>>> +     error_propagate_prepend(errp, ...);@p2
>>>>>>> +|
>>>>>>> +     error_propagate(errp, ...);@p2
>>>>>>> +)
>>>>>>> +     ... when any
>>>>>>> + }
>>>>>>> +
>>>>>>
>>>>>> Hmm, we don't catch the example I used in review of v8:
>>>>>>
>>>>>>        extern foo(int, Error **);
>>>>>>        extern bar(int, Error **);
>>>>>>
>>>>>>        void frob(Error **errp)
>>>>>>        {
>>>>>>            Error *local_err = NULL;
>>>>>>            int arg;
>>>>>>
>>>>>>            foo(arg, errp);
>>>>>>            bar(arg, &local_err);
>>>>>>            error_propagate(errp, local_err);
>>>>>>            bar(arg + 1, &local_err);
>>>>>>            error_propagate(errp, local_err);
>>>>>>        }
>>>>>>
>>>>>> I believe this is because rule1 does not match here.
>>>>>
>>>>> Yes, rule1 wants at least one code flow with non-doubled propagation.
>>>>>
>>>>>>
>>>>>> If I change the rule as follows, it catches the example:
>>>>>>
>>>>>>        @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
>>>>>>
>>>>>>         // Warn several propagations in control flow.
>>>>>>         @check2 disable optional_qualifier exists@
>>>>>>        -identifier fn = rule1.fn;
>>>>>>        -symbol errp;
>>>>>>        +identifier fn, _errp;
>>>>>>         position p1, p2;
>>>>>>         @@
>>>>>>
>>>>>>        - fn(..., Error ** ____, ...)
>>>>>>        + fn(..., Error **_errp, ...)
>>>>>>          {
>>>>>>              ...
>>>>>>         (
>>>>>>        -     error_propagate_prepend(errp, ...);@p1
>>>>>>        +     error_propagate_prepend(_errp, ...);@p1
>>>>>>         |
>>>>>>        -     error_propagate(errp, ...);@p1
>>>>>>        +     error_propagate(_errp, ...);@p1
>>>>>>         )
>>>>>>              ...
>>>>>>         (
>>>>>>        -     error_propagate_prepend(errp, ...);@p2
>>>>>>        +     error_propagate_prepend(_errp, ...);@p2
>>>>>>         |
>>>>>>        -     error_propagate(errp, ...);@p2
>>>>>>        +     error_propagate(_errp, ...);@p2
>>>>>>         )
>>>>>>              ... when any
>>>>>>          }
>>>>>>
>>>>>> To my mild surprise, it still doesn't find anything in our tree.
>>>>>>
>>>>>> Should we decouple the previous rule from rule1, too?  I tested the
>>>>>> following on the whole tree:
>>>>>
>>>>> I don't think so. Why to check what we are not going to convert? If we want
>>>>> to check side things, it's better to do it in other coccinelle script..
>>>>
>>>> Misunderstanding?  The rules are still chained together via the ___
>>>> hack, just not via function name, because that's unreliable and
>>>> redundant.
>>>
>>> Strange.. Then, how can it match something not matched by rule1?
>>
>> I think I got confused when I wrote the "Misunderstanding?" paragraph.
>>
>> Let me try again.
>>
>> First rule check2.
>>
>> The common case is a at most one propagation to @errp along any control
>> flow path.  We trust your Coccinelle script to convert that alright.
>>
>> Any other propagation to @errp I want to review.  Whether the script
>> attempts a conversion or not is unimportant, as long as it points me to
>> the function to review.
>>
>> Rule rule1 matches functions that propagate to @errp once along at least
>> one control flow path.
>>
>> Unchained from rule rule1, rule check2 flags any function that
>> propagates to @errp multiple times along any control flow path.
>>
>> Chained to rule1, it flags only functions that also have a path with
>> single propagation.
>>
>> In other words, the unchained rule flags *all* multi-propagations to
>> @errp, while the chained rule flags only the ones the script attempts to
>> convert.  The former is much more useful to me.
>>
>> Now rule check1.  It flags functions with multiple declarations along
>> any control flow path.  Again, chaining it to rule1 restricts it to the
>> functions we attempt to convert.  Makes it less useful to me.  However,
>> because my desire to review multiple declarations in function we don't
>> attempt to convert is lower than my desire to review multiple
>> propagations to @errp in such functions, chaining check1 is tolerable
>> for me.  But why chain check1 if we don't chain check2?
>>
>
> OK, let's unchain them.
>
>>>
>>>>
>>>>>>
>>>>>>        @@ -136,10 +136,10 @@ symbol errp;
>>>>>>
>>>>>>         // Warn several Error * definitions.
>>>>>>         @check1 disable optional_qualifier exists@
>>>>>>        -identifier fn = rule1.fn, local_err, local_err2;
>>>>>>        +identifier fn, _errp, local_err, local_err2;
>>>>>>         @@
>>>>>>
>>>>>>        - fn(..., Error ** ____, ...)
>>>>>>        + fn(..., Error **_errp, ...)
>>>>>>          {
>>>>>>              ...
>>>>>>              Error *local_err = NULL;
>>>>>>
>>>>>> Warnings remain unchanged.
>>>>>>
>>>>>>> +@ script:python @
>>>>>>> +fn << check2.fn;
>>>>>>> +p1 << check2.p1;
>>>>>>> +p2 << check2.p2;
>>>>>>> +@@
>>>>>>> +
>>>>>>> +print('Warning: function {} propagates to errp several times in '
>>>>>>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>>>>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>>>>> +
>>>>>>> +// Convert special case with goto separately.
>>>>>>> +// I tried merging this into the following rule the obvious way, but
>>>>>>> +// it made Coccinelle hang on block.c
>>>>>>> +//
>>>>>>> +// Note interesting thing: if we don't do it here, and try to fixup
>>>>>>> +// "out: }" things later after all transformations (the rule will be
>>>>>>> +// the same, just without error_propagate() call), coccinelle fails to
>>>>>>> +// match this "out: }".
>>>>>>> +@ disable optional_qualifier@
>>>>>>> +identifier rule1.fn, rule1.local_err, out;
>>>>>>
>>>>>> As explained above, I doubt the need for rule1.fn.  We do need
>>>>>> rule1.local_err to avoid unwanted transformations.  More of the same
>>>>>> below.
>>>>>
>>>>> Logically, I want to inherit from rule1. So why not to stress it by inheriting
>>>>> fn variable? It's just a correct thing to do.
>>>>> And I hope it helps coccinelle to work more efficiently.
>>>>>
>>>>>>
>>>>>>> +symbol errp;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>> + {
>>>>>>> +     <...
>>>>>>> +-    goto out;
>>>>>>> ++    return;
>>>>>>> +     ...>
>>>>>>> +- out:
>>>>>>> +-    error_propagate(errp, local_err);
>>>>>>> + }
>>>>>>> +
>>>>>>> +// Convert most of local_err related stuff.
>>>>>>> +//
>>>>>>> +// Note, that we update everything related to matched by rule1
>>>>>>> +// function name and local_err name. We may match something not
>>>>>>> +// related to the pattern matched by rule1. For example, local_err may
>>>>>>> +// be defined with the same name in different blocks inside one
>>>>>>> +// function, and in one block follow the propagation pattern and in
>>>>>>> +// other block doesn't. Or we may have several functions with the same
>>>>>>> +// name (for different configurations).
>>>>>>> +//
>>>>>>> +// Note also that errp-cleaning functions
>>>>>>> +//   error_free_errp
>>>>>>> +//   error_report_errp
>>>>>>> +//   error_reportf_errp
>>>>>>> +//   warn_report_errp
>>>>>>> +//   warn_reportf_errp
>>>>>>> +// are not yet implemented. They must call corresponding Error* -
>>>>>>> +// freeing function and then set *errp to NULL, to avoid further
>>>>>>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>>>>>> +// For example, error_free_errp may look like this:
>>>>>>> +//
>>>>>>> +//    void error_free_errp(Error **errp)
>>>>>>> +//    {
>>>>>>> +//        error_free(*errp);
>>>>>>> +//        *errp = NULL;
>>>>>>> +//    }
>>>>>>> +@ disable optional_qualifier exists@
>>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>>> +expression list args;
>>>>>>> +symbol errp;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>> + {
>>>>>>> +     <...
>>>>>>> +(
>>>>>>> +-    Error *local_err = NULL;
>>>>>>> +|
>>>>>>> +
>>>>>>> +// Convert error clearing functions
>>>>>>> +(
>>>>>>> +-    error_free(local_err);
>>>>>>> ++    error_free_errp(errp);
>>>>>>> +|
>>>>>>> +-    error_report_err(local_err);
>>>>>>> ++    error_report_errp(errp);
>>>>>>> +|
>>>>>>> +-    error_reportf_err(local_err, args);
>>>>>>> ++    error_reportf_errp(errp, args);
>>>>>>> +|
>>>>>>> +-    warn_report_err(local_err);
>>>>>>> ++    warn_report_errp(errp);
>>>>>>> +|
>>>>>>> +-    warn_reportf_err(local_err, args);
>>>>>>> ++    warn_reportf_errp(errp, args);
>>>>>>> +)
>>>>>>> +?-    local_err = NULL;
>>>>>>> +
>>>>>>> +|
>>>>>>> +-    error_propagate_prepend(errp, local_err, args);
>>>>>>> ++    error_prepend(errp, args);
>>>>>>> +|
>>>>>>> +-    error_propagate(errp, local_err);
>>>>>>> +|
>>>>>>> +-    &local_err
>>>>>>> ++    errp
>>>>>>> +)
>>>>>>> +     ...>
>>>>>>> + }
>>>>>>> +
>>>>>>> +// Convert remaining local_err usage. For example, different kinds of
>>>>>>> +// error checking in if conditionals. We can't merge this into
>>>>>>> +// previous hunk, as this conflicts with other substitutions in it (at
>>>>>>> +// least with "- local_err = NULL").
>>>>>>> +@ disable optional_qualifier@
>>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>>> +symbol errp;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>> + {
>>>>>>> +     <...
>>>>>>> +-    local_err
>>>>>>> ++    *errp
>>>>>>> +     ...>
>>>>>>> + }
>>>>>>> +
>>>>>>> +// Always use the same pattern for checking error
>>>>>>> +@ disable optional_qualifier@
>>>>>>> +identifier rule1.fn;
>>>>>>> +symbol errp;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>> + {
>>>>>>> +     <...
>>>>>>> +-    *errp != NULL
>>>>>>> ++    *errp
>>>>>>> +     ...>
>>>>>>> + }
>>>>>>> +
>>>>>>> +// Revert temporary ___ identifier.
>>>>>>> +@ disable optional_qualifier@
>>>>>>> +identifier rule1.fn;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error **
>>>>>>> +-   ____
>>>>>>> ++   errp
>>>>>>> +    , ...)
>>>>>>> + {
>>>>>>> +     ...
>>>>>>> + }
>>>>>>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>>>>>>> index 30140d9bfe..56c133520d 100644
>>>>>>> --- a/include/qapi/error.h
>>>>>>> +++ b/include/qapi/error.h
>>>>>>> @@ -214,6 +214,9 @@
>>>>>>>      *         }
>>>>>>>      *         ...
>>>>>>>      *     }
>>>>>>> + *
>>>>>>> + * For mass-conversion use script
>>>>>>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>>      */
>>>>>>>       #ifndef ERROR_H
>>>>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>>>>> index 857f969aa1..047f1b9714 100644
>>>>>>> --- a/MAINTAINERS
>>>>>>> +++ b/MAINTAINERS
>>>>>>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>>>>>>     F: qapi/error.json
>>>>>>>     F: util/error.c
>>>>>>>     F: util/qemu-error.c
>>>>>>> +F: scripts/coccinelle/*err*.cocci
>>>>>>>       GDB stub
>>>>>>>     M: Alex Bennée <alex.bennee@linaro.org>
>>>>>>
>>>>
>>>>
>>>>   From 42a08c529024337d1b859839c9ce7f797f784555 Mon Sep 17 00:00:00 2001
>>>> From: Markus Armbruster <armbru@redhat.com>
>>>> Date: Fri, 13 Mar 2020 14:27:57 +0100
>>>> Subject: [PATCH] fixup! scripts: Coccinelle script to use
>>>>    ERRP_AUTO_PROPAGATE()
>>>>
>>>> ---
>>>>    scripts/coccinelle/auto-propagated-errp.cocci | 37 ++++++++++---------
>>>>    1 file changed, 20 insertions(+), 17 deletions(-)
>>>>
>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>> index 7dac2dcfa4..43b0b0e63b 100644
>>>> --- a/scripts/coccinelle/auto-propagated-errp.cocci
>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>> @@ -136,45 +136,48 @@ symbol errp;
>>>>      // Warn several Error * definitions.
>>>>    @check1 disable optional_qualifier exists@
>>>> -identifier fn = rule1.fn, local_err, local_err2;
>>>> +identifier fn, _errp, local_err, local_err2;
>>>> +position p1, p2;
>>>
>>>
>>> Hmm, seems like I forget to define ____ as symbol in my patch
>>
>> Coccinelle defaults to symbol.
>
> But for errp we saw warnings simetimes.

I believe it warns when you use rely on the symbol default while also
using it as something else in other rules.

Feel free to explicitly define it as symbol.

>>>>    @@
>>>>    - fn(..., Error ** ____, ...)
>>>> + fn(..., Error **_errp, ...)
>>>
>>> Ahmm.. it will break compilation?
>>>
>>> Or, how will it work when _errp defined as meta variable is only in "+..." line? Should it be symbol instead, or just not defined?
>>
>> Misunderstanding?  It's a diff between your .cocci and mine. 
>
> Oops, yes, sorry. Patches to coccinelle scripts are tricky thing.
>
>> My version
>> is
>>
>>      // Warn several Error * definitions.
>>      @check1 disable optional_qualifier exists@
>>      identifier fn, _errp, local_err, local_err2;
>>      position p1, p2;
>>      @@
>>
>>       fn(..., Error **_errp, ...)
>>       {
>>           ...
>>           Error *local_err = NULL;@p1
>>           ... when any
>>           Error *local_err2 = NULL;@p2
>>           ... when any
>>       }
>>
>>      @ script:python @
>>      fn << check1.fn;
>>      p1 << check1.p1;
>>      p2 << check1.p2;
>>      @@
>>
>>>>     {
>>>>         ...
>>>> -     Error *local_err = NULL;
>>>> +     Error *local_err = NULL;@p1
>>>
>>> Why to do -/+ here? Nothing changed..
>>>
>>>>         ... when any
>>>> -     Error *local_err2 = NULL;
>>>> +     Error *local_err2 = NULL;@p2
>>>>         ... when any
>>>>     }
>>>>      @ script:python @
>>>>    fn << check1.fn;
>>>> +p1 << check1.p1;
>>>> +p2 << check1.p2;
>>>>    @@
>>>>      print('Warning: function {} has several definitions of '
>>>> -      'Error * local variable'.format(fn))
>>>> +      'Error * local variable: at {}:{} and then at {}:{}'.format(
>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>>      // Warn several propagations in control flow.
>>>>    @check2 disable optional_qualifier exists@
>>>> -identifier fn = rule1.fn;
>>>> -symbol errp;
>>>> +identifier fn, _errp;
>>>>    position p1, p2;
>>>>    @@
>>>>    - fn(..., Error ** ____, ...)
>>>> + fn(..., Error **_errp, ...)
>>>>     {
>>>>         ...
>>>>    (
>>>> -     error_propagate_prepend(errp, ...);@p1
>>>> +     error_propagate_prepend(_errp, ...);@p1
>>>>    |
>>>> -     error_propagate(errp, ...);@p1
>>>> +     error_propagate(_errp, ...);@p1
>>>>    )
>>>>         ...
>>>>    (
>>>> -     error_propagate_prepend(errp, ...);@p2
>>>> +     error_propagate_prepend(_errp, ...);@p2
>>>>    |
>>>> -     error_propagate(errp, ...);@p2
>>>> +     error_propagate(_errp, ...);@p2
>>>>    )
>>>
>>> You change some occurrences of errp to _errp, but not all. It breaks compilation.
>>>
>>>>         ... when any
>>>>     }
>>>> @@ -198,7 +201,7 @@ print('Warning: function {} propagates to errp several times in '
>>>>    // the same, just without error_propagate() call), coccinelle fails to
>>>>    // match this "out: }".
>>>>    @ disable optional_qualifier@
>>>> -identifier rule1.fn, rule1.local_err, out;
>>>> +identifier fn, rule1.local_err, out;
>>>
>>> Hmm. If it improves performance it is strange.. But I can live with this change.
>>>
>>>>    symbol errp;
>>>>    @@
>>>>    @@ -239,7 +242,7 @@ symbol errp;
>>>>    //        *errp = NULL;
>>>>    //    }
>>>>    @ disable optional_qualifier exists@
>>>> -identifier rule1.fn, rule1.local_err;
>>>> +identifier fn, rule1.local_err;
>>>>    expression list args;
>>>>    symbol errp;
>>>>    @@
>>>> @@ -287,7 +290,7 @@ symbol errp;
>>>>    // previous hunk, as this conflicts with other substitutions in it (at
>>>>    // least with "- local_err = NULL").
>>>>    @ disable optional_qualifier@
>>>> -identifier rule1.fn, rule1.local_err;
>>>> +identifier fn, rule1.local_err;
>>>>    symbol errp;
>>>>    @@
>>>>    @@ -301,7 +304,7 @@ symbol errp;
>>>>      // Always use the same pattern for checking error
>>>>    @ disable optional_qualifier@
>>>> -identifier rule1.fn;
>>>> +identifier fn;
>>>>    symbol errp;
>>>>    @@
>>>>    @@ -315,7 +318,7 @@ symbol errp;
>>>>      // Revert temporary ___ identifier.
>>>>    @ disable optional_qualifier@
>>>> -identifier rule1.fn;
>>>> +identifier fn;
>>>>    @@
>>>>       fn(..., Error **
>>>>
>>
>> I append my hacked up version of auto-propagated-errp.cocci.  It
>> produces the same patch as yours for the complete tree.
>>
>>
>>
>> // Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>> //
>> // Copyright (c) 2020 Virtuozzo International GmbH.
>> //
>> // This program is free software; you can redistribute it and/or
>> // modify it under the terms of the GNU General Public License as
>> // published by the Free Software Foundation; either version 2 of the
>> // License, or (at your option) any later version.
>> //
>> // This program is distributed in the hope that it will be useful,
>> // but WITHOUT ANY WARRANTY; without even the implied warranty of
>> // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> // GNU General Public License for more details.
>> //
>> // You should have received a copy of the GNU General Public License
>> // along with this program.  If not, see
>> // <http://www.gnu.org/licenses/>.
>> //
>> // Usage example:
>> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>> //  --macro-file scripts/cocci-macro-file.h --in-place \
>> //  --no-show-diff --max-width 80 FILES...
>> //
>> // Note: --max-width 80 is needed because coccinelle default is less
>> // than 80, and without this parameter coccinelle may reindent some
>> // lines which fit into 80 characters but not to coccinelle default,
>> // which in turn produces extra patch hunks for no reason.
>>
>> // Switch unusual Error ** parameter names to errp
>> // (this is necessary to use ERRP_AUTO_PROPAGATE).
>> //
>> // Disable optional_qualifier to skip functions with
>> // "Error *const *errp" parameter.
>> //
>> // Skip functions with "assert(_errp && *_errp)" statement, because
>> // that signals unusual semantics, and the parameter name may well
>> // serve a purpose. (like nbd_iter_channel_error()).
>> //
>> // Skip util/error.c to not touch, for example, error_propagate() and
>> // error_propagate_prepend().
>> @ depends on !(file in "util/error.c") disable optional_qualifier@
>> identifier fn;
>> identifier _errp != errp;
>> @@
>>
>>   fn(...,
>> -   Error **_errp
>> +   Error **errp
>>      ,...)
>>   {
>> (
>>       ... when != assert(_errp && *_errp)
>> &
>>       <...
>> -    _errp
>> +    errp
>>       ...>
>> )
>>   }
>>
>> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>> // necessary
>> //
>> // Note, that without "when any" the final "..." does not mach
>> // something matched by previous pattern, i.e. the rule will not match
>> // double error_prepend in control flow like in
>> // vfio_set_irq_signaling().
>> //
>> // Note, "exists" says that we want apply rule even if it matches not
>> // on all possible control flows (otherwise, it will not match
>> // standard pattern when error_propagate() call is in if branch).
>> @ disable optional_qualifier exists@
>> identifier fn, local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error **errp, ...)
>>   {
>> +   ERRP_AUTO_PROPAGATE();
>>      ...  when != ERRP_AUTO_PROPAGATE();
>> (
>> (
>>      error_append_hint(errp, ...);
>> |
>>      error_prepend(errp, ...);
>> |
>>      error_vprepend(errp, ...);
>> )
>>      ... when any
>> |
>>      Error *local_err = NULL;
>>      ...
>> (
>>      error_propagate_prepend(errp, local_err, ...);
>> |
>>      error_propagate(errp, local_err);
>> )
>>      ...
>> )
>>   }
>>
>>
>> // Match functions with propagation of local error to errp.
>> // We want to refer these functions in several following rules, but I
>> // don't know a proper way to inherit a function, not just its name
>> // (to not match another functions with same name in following rules).
>> // Not-proper way is as follows: rename errp parameter in functions
>> // header and match it in following rules. Rename it back after all
>> // transformations.
>> //
>> // The simplest case of propagation scheme is single definition of
>> // local_err with at most one error_propagate_prepend or
>> // error_propagate on each control-flow. Still, we want to match more
>> // complex schemes too. We'll warn them with help of further rules.
>> @rule1 disable optional_qualifier exists@
>> identifier fn, local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error **
>> -    errp
>> +    ____
>>      , ...)
>>   {
>>       ...
>>       Error *local_err = NULL;
>>       ...
>> (
>>       error_propagate_prepend(errp, local_err, ...);
>> |
>>       error_propagate(errp, local_err);
>> )
>>       ...
>>   }
>>
>>
>> // Warn several Error * definitions.
>> @check1 disable optional_qualifier exists@
>> identifier fn, _errp, local_err, local_err2;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>>   {
>>       ...
>>       Error *local_err = NULL;@p1
>>       ... when any
>>       Error *local_err2 = NULL;@p2
>>       ... when any
>>   }
>>
>> @ script:python @
>> fn << check1.fn;
>> p1 << check1.p1;
>> p2 << check1.p2;
>> @@
>>
>> print('Warning: function {} has several definitions of '
>>        'Error * local variable: at {}:{} and then at {}:{}'.format(
>>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>
>> // Warn several propagations in control flow.
>> @check2 disable optional_qualifier exists@
>> identifier fn, _errp;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>>   {
>>       ...
>> (
>>       error_propagate_prepend(_errp, ...);@p1
>> |
>>       error_propagate(_errp, ...);@p1
>> )
>>       ...
>> (
>>       error_propagate_prepend(_errp, ...);@p2
>> |
>>       error_propagate(_errp, ...);@p2
>> )
>>       ... when any
>>   }
>>
>> @ script:python @
>> fn << check2.fn;
>> p1 << check2.p1;
>> p2 << check2.p2;
>> @@
>>
>> print('Warning: function {} propagates to errp several times in '
>>        'one control flow: at {}:{} and then at {}:{}'.format(
>>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>
>> // Convert special case with goto separately.
>> // I tried merging this into the following rule the obvious way, but
>> // it made Coccinelle hang on block.c
>> //
>> // Note interesting thing: if we don't do it here, and try to fixup
>> // "out: }" things later after all transformations (the rule will be
>> // the same, just without error_propagate() call), coccinelle fails to
>> // match this "out: }".
>> @ disable optional_qualifier@
>> identifier fn, rule1.local_err, out;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    goto out;
>> +    return;
>>       ...>
>> - out:
>> -    error_propagate(errp, local_err);
>>   }
>>
>> // Convert most of local_err related stuff.
>> //
>> // Note, that we update everything related to matched by rule1
>> // function name and local_err name. We may match something not
>> // related to the pattern matched by rule1. For example, local_err may
>> // be defined with the same name in different blocks inside one
>> // function, and in one block follow the propagation pattern and in
>> // other block doesn't. Or we may have several functions with the same
>> // name (for different configurations).
>> //
>> // Note also that errp-cleaning functions
>> //   error_free_errp
>> //   error_report_errp
>> //   error_reportf_errp
>> //   warn_report_errp
>> //   warn_reportf_errp
>> // are not yet implemented. They must call corresponding Error* -
>> // freeing function and then set *errp to NULL, to avoid further
>> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>> // For example, error_free_errp may look like this:
>> //
>> //    void error_free_errp(Error **errp)
>> //    {
>> //        error_free(*errp);
>> //        *errp = NULL;
>> //    }
>> @ disable optional_qualifier exists@
>> identifier fn, rule1.local_err;
>> expression list args;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> (
>> -    Error *local_err = NULL;
>> |
>>
>> // Convert error clearing functions
>> (
>> -    error_free(local_err);
>> +    error_free_errp(errp);
>> |
>> -    error_report_err(local_err);
>> +    error_report_errp(errp);
>> |
>> -    error_reportf_err(local_err, args);
>> +    error_reportf_errp(errp, args);
>> |
>> -    warn_report_err(local_err);
>> +    warn_report_errp(errp);
>> |
>> -    warn_reportf_err(local_err, args);// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
> //
> // Copyright (c) 2020 Virtuozzo International GmbH.
> //
> // This program is free software; you can redistribute it and/or
> // modify it under the terms of the GNU General Public License as
> // published by the Free Software Foundation; either version 2 of the
> // License, or (at your option) any later version.
> //
> // This program is distributed in the hope that it will be useful,
> // but WITHOUT ANY WARRANTY; without even the implied warranty of
> // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> // GNU General Public License for more details.
> //
> // You should have received a copy of the GNU General Public License
> // along with this program.  If not, see
> // <http://www.gnu.org/licenses/>.
> //
> // Usage example:
> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
> //  --macro-file scripts/cocci-macro-file.h --in-place \
> //  --no-show-diff --max-width 80 FILES...
> //
> // Note: --max-width 80 is needed because coccinelle default is less
> // than 80, and without this parameter coccinelle may reindent some
> // lines which fit into 80 characters but not to coccinelle default,
> // which in turn produces extra patch hunks for no reason.
>
> // Switch unusual Error ** parameter names to errp
> // (this is necessary to use ERRP_AUTO_PROPAGATE).
> //
> // Disable optional_qualifier to skip functions with
> // "Error *const *errp" parameter.
> //
> // Skip functions with "assert(_errp && *_errp)" statement, because
> // that signals unusual semantics, and the parameter name may well
> // serve a purpose. (like nbd_iter_channel_error()).
> //
> // Skip util/error.c to not touch, for example, error_propagate() and
> // error_propagate_prepend().
> @ depends on !(file in "util/error.c") disable optional_qualifier@
> identifier fn;
> identifier _errp != errp;
> @@
>
>  fn(...,
> -   Error **_errp
> +   Error **errp
>     ,...)
>  {
> (
>      ... when != assert(_errp && *_errp)
> &
>      <...
> -    _errp
> +    errp
>      ...>
> )
>  }
>
> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
> // necessary
> //
> // Note, that without "when any" the final "..." does not mach
> // something matched by previous pattern, i.e. the rule will not match
> // double error_prepend in control flow like in
> // vfio_set_irq_signaling().
> //
> // Note, "exists" says that we want apply rule even if it matches not
> // on all possible control flows (otherwise, it will not match
> // standard pattern when error_propagate() call is in if branch).
> @ disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
>
>  fn(..., Error **errp, ...)
>  {
> +   ERRP_AUTO_PROPAGATE();
>     ...  when != ERRP_AUTO_PROPAGATE();
> (
> (
>     error_append_hint(errp, ...);
> |
>     error_prepend(errp, ...);
> |
>     error_vprepend(errp, ...);
> )
>     ... when any
> |
>     Error *local_err = NULL;
>     ...
> (
>     error_propagate_prepend(errp, local_err, ...);
> |
>     error_propagate(errp, local_err);
> )
>     ...
> )
>  }
>
>
> // Match functions with propagation of local error to errp.
> // We want to refer these functions in several following rules, but I
> // don't know a proper way to inherit a function, not just its name
> // (to not match another functions with same name in following rules).
> // Not-proper way is as follows: rename errp parameter in functions
> // header and match it in following rules. Rename it back after all
> // transformations.
> //
> // The simplest case of propagation scheme is single definition of
> // local_err with at most one error_propagate_prepend or
> // error_propagate on each control-flow. Still, we want to match more
> // complex schemes too. We'll warn them with help of further rules.
> @rule1 disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
>
>  fn(..., Error **
> -    errp
> +    ____
>     , ...)
>  {
>      ...
>      Error *local_err = NULL;
>      ...
> (
>      error_propagate_prepend(errp, local_err, ...);
> |
>      error_propagate(errp, local_err);
> )
>      ...
>  }
>
>
> // Warn several Error * definitions.
> @check1 disable optional_qualifier exists@
> identifier fn, _errp, local_err, local_err2;
> position p1, p2;
> @@
>
>  fn(..., Error **_errp, ...)
>  {
>      ...
>      Error *local_err = NULL;@p1
>      ... when any
>      Error *local_err2 = NULL;@p2
>      ... when any
>  }
>
> @ script:python @
> fn << check1.fn;
> p1 << check1.p1;
> p2 << check1.p2;
> @@
>
> print('Warning: function {} has several definitions of '
>       'Error * local variable: at {}:{} and then at {}:{}'.format(
>           fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>
> // Warn several propagations in control flow.
> @check2 disable optional_qualifier exists@
> identifier fn, _errp;
> position p1, p2;
> @@
>
>  fn(..., Error **_errp, ...)
>  {
>      ...
> (
>      error_propagate_prepend(_errp, ...);@p1
> |
>      error_propagate(_errp, ...);@p1
> )
>      ...
> (
>      error_propagate_prepend(_errp, ...);@p2
> |
>      error_propagate(_errp, ...);@p2
> )
>      ... when any
>  }
>
> @ script:python @
> fn << check2.fn;
> p1 << check2.p1;
> p2 << check2.p2;
> @@
>
> print('Warning: function {} propagates to errp several times in '
>       'one control flow: at {}:{} and then at {}:{}'.format(
>           fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>
> // Convert special case with goto separately.
> // I tried merging this into the following rule the obvious way, but
> // it made Coccinelle hang on block.c
> //
> // Note interesting thing: if we don't do it here, and try to fixup
> // "out: }" things later after all transformations (the rule will be
> // the same, just without error_propagate() call), coccinelle fails to
> // match this "out: }".
> @ disable optional_qualifier@
> identifier fn, rule1.local_err, out;
> symbol errp;
> @@
>
>  fn(..., Error ** ____, ...)
>  {
>      <...
> -    goto out;
> +    return;
>      ...>
> - out:
> -    error_propagate(errp, local_err);
>  }
>
> // Convert most of local_err related stuff.
> //
> // Note, that we update everything related to matched by rule1
> // function name and local_err name. We may match something not
> // related to the pattern matched by rule1. For example, local_err may
> // be defined with the same name in different blocks inside one
> // function, and in one block follow the propagation pattern and in
> // other block doesn't. Or we may have several functions with the same
> // name (for different configurations).
> //
> // Note also that errp-cleaning functions
> //   error_free_errp
> //   error_report_errp
> //   error_reportf_errp
> //   warn_report_errp
> //   warn_reportf_errp
> // are not yet implemented. They must call corresponding Error* -
> // freeing function and then set *errp to NULL, to avoid further
> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
> // For example, error_free_errp may look like this:
> //
> //    void error_free_errp(Error **errp)
> //    {
> //        error_free(*errp);
> //        *errp = NULL;
> //    }
> @ disable optional_qualifier exists@
> identifier fn, rule1.local_err;
> expression list args;
> symbol errp;
> @@
>
>  fn(..., Error ** ____, ...)
>  {
>      <...
> (
> -    Error *local_err = NULL;
> |
>
> // Convert error clearing functions
> (
> -    error_free(local_err);
> +    error_free_errp(errp);
> |
> -    error_report_err(local_err);
> +    error_report_errp(errp);
> |
> -    error_reportf_err(local_err, args);
> +    error_reportf_errp(errp, args);
> |
> -    warn_report_err(local_err);
> +    warn_report_errp(errp);
> |
> -    warn_reportf_err(local_err, args);
> +    warn_reportf_errp(errp, args);
> )
> ?-    local_err = NULL;
>
> |
> -    error_propagate_prepend(errp, local_err, args);
> +    error_prepend(errp, args);
> |
> -    error_propagate(errp, local_err);
> |
> -    &local_err
> +    errp
> )
>      ...>
>  }
>
> // Convert remaining local_err usage. For example, different kinds of
> // error checking in if conditionals. We can't merge this into
> // previous hunk, as this conflicts with other substitutions in it (at
> // least with "- local_err = NULL").
> @ disable optional_qualifier@
> identifier fn, rule1.local_err;
> symbol errp;
> @@
>
>  fn(..., Error ** ____, ...)
>  {
>      <...
> -    local_err
> +    *errp
>      ...>
>  }
>
> // Always use the same pattern for checking error
> @ disable optional_qualifier@
> identifier fn;
> symbol errp;
> @@
>
>  fn(..., Error ** ____, ...)
>  {
>      <...
> -    *errp != NULL
> +    *errp
>      ...>
>  }
>
> // Revert temporary ___ identifier.
> @ disable optional_qualifier@
> identifier fn;
> @@
>
>  fn(..., Error **
> -   ____
> +   errp
>     , ...)
>  {
>      ...
>  }
>
>> +    warn_reportf_errp(errp, args);
>> )
>> ?-    local_err = NULL;
>>
>> |
>> -    error_propagate_prepend(errp, local_err, args);
>> +    error_prepend(errp, args);
>> |
>> -    error_propagate(errp, local_err);
>> |
>> -    &local_err
>> +    errp
>> )
>>       ...>
>>   }
>>
>> // Convert remaining local_err usage. For example, different kinds of
>> // error checking in if conditionals. We can't merge this into
>> // previous hunk, as this conflicts with other substitutions in it (at
>> // least with "- local_err = NULL").
>> @ disable optional_qualifier@
>> identifier fn, rule1.local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    local_err
>> +    *errp
>>       ...>
>>   }
>>
>> // Always use the same pattern for checking error
>> @ disable optional_qualifier@
>> identifier fn;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    *errp != NULL
>> +    *errp
>>       ...>
>>   }
>>
>> // Revert temporary ___ identifier.
>> @ disable optional_qualifier@
>> identifier fn;
>> @@
>>
>>   fn(..., Error **
>> -   ____
>> +   errp
>>      , ...)
>>   {
>>       ...
>>   }
>>
>
> OK, I almost OK with it, the only thing I doubt a bit is the following:
>
> We want to keep rule1.local_err inheritance to keep connection with
> local_err definition.

Yes.

> Interesting, when we have both rule1.fn and rule1.local_err inherited,
> do we inherit them in separate (i.e. all possible combinations of fn
> and local_err symbols from rule1) or do we inherit a pair, i.e. only
> fn/local_err pairs, found by rule1? If the latter is correct, that
> with your script we loss this pair inheritance, and go to all possible
> combinations of fn and local_err from rule1, possibly adding some wrong
> conversion (OK, you've checked that no such cases in current code tree).

The chaining "identifier rule1.FOO" is by name.  It's reliable only as
long as there is exactly one instance of the name.

We already discussed the case of the function name: if there are two
instances of foo(), and rule1 matches only one of them, then we
nevertheless apply the rules chained to rule1 to both.  Because that can
be wrong, you came up with the ___ trick, which chains reliably.

The same issue exists with the variable name: if there are two instances
of @local_err, and rule1 matches only one of them, then we nevertheless
apply the rules chained to rule1 to both.  Can also be wrong.

What are the conditions for "wrong"?

Because the ___ chaining is reliable, we know rule1 matched the
function, i.e. it has a parameter Error **errp, and it has a automatic
variable Error *local_err = NULL.

We're good as long as *all* identifiers @local_err in this function are
declared that way.  This seems quite likely.  It's not certain, though.

Since nested declarations of Error ** variables are rare, we can rely on
review to ensure we transform these functions correctly.

> So, dropping inheritance in check-rules makes sence, as it may match
> (and warn) more interesting cases.
>
> But for other rules, I'd prefere to be safer, and explictly inherit all
> actually inherited identifiers..

I still can't see what chaining by function name in addition to the ___
chaining buys us.

>                                  Still, I feel, we'll never be
> absolutely safe with coccinelle :)

Right, although this particular problem is not really Coccinelle's
fault.  Blindly treating all instances of a certain identifier in a
certain area the same regardless of how they are bound to declarations
is fundamentally unreliable, regardless of your actual tooling.



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-16  8:21                 ` Markus Armbruster
  0 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-16  8:21 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> On 14.03.2020 00:54, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>
>>> 13.03.2020 18:42, Markus Armbruster wrote:
>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>
>>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>>> out now as is.
>>>>>>
>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>
>>>>>>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>>>>>>> does corresponding changes in code (look for details in
>>>>>>> include/qapi/error.h)
>>>>>>>
>>>>>>> Usage example:
>>>>>>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>>>     --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>>>>>>     --max-width 80 FILES...
>>>>>>>
>>>>>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>>>>>> ---
>>>>>>>
>>>>>>> Cc: Eric Blake <eblake@redhat.com>
>>>>>>> Cc: Kevin Wolf <kwolf@redhat.com>
>>>>>>> Cc: Max Reitz <mreitz@redhat.com>
>>>>>>> Cc: Greg Kurz <groug@kaod.org>
>>>>>>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>>>>>>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>>>>>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>>>>>> Cc: Paul Durrant <paul@xen.org>
>>>>>>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>>>>>>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>>>>>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>>>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>>>>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>>>>>>> Cc: Markus Armbruster <armbru@redhat.com>
>>>>>>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>>>>>>> Cc: qemu-devel@nongnu.org
>>>>>>> Cc: qemu-block@nongnu.org
>>>>>>> Cc: xen-devel@lists.xenproject.org
>>>>>>>
>>>>>>>     scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>>>>>>     include/qapi/error.h                          |   3 +
>>>>>>>     MAINTAINERS                                   |   1 +
>>>>>>>     3 files changed, 331 insertions(+)
>>>>>>>     create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>>
>>>>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>> new file mode 100644
>>>>>>> index 0000000000..7dac2dcfa4
>>>>>>> --- /dev/null
>>>>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>> @@ -0,0 +1,327 @@
>>>>>>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>>>>>> +//
>>>>>>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>>>>>>> +//
>>>>>>> +// This program is free software; you can redistribute it and/or
>>>>>>> +// modify it under the terms of the GNU General Public License as
>>>>>>> +// published by the Free Software Foundation; either version 2 of the
>>>>>>> +// License, or (at your option) any later version.
>>>>>>> +//
>>>>>>> +// This program is distributed in the hope that it will be useful,
>>>>>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>>>>> +// GNU General Public License for more details.
>>>>>>> +//
>>>>>>> +// You should have received a copy of the GNU General Public License
>>>>>>> +// along with this program.  If not, see
>>>>>>> +// <http://www.gnu.org/licenses/>.
>>>>>>> +//
>>>>>>> +// Usage example:
>>>>>>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>>>>>>> +//  --no-show-diff --max-width 80 FILES...
>>>>>>> +//
>>>>>>> +// Note: --max-width 80 is needed because coccinelle default is less
>>>>>>> +// than 80, and without this parameter coccinelle may reindent some
>>>>>>> +// lines which fit into 80 characters but not to coccinelle default,
>>>>>>> +// which in turn produces extra patch hunks for no reason.
>>>>>>
>>>>>> This is about unwanted reformatting of parameter lists due to the ___
>>>>>> chaining hack.  --max-width 80 makes that less likely, but not
>>>>>> impossible.
>>>>>>
>>>>>> We can search for unwanted reformatting of parameter lists.  I think
>>>>>> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
>>>>>> tree, I get one false positive (not a parameter list), and one hit:
>>>>>>
>>>>>>        @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>>>>>>             }
>>>>>>         }
>>>>>>
>>>>>>        -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>>>>>>        +void object_apply_global_props(Object *obj, const GPtrArray *props,
>>>>>>        +                               Error **errp)
>>>>>>         {
>>>>>>        +    ERRP_AUTO_PROPAGATE();
>>>>>>             int i;
>>>>>>
>>>>>>             if (!props) {
>>>>>>
>>>>>> Reformatting, but not unwanted.
>>>>>
>>>>> Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
>>>>> ERRP_AUTO_PROPAGATE addition even for non-automatic patch.
>>>>
>>>> Agree.
>>>>
>>>>>>
>>>>>> The --max-width 80 hack is good enough for me.
>>>>>>
>>>>>> It does result in slightly long transformed lines, e.g. this one in
>>>>>> replication.c:
>>>>>>
>>>>>>        @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>>>>>>                 s->mode = REPLICATION_MODE_PRIMARY;
>>>>>>                 top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>>>>>>                 if (top_id) {
>>>>>>        -            error_setg(&local_err, "The primary side does not support option top-id");
>>>>>>        +            error_setg(errp, "The primary side does not support option top-id");
>>>>>>                     goto fail;
>>>>>>                 }
>>>>>>             } else if (!strcmp(mode, "secondary")) {
>>>>>>
>>>>>> v8 did break this line (that's how I found it).  However, v9 still
>>>>>> shortens the line, just not below the target.  All your + lines look
>>>>>> quite unlikely to lengthen lines.  Let's not worry about this.
>>>>>>
>>>>>>> +// Switch unusual Error ** parameter names to errp
>>>>>>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>>>>>>> +//
>>>>>>> +// Disable optional_qualifier to skip functions with
>>>>>>> +// "Error *const *errp" parameter.
>>>>>>> +//
>>>>>>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>>>>>>> +// that signals unusual semantics, and the parameter name may well
>>>>>>> +// serve a purpose. (like nbd_iter_channel_error()).
>>>>>>> +//
>>>>>>> +// Skip util/error.c to not touch, for example, error_propagate() and
>>>>>>> +// error_propagate_prepend().
>>>>>>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>>>>>>> +identifier fn;
>>>>>>> +identifier _errp != errp;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(...,
>>>>>>> +-   Error **_errp
>>>>>>> ++   Error **errp
>>>>>>> +    ,...)
>>>>>>> + {
>>>>>>> +(
>>>>>>> +     ... when != assert(_errp && *_errp)
>>>>>>> +&
>>>>>>> +     <...
>>>>>>> +-    _errp
>>>>>>> ++    errp
>>>>>>> +     ...>
>>>>>>> +)
>>>>>>> + }
>>>>>>> +
>>>>>>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>>>>>> +// necessary
>>>>>>> +//
>>>>>>> +// Note, that without "when any" the final "..." does not mach
>>>>>>> +// something matched by previous pattern, i.e. the rule will not match
>>>>>>> +// double error_prepend in control flow like in
>>>>>>> +// vfio_set_irq_signaling().
>>>>>>> +//
>>>>>>> +// Note, "exists" says that we want apply rule even if it matches not
>>>>>>> +// on all possible control flows (otherwise, it will not match
>>>>>>> +// standard pattern when error_propagate() call is in if branch).
>>>>>>> +@ disable optional_qualifier exists@
>>>>>>> +identifier fn, local_err;
>>>>>>> +symbol errp;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error **errp, ...)
>>>>>>> + {
>>>>>>> ++   ERRP_AUTO_PROPAGATE();
>>>>>>> +    ...  when != ERRP_AUTO_PROPAGATE();
>>>>>>> +(
>>>>>>> +(
>>>>>>> +    error_append_hint(errp, ...);
>>>>>>> +|
>>>>>>> +    error_prepend(errp, ...);
>>>>>>> +|
>>>>>>> +    error_vprepend(errp, ...);
>>>>>>> +)
>>>>>>> +    ... when any
>>>>>>> +|
>>>>>>> +    Error *local_err = NULL;
>>>>>>> +    ...
>>>>>>> +(
>>>>>>> +    error_propagate_prepend(errp, local_err, ...);
>>>>>>> +|
>>>>>>> +    error_propagate(errp, local_err);
>>>>>>> +)
>>>>>>> +    ...
>>>>>>> +)
>>>>>>> + }
>>>>>>> +
>>>>>>> +
>>>>>>> +// Match functions with propagation of local error to errp.
>>>>>>> +// We want to refer these functions in several following rules, but I
>>>>>>> +// don't know a proper way to inherit a function, not just its name
>>>>>>> +// (to not match another functions with same name in following rules).
>>>>>>> +// Not-proper way is as follows: rename errp parameter in functions
>>>>>>> +// header and match it in following rules. Rename it back after all
>>>>>>> +// transformations.
>>>>>>> +//
>>>>>>> +// The simplest case of propagation scheme is single definition of
>>>>>>> +// local_err with at most one error_propagate_prepend or
>>>>>>> +// error_propagate on each control-flow. Still, we want to match more
>>>>>>> +// complex schemes too. We'll warn them with help of further rules.
>>>>>>
>>>>>> I think what we actually want is to examine instances of this pattern to
>>>>>> figure out whether and how we want to transform them.  Perhaps:
>>>>>>
>>>>>>        // The common case is a single definition of local_err with at most one
>>>>>>        // error_propagate_prepend() or error_propagate() on each control-flow
>>>>>>        // path. Instances of this case we convert with this script. Functions
>>>>>
>>>>> For me, sounds a bit like "other things we don't convert".
>>>>> Actually we convert other things too.
>>>>
>>>> What other patterns of error propagation do we convert?
>>>
>>> Something like in xen_block_device_destroy, why not? Otherwise, it's better to avoid
>>> matching things like xen_block_device_destroy, not just warn them.
>>> But I'd prefer to proceed now as is to fit into 5.0.. Too much time already
>>> spent on this. So, I'm OK with your wording too.
>>
>> Let's scratch "Instances of this case we convert with this script."
>
> OK
>
>>
>>>>>>        // with multiple definitions or propagates we want to examine
>>>>>>        // manually. Later rules emit warnings to guide us to them.
>>>>>>
>>>>>>> +@rule1 disable optional_qualifier exists@
>>>>>>> +identifier fn, local_err;
>>>>>>> +symbol errp;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error **
>>>>>>> +-    errp
>>>>>>> ++    ____
>>>>>>> +    , ...)
>>>>>>> + {
>>>>>>> +     ...
>>>>>>> +     Error *local_err = NULL;
>>>>>>> +     ...
>>>>>>> +(
>>>>>>> +     error_propagate_prepend(errp, local_err, ...);
>>>>>>> +|
>>>>>>> +     error_propagate(errp, local_err);
>>>>>>> +)
>>>>>>> +     ...
>>>>>>> + }
>>>>>>> +
>>>>>>> +
>>>>>>> +// Warn several Error * definitions.
>>>>>>> +@check1 disable optional_qualifier exists@
>>>>>>> +identifier fn = rule1.fn, local_err, local_err2;
>>>>>>
>>>>>> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
>>>>>> particular reason for the difference?
>>>>>
>>>>> I didn't find other way to ref check1.fn in next python rule. It just don't
>>>>> work if I write here just rule1.fn.
>>>>>
>>>>>>
>>>>>> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
>>>>>> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
>>>>>> everywhere, then apply the script to the complete tree, I get the same
>>>>>> result.
>>>>>
>>>>> I think, it's more efficient to reuse names from previous rules. I think it should
>>>>> work faster (more information, less extra matching).
>>>>
>>>> Nope.  With my hacked up script (patch appended) Coccinelle is actually
>>>> *faster* for the .[ch] touched by this series: with your unmodified
>>>> script, it takes a bit over 12s on my box, with mine around 7s.  Output
>>>> is identical.
>>>>
>>>> Never guess performance, always measure it :)
>>>
>>> Hmm, whole tree results would be better proof
>>>
>>>>
>>>> Two notes on my script:
>>>>
>>>> * Unlike yours, it recognizes double-propagation in my test case.
>>>>     Discussed below.
>>>>
>>>> * Its "several definitions of" warning includes positions.  That turned
>>>>     out to be useless, but I've been too lazy to take that out again.
>>>>
>>>>>>
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>> + {
>>>>>>> +     ...
>>>>>>> +     Error *local_err = NULL;
>>>>>>> +     ... when any
>>>>>>> +     Error *local_err2 = NULL;
>>>>>>> +     ... when any
>>>>>>> + }
>>
>> This flags functions that have more than one declaration along any
>> control flow path.  It doesn't flag this one:
>>
>>      void gnat(bool b, Error **errp)
>>      {
>>          if (b) {
>>              Error *local_err = NULL;
>>              foo(arg, &local_err);
>>              error_propagate(errp, local_err);
>>          } else {
>>              Error *local_err = NULL;
>>              bar(arg, &local_err);
>>              error_propagate(errp, local_err);
>>          }
>>      }
>>
>> The Coccinelle script does the right thing for this one regardless.
>>
>> I'd prefer to have such functions flagged, too.  But spending time on
>> convincing Coccinelle to do it for me is not worthwhile; I can simply
>> search the diff produced by Coccinelle for deletions of declarations
>> that are not indented exactly four spaces.
>>
>> But if we keep this rule, we should adjust its comment
>>
>>      // Warn several Error * definitions.
>>
>> because it sure suggests it also catches functions like the one I gave
>> above.
>
> Hmm, yes.. We can write "Warn several Error * definitions in _one_
> control flow (it's not so trivial to match _any_ case with several
> definitions with coccinelle)" or something like this.

Ha, "trivial" reminds me of a story.  The math professor, after having
spent a good chunk of his lecture developing a proof on the blackboad
turns to the audience to explain why this little part doesn't require
proof with the words familiar to any math student "and this is trivial."
Pause, puzzled look...  "Is it trivial?"  Pause, storms out of the
lecture hall.  A minute or three pass.  Professor comes back beaming,
"it is trivial!", and proceeds with the proof.

My point is: it might be trivial with Coccinelle once you know how to do
it.  We don't.

Suggest "(can't figure out how to match several definitions regardless
of control flow)".

>
>>
>>>>>>> +
>>>>>>> +@ script:python @
>>>>>>> +fn << check1.fn;
>>>>>>> +@@
>>>>>>> +
>>>>>>> +print('Warning: function {} has several definitions of '
>>>>>>> +      'Error * local variable'.format(fn))
>>>>>>> +
>>>>>>> +// Warn several propagations in control flow.
>>>>>>> +@check2 disable optional_qualifier exists@
>>>>>>> +identifier fn = rule1.fn;
>>>>>>> +symbol errp;
>>>>>>> +position p1, p2;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>> + {
>>>>>>> +     ...
>>>>>>> +(
>>>>>>> +     error_propagate_prepend(errp, ...);@p1
>>>>>>> +|
>>>>>>> +     error_propagate(errp, ...);@p1
>>>>>>> +)
>>>>>>> +     ...
>>>>>>> +(
>>>>>>> +     error_propagate_prepend(errp, ...);@p2
>>>>>>> +|
>>>>>>> +     error_propagate(errp, ...);@p2
>>>>>>> +)
>>>>>>> +     ... when any
>>>>>>> + }
>>>>>>> +
>>>>>>
>>>>>> Hmm, we don't catch the example I used in review of v8:
>>>>>>
>>>>>>        extern foo(int, Error **);
>>>>>>        extern bar(int, Error **);
>>>>>>
>>>>>>        void frob(Error **errp)
>>>>>>        {
>>>>>>            Error *local_err = NULL;
>>>>>>            int arg;
>>>>>>
>>>>>>            foo(arg, errp);
>>>>>>            bar(arg, &local_err);
>>>>>>            error_propagate(errp, local_err);
>>>>>>            bar(arg + 1, &local_err);
>>>>>>            error_propagate(errp, local_err);
>>>>>>        }
>>>>>>
>>>>>> I believe this is because rule1 does not match here.
>>>>>
>>>>> Yes, rule1 wants at least one code flow with non-doubled propagation.
>>>>>
>>>>>>
>>>>>> If I change the rule as follows, it catches the example:
>>>>>>
>>>>>>        @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
>>>>>>
>>>>>>         // Warn several propagations in control flow.
>>>>>>         @check2 disable optional_qualifier exists@
>>>>>>        -identifier fn = rule1.fn;
>>>>>>        -symbol errp;
>>>>>>        +identifier fn, _errp;
>>>>>>         position p1, p2;
>>>>>>         @@
>>>>>>
>>>>>>        - fn(..., Error ** ____, ...)
>>>>>>        + fn(..., Error **_errp, ...)
>>>>>>          {
>>>>>>              ...
>>>>>>         (
>>>>>>        -     error_propagate_prepend(errp, ...);@p1
>>>>>>        +     error_propagate_prepend(_errp, ...);@p1
>>>>>>         |
>>>>>>        -     error_propagate(errp, ...);@p1
>>>>>>        +     error_propagate(_errp, ...);@p1
>>>>>>         )
>>>>>>              ...
>>>>>>         (
>>>>>>        -     error_propagate_prepend(errp, ...);@p2
>>>>>>        +     error_propagate_prepend(_errp, ...);@p2
>>>>>>         |
>>>>>>        -     error_propagate(errp, ...);@p2
>>>>>>        +     error_propagate(_errp, ...);@p2
>>>>>>         )
>>>>>>              ... when any
>>>>>>          }
>>>>>>
>>>>>> To my mild surprise, it still doesn't find anything in our tree.
>>>>>>
>>>>>> Should we decouple the previous rule from rule1, too?  I tested the
>>>>>> following on the whole tree:
>>>>>
>>>>> I don't think so. Why to check what we are not going to convert? If we want
>>>>> to check side things, it's better to do it in other coccinelle script..
>>>>
>>>> Misunderstanding?  The rules are still chained together via the ___
>>>> hack, just not via function name, because that's unreliable and
>>>> redundant.
>>>
>>> Strange.. Then, how can it match something not matched by rule1?
>>
>> I think I got confused when I wrote the "Misunderstanding?" paragraph.
>>
>> Let me try again.
>>
>> First rule check2.
>>
>> The common case is a at most one propagation to @errp along any control
>> flow path.  We trust your Coccinelle script to convert that alright.
>>
>> Any other propagation to @errp I want to review.  Whether the script
>> attempts a conversion or not is unimportant, as long as it points me to
>> the function to review.
>>
>> Rule rule1 matches functions that propagate to @errp once along at least
>> one control flow path.
>>
>> Unchained from rule rule1, rule check2 flags any function that
>> propagates to @errp multiple times along any control flow path.
>>
>> Chained to rule1, it flags only functions that also have a path with
>> single propagation.
>>
>> In other words, the unchained rule flags *all* multi-propagations to
>> @errp, while the chained rule flags only the ones the script attempts to
>> convert.  The former is much more useful to me.
>>
>> Now rule check1.  It flags functions with multiple declarations along
>> any control flow path.  Again, chaining it to rule1 restricts it to the
>> functions we attempt to convert.  Makes it less useful to me.  However,
>> because my desire to review multiple declarations in function we don't
>> attempt to convert is lower than my desire to review multiple
>> propagations to @errp in such functions, chaining check1 is tolerable
>> for me.  But why chain check1 if we don't chain check2?
>>
>
> OK, let's unchain them.
>
>>>
>>>>
>>>>>>
>>>>>>        @@ -136,10 +136,10 @@ symbol errp;
>>>>>>
>>>>>>         // Warn several Error * definitions.
>>>>>>         @check1 disable optional_qualifier exists@
>>>>>>        -identifier fn = rule1.fn, local_err, local_err2;
>>>>>>        +identifier fn, _errp, local_err, local_err2;
>>>>>>         @@
>>>>>>
>>>>>>        - fn(..., Error ** ____, ...)
>>>>>>        + fn(..., Error **_errp, ...)
>>>>>>          {
>>>>>>              ...
>>>>>>              Error *local_err = NULL;
>>>>>>
>>>>>> Warnings remain unchanged.
>>>>>>
>>>>>>> +@ script:python @
>>>>>>> +fn << check2.fn;
>>>>>>> +p1 << check2.p1;
>>>>>>> +p2 << check2.p2;
>>>>>>> +@@
>>>>>>> +
>>>>>>> +print('Warning: function {} propagates to errp several times in '
>>>>>>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>>>>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>>>>> +
>>>>>>> +// Convert special case with goto separately.
>>>>>>> +// I tried merging this into the following rule the obvious way, but
>>>>>>> +// it made Coccinelle hang on block.c
>>>>>>> +//
>>>>>>> +// Note interesting thing: if we don't do it here, and try to fixup
>>>>>>> +// "out: }" things later after all transformations (the rule will be
>>>>>>> +// the same, just without error_propagate() call), coccinelle fails to
>>>>>>> +// match this "out: }".
>>>>>>> +@ disable optional_qualifier@
>>>>>>> +identifier rule1.fn, rule1.local_err, out;
>>>>>>
>>>>>> As explained above, I doubt the need for rule1.fn.  We do need
>>>>>> rule1.local_err to avoid unwanted transformations.  More of the same
>>>>>> below.
>>>>>
>>>>> Logically, I want to inherit from rule1. So why not to stress it by inheriting
>>>>> fn variable? It's just a correct thing to do.
>>>>> And I hope it helps coccinelle to work more efficiently.
>>>>>
>>>>>>
>>>>>>> +symbol errp;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>> + {
>>>>>>> +     <...
>>>>>>> +-    goto out;
>>>>>>> ++    return;
>>>>>>> +     ...>
>>>>>>> +- out:
>>>>>>> +-    error_propagate(errp, local_err);
>>>>>>> + }
>>>>>>> +
>>>>>>> +// Convert most of local_err related stuff.
>>>>>>> +//
>>>>>>> +// Note, that we update everything related to matched by rule1
>>>>>>> +// function name and local_err name. We may match something not
>>>>>>> +// related to the pattern matched by rule1. For example, local_err may
>>>>>>> +// be defined with the same name in different blocks inside one
>>>>>>> +// function, and in one block follow the propagation pattern and in
>>>>>>> +// other block doesn't. Or we may have several functions with the same
>>>>>>> +// name (for different configurations).
>>>>>>> +//
>>>>>>> +// Note also that errp-cleaning functions
>>>>>>> +//   error_free_errp
>>>>>>> +//   error_report_errp
>>>>>>> +//   error_reportf_errp
>>>>>>> +//   warn_report_errp
>>>>>>> +//   warn_reportf_errp
>>>>>>> +// are not yet implemented. They must call corresponding Error* -
>>>>>>> +// freeing function and then set *errp to NULL, to avoid further
>>>>>>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>>>>>> +// For example, error_free_errp may look like this:
>>>>>>> +//
>>>>>>> +//    void error_free_errp(Error **errp)
>>>>>>> +//    {
>>>>>>> +//        error_free(*errp);
>>>>>>> +//        *errp = NULL;
>>>>>>> +//    }
>>>>>>> +@ disable optional_qualifier exists@
>>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>>> +expression list args;
>>>>>>> +symbol errp;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>> + {
>>>>>>> +     <...
>>>>>>> +(
>>>>>>> +-    Error *local_err = NULL;
>>>>>>> +|
>>>>>>> +
>>>>>>> +// Convert error clearing functions
>>>>>>> +(
>>>>>>> +-    error_free(local_err);
>>>>>>> ++    error_free_errp(errp);
>>>>>>> +|
>>>>>>> +-    error_report_err(local_err);
>>>>>>> ++    error_report_errp(errp);
>>>>>>> +|
>>>>>>> +-    error_reportf_err(local_err, args);
>>>>>>> ++    error_reportf_errp(errp, args);
>>>>>>> +|
>>>>>>> +-    warn_report_err(local_err);
>>>>>>> ++    warn_report_errp(errp);
>>>>>>> +|
>>>>>>> +-    warn_reportf_err(local_err, args);
>>>>>>> ++    warn_reportf_errp(errp, args);
>>>>>>> +)
>>>>>>> +?-    local_err = NULL;
>>>>>>> +
>>>>>>> +|
>>>>>>> +-    error_propagate_prepend(errp, local_err, args);
>>>>>>> ++    error_prepend(errp, args);
>>>>>>> +|
>>>>>>> +-    error_propagate(errp, local_err);
>>>>>>> +|
>>>>>>> +-    &local_err
>>>>>>> ++    errp
>>>>>>> +)
>>>>>>> +     ...>
>>>>>>> + }
>>>>>>> +
>>>>>>> +// Convert remaining local_err usage. For example, different kinds of
>>>>>>> +// error checking in if conditionals. We can't merge this into
>>>>>>> +// previous hunk, as this conflicts with other substitutions in it (at
>>>>>>> +// least with "- local_err = NULL").
>>>>>>> +@ disable optional_qualifier@
>>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>>> +symbol errp;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>> + {
>>>>>>> +     <...
>>>>>>> +-    local_err
>>>>>>> ++    *errp
>>>>>>> +     ...>
>>>>>>> + }
>>>>>>> +
>>>>>>> +// Always use the same pattern for checking error
>>>>>>> +@ disable optional_qualifier@
>>>>>>> +identifier rule1.fn;
>>>>>>> +symbol errp;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>> + {
>>>>>>> +     <...
>>>>>>> +-    *errp != NULL
>>>>>>> ++    *errp
>>>>>>> +     ...>
>>>>>>> + }
>>>>>>> +
>>>>>>> +// Revert temporary ___ identifier.
>>>>>>> +@ disable optional_qualifier@
>>>>>>> +identifier rule1.fn;
>>>>>>> +@@
>>>>>>> +
>>>>>>> + fn(..., Error **
>>>>>>> +-   ____
>>>>>>> ++   errp
>>>>>>> +    , ...)
>>>>>>> + {
>>>>>>> +     ...
>>>>>>> + }
>>>>>>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>>>>>>> index 30140d9bfe..56c133520d 100644
>>>>>>> --- a/include/qapi/error.h
>>>>>>> +++ b/include/qapi/error.h
>>>>>>> @@ -214,6 +214,9 @@
>>>>>>>      *         }
>>>>>>>      *         ...
>>>>>>>      *     }
>>>>>>> + *
>>>>>>> + * For mass-conversion use script
>>>>>>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>>      */
>>>>>>>       #ifndef ERROR_H
>>>>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>>>>> index 857f969aa1..047f1b9714 100644
>>>>>>> --- a/MAINTAINERS
>>>>>>> +++ b/MAINTAINERS
>>>>>>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>>>>>>     F: qapi/error.json
>>>>>>>     F: util/error.c
>>>>>>>     F: util/qemu-error.c
>>>>>>> +F: scripts/coccinelle/*err*.cocci
>>>>>>>       GDB stub
>>>>>>>     M: Alex Bennée <alex.bennee@linaro.org>
>>>>>>
>>>>
>>>>
>>>>   From 42a08c529024337d1b859839c9ce7f797f784555 Mon Sep 17 00:00:00 2001
>>>> From: Markus Armbruster <armbru@redhat.com>
>>>> Date: Fri, 13 Mar 2020 14:27:57 +0100
>>>> Subject: [PATCH] fixup! scripts: Coccinelle script to use
>>>>    ERRP_AUTO_PROPAGATE()
>>>>
>>>> ---
>>>>    scripts/coccinelle/auto-propagated-errp.cocci | 37 ++++++++++---------
>>>>    1 file changed, 20 insertions(+), 17 deletions(-)
>>>>
>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>> index 7dac2dcfa4..43b0b0e63b 100644
>>>> --- a/scripts/coccinelle/auto-propagated-errp.cocci
>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>> @@ -136,45 +136,48 @@ symbol errp;
>>>>      // Warn several Error * definitions.
>>>>    @check1 disable optional_qualifier exists@
>>>> -identifier fn = rule1.fn, local_err, local_err2;
>>>> +identifier fn, _errp, local_err, local_err2;
>>>> +position p1, p2;
>>>
>>>
>>> Hmm, seems like I forget to define ____ as symbol in my patch
>>
>> Coccinelle defaults to symbol.
>
> But for errp we saw warnings simetimes.

I believe it warns when you use rely on the symbol default while also
using it as something else in other rules.

Feel free to explicitly define it as symbol.

>>>>    @@
>>>>    - fn(..., Error ** ____, ...)
>>>> + fn(..., Error **_errp, ...)
>>>
>>> Ahmm.. it will break compilation?
>>>
>>> Or, how will it work when _errp defined as meta variable is only in "+..." line? Should it be symbol instead, or just not defined?
>>
>> Misunderstanding?  It's a diff between your .cocci and mine. 
>
> Oops, yes, sorry. Patches to coccinelle scripts are tricky thing.
>
>> My version
>> is
>>
>>      // Warn several Error * definitions.
>>      @check1 disable optional_qualifier exists@
>>      identifier fn, _errp, local_err, local_err2;
>>      position p1, p2;
>>      @@
>>
>>       fn(..., Error **_errp, ...)
>>       {
>>           ...
>>           Error *local_err = NULL;@p1
>>           ... when any
>>           Error *local_err2 = NULL;@p2
>>           ... when any
>>       }
>>
>>      @ script:python @
>>      fn << check1.fn;
>>      p1 << check1.p1;
>>      p2 << check1.p2;
>>      @@
>>
>>>>     {
>>>>         ...
>>>> -     Error *local_err = NULL;
>>>> +     Error *local_err = NULL;@p1
>>>
>>> Why to do -/+ here? Nothing changed..
>>>
>>>>         ... when any
>>>> -     Error *local_err2 = NULL;
>>>> +     Error *local_err2 = NULL;@p2
>>>>         ... when any
>>>>     }
>>>>      @ script:python @
>>>>    fn << check1.fn;
>>>> +p1 << check1.p1;
>>>> +p2 << check1.p2;
>>>>    @@
>>>>      print('Warning: function {} has several definitions of '
>>>> -      'Error * local variable'.format(fn))
>>>> +      'Error * local variable: at {}:{} and then at {}:{}'.format(
>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>>      // Warn several propagations in control flow.
>>>>    @check2 disable optional_qualifier exists@
>>>> -identifier fn = rule1.fn;
>>>> -symbol errp;
>>>> +identifier fn, _errp;
>>>>    position p1, p2;
>>>>    @@
>>>>    - fn(..., Error ** ____, ...)
>>>> + fn(..., Error **_errp, ...)
>>>>     {
>>>>         ...
>>>>    (
>>>> -     error_propagate_prepend(errp, ...);@p1
>>>> +     error_propagate_prepend(_errp, ...);@p1
>>>>    |
>>>> -     error_propagate(errp, ...);@p1
>>>> +     error_propagate(_errp, ...);@p1
>>>>    )
>>>>         ...
>>>>    (
>>>> -     error_propagate_prepend(errp, ...);@p2
>>>> +     error_propagate_prepend(_errp, ...);@p2
>>>>    |
>>>> -     error_propagate(errp, ...);@p2
>>>> +     error_propagate(_errp, ...);@p2
>>>>    )
>>>
>>> You change some occurrences of errp to _errp, but not all. It breaks compilation.
>>>
>>>>         ... when any
>>>>     }
>>>> @@ -198,7 +201,7 @@ print('Warning: function {} propagates to errp several times in '
>>>>    // the same, just without error_propagate() call), coccinelle fails to
>>>>    // match this "out: }".
>>>>    @ disable optional_qualifier@
>>>> -identifier rule1.fn, rule1.local_err, out;
>>>> +identifier fn, rule1.local_err, out;
>>>
>>> Hmm. If it improves performance it is strange.. But I can live with this change.
>>>
>>>>    symbol errp;
>>>>    @@
>>>>    @@ -239,7 +242,7 @@ symbol errp;
>>>>    //        *errp = NULL;
>>>>    //    }
>>>>    @ disable optional_qualifier exists@
>>>> -identifier rule1.fn, rule1.local_err;
>>>> +identifier fn, rule1.local_err;
>>>>    expression list args;
>>>>    symbol errp;
>>>>    @@
>>>> @@ -287,7 +290,7 @@ symbol errp;
>>>>    // previous hunk, as this conflicts with other substitutions in it (at
>>>>    // least with "- local_err = NULL").
>>>>    @ disable optional_qualifier@
>>>> -identifier rule1.fn, rule1.local_err;
>>>> +identifier fn, rule1.local_err;
>>>>    symbol errp;
>>>>    @@
>>>>    @@ -301,7 +304,7 @@ symbol errp;
>>>>      // Always use the same pattern for checking error
>>>>    @ disable optional_qualifier@
>>>> -identifier rule1.fn;
>>>> +identifier fn;
>>>>    symbol errp;
>>>>    @@
>>>>    @@ -315,7 +318,7 @@ symbol errp;
>>>>      // Revert temporary ___ identifier.
>>>>    @ disable optional_qualifier@
>>>> -identifier rule1.fn;
>>>> +identifier fn;
>>>>    @@
>>>>       fn(..., Error **
>>>>
>>
>> I append my hacked up version of auto-propagated-errp.cocci.  It
>> produces the same patch as yours for the complete tree.
>>
>>
>>
>> // Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>> //
>> // Copyright (c) 2020 Virtuozzo International GmbH.
>> //
>> // This program is free software; you can redistribute it and/or
>> // modify it under the terms of the GNU General Public License as
>> // published by the Free Software Foundation; either version 2 of the
>> // License, or (at your option) any later version.
>> //
>> // This program is distributed in the hope that it will be useful,
>> // but WITHOUT ANY WARRANTY; without even the implied warranty of
>> // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> // GNU General Public License for more details.
>> //
>> // You should have received a copy of the GNU General Public License
>> // along with this program.  If not, see
>> // <http://www.gnu.org/licenses/>.
>> //
>> // Usage example:
>> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>> //  --macro-file scripts/cocci-macro-file.h --in-place \
>> //  --no-show-diff --max-width 80 FILES...
>> //
>> // Note: --max-width 80 is needed because coccinelle default is less
>> // than 80, and without this parameter coccinelle may reindent some
>> // lines which fit into 80 characters but not to coccinelle default,
>> // which in turn produces extra patch hunks for no reason.
>>
>> // Switch unusual Error ** parameter names to errp
>> // (this is necessary to use ERRP_AUTO_PROPAGATE).
>> //
>> // Disable optional_qualifier to skip functions with
>> // "Error *const *errp" parameter.
>> //
>> // Skip functions with "assert(_errp && *_errp)" statement, because
>> // that signals unusual semantics, and the parameter name may well
>> // serve a purpose. (like nbd_iter_channel_error()).
>> //
>> // Skip util/error.c to not touch, for example, error_propagate() and
>> // error_propagate_prepend().
>> @ depends on !(file in "util/error.c") disable optional_qualifier@
>> identifier fn;
>> identifier _errp != errp;
>> @@
>>
>>   fn(...,
>> -   Error **_errp
>> +   Error **errp
>>      ,...)
>>   {
>> (
>>       ... when != assert(_errp && *_errp)
>> &
>>       <...
>> -    _errp
>> +    errp
>>       ...>
>> )
>>   }
>>
>> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>> // necessary
>> //
>> // Note, that without "when any" the final "..." does not mach
>> // something matched by previous pattern, i.e. the rule will not match
>> // double error_prepend in control flow like in
>> // vfio_set_irq_signaling().
>> //
>> // Note, "exists" says that we want apply rule even if it matches not
>> // on all possible control flows (otherwise, it will not match
>> // standard pattern when error_propagate() call is in if branch).
>> @ disable optional_qualifier exists@
>> identifier fn, local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error **errp, ...)
>>   {
>> +   ERRP_AUTO_PROPAGATE();
>>      ...  when != ERRP_AUTO_PROPAGATE();
>> (
>> (
>>      error_append_hint(errp, ...);
>> |
>>      error_prepend(errp, ...);
>> |
>>      error_vprepend(errp, ...);
>> )
>>      ... when any
>> |
>>      Error *local_err = NULL;
>>      ...
>> (
>>      error_propagate_prepend(errp, local_err, ...);
>> |
>>      error_propagate(errp, local_err);
>> )
>>      ...
>> )
>>   }
>>
>>
>> // Match functions with propagation of local error to errp.
>> // We want to refer these functions in several following rules, but I
>> // don't know a proper way to inherit a function, not just its name
>> // (to not match another functions with same name in following rules).
>> // Not-proper way is as follows: rename errp parameter in functions
>> // header and match it in following rules. Rename it back after all
>> // transformations.
>> //
>> // The simplest case of propagation scheme is single definition of
>> // local_err with at most one error_propagate_prepend or
>> // error_propagate on each control-flow. Still, we want to match more
>> // complex schemes too. We'll warn them with help of further rules.
>> @rule1 disable optional_qualifier exists@
>> identifier fn, local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error **
>> -    errp
>> +    ____
>>      , ...)
>>   {
>>       ...
>>       Error *local_err = NULL;
>>       ...
>> (
>>       error_propagate_prepend(errp, local_err, ...);
>> |
>>       error_propagate(errp, local_err);
>> )
>>       ...
>>   }
>>
>>
>> // Warn several Error * definitions.
>> @check1 disable optional_qualifier exists@
>> identifier fn, _errp, local_err, local_err2;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>>   {
>>       ...
>>       Error *local_err = NULL;@p1
>>       ... when any
>>       Error *local_err2 = NULL;@p2
>>       ... when any
>>   }
>>
>> @ script:python @
>> fn << check1.fn;
>> p1 << check1.p1;
>> p2 << check1.p2;
>> @@
>>
>> print('Warning: function {} has several definitions of '
>>        'Error * local variable: at {}:{} and then at {}:{}'.format(
>>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>
>> // Warn several propagations in control flow.
>> @check2 disable optional_qualifier exists@
>> identifier fn, _errp;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>>   {
>>       ...
>> (
>>       error_propagate_prepend(_errp, ...);@p1
>> |
>>       error_propagate(_errp, ...);@p1
>> )
>>       ...
>> (
>>       error_propagate_prepend(_errp, ...);@p2
>> |
>>       error_propagate(_errp, ...);@p2
>> )
>>       ... when any
>>   }
>>
>> @ script:python @
>> fn << check2.fn;
>> p1 << check2.p1;
>> p2 << check2.p2;
>> @@
>>
>> print('Warning: function {} propagates to errp several times in '
>>        'one control flow: at {}:{} and then at {}:{}'.format(
>>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>
>> // Convert special case with goto separately.
>> // I tried merging this into the following rule the obvious way, but
>> // it made Coccinelle hang on block.c
>> //
>> // Note interesting thing: if we don't do it here, and try to fixup
>> // "out: }" things later after all transformations (the rule will be
>> // the same, just without error_propagate() call), coccinelle fails to
>> // match this "out: }".
>> @ disable optional_qualifier@
>> identifier fn, rule1.local_err, out;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    goto out;
>> +    return;
>>       ...>
>> - out:
>> -    error_propagate(errp, local_err);
>>   }
>>
>> // Convert most of local_err related stuff.
>> //
>> // Note, that we update everything related to matched by rule1
>> // function name and local_err name. We may match something not
>> // related to the pattern matched by rule1. For example, local_err may
>> // be defined with the same name in different blocks inside one
>> // function, and in one block follow the propagation pattern and in
>> // other block doesn't. Or we may have several functions with the same
>> // name (for different configurations).
>> //
>> // Note also that errp-cleaning functions
>> //   error_free_errp
>> //   error_report_errp
>> //   error_reportf_errp
>> //   warn_report_errp
>> //   warn_reportf_errp
>> // are not yet implemented. They must call corresponding Error* -
>> // freeing function and then set *errp to NULL, to avoid further
>> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>> // For example, error_free_errp may look like this:
>> //
>> //    void error_free_errp(Error **errp)
>> //    {
>> //        error_free(*errp);
>> //        *errp = NULL;
>> //    }
>> @ disable optional_qualifier exists@
>> identifier fn, rule1.local_err;
>> expression list args;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> (
>> -    Error *local_err = NULL;
>> |
>>
>> // Convert error clearing functions
>> (
>> -    error_free(local_err);
>> +    error_free_errp(errp);
>> |
>> -    error_report_err(local_err);
>> +    error_report_errp(errp);
>> |
>> -    error_reportf_err(local_err, args);
>> +    error_reportf_errp(errp, args);
>> |
>> -    warn_report_err(local_err);
>> +    warn_report_errp(errp);
>> |
>> -    warn_reportf_err(local_err, args);// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
> //
> // Copyright (c) 2020 Virtuozzo International GmbH.
> //
> // This program is free software; you can redistribute it and/or
> // modify it under the terms of the GNU General Public License as
> // published by the Free Software Foundation; either version 2 of the
> // License, or (at your option) any later version.
> //
> // This program is distributed in the hope that it will be useful,
> // but WITHOUT ANY WARRANTY; without even the implied warranty of
> // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> // GNU General Public License for more details.
> //
> // You should have received a copy of the GNU General Public License
> // along with this program.  If not, see
> // <http://www.gnu.org/licenses/>.
> //
> // Usage example:
> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
> //  --macro-file scripts/cocci-macro-file.h --in-place \
> //  --no-show-diff --max-width 80 FILES...
> //
> // Note: --max-width 80 is needed because coccinelle default is less
> // than 80, and without this parameter coccinelle may reindent some
> // lines which fit into 80 characters but not to coccinelle default,
> // which in turn produces extra patch hunks for no reason.
>
> // Switch unusual Error ** parameter names to errp
> // (this is necessary to use ERRP_AUTO_PROPAGATE).
> //
> // Disable optional_qualifier to skip functions with
> // "Error *const *errp" parameter.
> //
> // Skip functions with "assert(_errp && *_errp)" statement, because
> // that signals unusual semantics, and the parameter name may well
> // serve a purpose. (like nbd_iter_channel_error()).
> //
> // Skip util/error.c to not touch, for example, error_propagate() and
> // error_propagate_prepend().
> @ depends on !(file in "util/error.c") disable optional_qualifier@
> identifier fn;
> identifier _errp != errp;
> @@
>
>  fn(...,
> -   Error **_errp
> +   Error **errp
>     ,...)
>  {
> (
>      ... when != assert(_errp && *_errp)
> &
>      <...
> -    _errp
> +    errp
>      ...>
> )
>  }
>
> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
> // necessary
> //
> // Note, that without "when any" the final "..." does not mach
> // something matched by previous pattern, i.e. the rule will not match
> // double error_prepend in control flow like in
> // vfio_set_irq_signaling().
> //
> // Note, "exists" says that we want apply rule even if it matches not
> // on all possible control flows (otherwise, it will not match
> // standard pattern when error_propagate() call is in if branch).
> @ disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
>
>  fn(..., Error **errp, ...)
>  {
> +   ERRP_AUTO_PROPAGATE();
>     ...  when != ERRP_AUTO_PROPAGATE();
> (
> (
>     error_append_hint(errp, ...);
> |
>     error_prepend(errp, ...);
> |
>     error_vprepend(errp, ...);
> )
>     ... when any
> |
>     Error *local_err = NULL;
>     ...
> (
>     error_propagate_prepend(errp, local_err, ...);
> |
>     error_propagate(errp, local_err);
> )
>     ...
> )
>  }
>
>
> // Match functions with propagation of local error to errp.
> // We want to refer these functions in several following rules, but I
> // don't know a proper way to inherit a function, not just its name
> // (to not match another functions with same name in following rules).
> // Not-proper way is as follows: rename errp parameter in functions
> // header and match it in following rules. Rename it back after all
> // transformations.
> //
> // The simplest case of propagation scheme is single definition of
> // local_err with at most one error_propagate_prepend or
> // error_propagate on each control-flow. Still, we want to match more
> // complex schemes too. We'll warn them with help of further rules.
> @rule1 disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
>
>  fn(..., Error **
> -    errp
> +    ____
>     , ...)
>  {
>      ...
>      Error *local_err = NULL;
>      ...
> (
>      error_propagate_prepend(errp, local_err, ...);
> |
>      error_propagate(errp, local_err);
> )
>      ...
>  }
>
>
> // Warn several Error * definitions.
> @check1 disable optional_qualifier exists@
> identifier fn, _errp, local_err, local_err2;
> position p1, p2;
> @@
>
>  fn(..., Error **_errp, ...)
>  {
>      ...
>      Error *local_err = NULL;@p1
>      ... when any
>      Error *local_err2 = NULL;@p2
>      ... when any
>  }
>
> @ script:python @
> fn << check1.fn;
> p1 << check1.p1;
> p2 << check1.p2;
> @@
>
> print('Warning: function {} has several definitions of '
>       'Error * local variable: at {}:{} and then at {}:{}'.format(
>           fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>
> // Warn several propagations in control flow.
> @check2 disable optional_qualifier exists@
> identifier fn, _errp;
> position p1, p2;
> @@
>
>  fn(..., Error **_errp, ...)
>  {
>      ...
> (
>      error_propagate_prepend(_errp, ...);@p1
> |
>      error_propagate(_errp, ...);@p1
> )
>      ...
> (
>      error_propagate_prepend(_errp, ...);@p2
> |
>      error_propagate(_errp, ...);@p2
> )
>      ... when any
>  }
>
> @ script:python @
> fn << check2.fn;
> p1 << check2.p1;
> p2 << check2.p2;
> @@
>
> print('Warning: function {} propagates to errp several times in '
>       'one control flow: at {}:{} and then at {}:{}'.format(
>           fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>
> // Convert special case with goto separately.
> // I tried merging this into the following rule the obvious way, but
> // it made Coccinelle hang on block.c
> //
> // Note interesting thing: if we don't do it here, and try to fixup
> // "out: }" things later after all transformations (the rule will be
> // the same, just without error_propagate() call), coccinelle fails to
> // match this "out: }".
> @ disable optional_qualifier@
> identifier fn, rule1.local_err, out;
> symbol errp;
> @@
>
>  fn(..., Error ** ____, ...)
>  {
>      <...
> -    goto out;
> +    return;
>      ...>
> - out:
> -    error_propagate(errp, local_err);
>  }
>
> // Convert most of local_err related stuff.
> //
> // Note, that we update everything related to matched by rule1
> // function name and local_err name. We may match something not
> // related to the pattern matched by rule1. For example, local_err may
> // be defined with the same name in different blocks inside one
> // function, and in one block follow the propagation pattern and in
> // other block doesn't. Or we may have several functions with the same
> // name (for different configurations).
> //
> // Note also that errp-cleaning functions
> //   error_free_errp
> //   error_report_errp
> //   error_reportf_errp
> //   warn_report_errp
> //   warn_reportf_errp
> // are not yet implemented. They must call corresponding Error* -
> // freeing function and then set *errp to NULL, to avoid further
> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
> // For example, error_free_errp may look like this:
> //
> //    void error_free_errp(Error **errp)
> //    {
> //        error_free(*errp);
> //        *errp = NULL;
> //    }
> @ disable optional_qualifier exists@
> identifier fn, rule1.local_err;
> expression list args;
> symbol errp;
> @@
>
>  fn(..., Error ** ____, ...)
>  {
>      <...
> (
> -    Error *local_err = NULL;
> |
>
> // Convert error clearing functions
> (
> -    error_free(local_err);
> +    error_free_errp(errp);
> |
> -    error_report_err(local_err);
> +    error_report_errp(errp);
> |
> -    error_reportf_err(local_err, args);
> +    error_reportf_errp(errp, args);
> |
> -    warn_report_err(local_err);
> +    warn_report_errp(errp);
> |
> -    warn_reportf_err(local_err, args);
> +    warn_reportf_errp(errp, args);
> )
> ?-    local_err = NULL;
>
> |
> -    error_propagate_prepend(errp, local_err, args);
> +    error_prepend(errp, args);
> |
> -    error_propagate(errp, local_err);
> |
> -    &local_err
> +    errp
> )
>      ...>
>  }
>
> // Convert remaining local_err usage. For example, different kinds of
> // error checking in if conditionals. We can't merge this into
> // previous hunk, as this conflicts with other substitutions in it (at
> // least with "- local_err = NULL").
> @ disable optional_qualifier@
> identifier fn, rule1.local_err;
> symbol errp;
> @@
>
>  fn(..., Error ** ____, ...)
>  {
>      <...
> -    local_err
> +    *errp
>      ...>
>  }
>
> // Always use the same pattern for checking error
> @ disable optional_qualifier@
> identifier fn;
> symbol errp;
> @@
>
>  fn(..., Error ** ____, ...)
>  {
>      <...
> -    *errp != NULL
> +    *errp
>      ...>
>  }
>
> // Revert temporary ___ identifier.
> @ disable optional_qualifier@
> identifier fn;
> @@
>
>  fn(..., Error **
> -   ____
> +   errp
>     , ...)
>  {
>      ...
>  }
>
>> +    warn_reportf_errp(errp, args);
>> )
>> ?-    local_err = NULL;
>>
>> |
>> -    error_propagate_prepend(errp, local_err, args);
>> +    error_prepend(errp, args);
>> |
>> -    error_propagate(errp, local_err);
>> |
>> -    &local_err
>> +    errp
>> )
>>       ...>
>>   }
>>
>> // Convert remaining local_err usage. For example, different kinds of
>> // error checking in if conditionals. We can't merge this into
>> // previous hunk, as this conflicts with other substitutions in it (at
>> // least with "- local_err = NULL").
>> @ disable optional_qualifier@
>> identifier fn, rule1.local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    local_err
>> +    *errp
>>       ...>
>>   }
>>
>> // Always use the same pattern for checking error
>> @ disable optional_qualifier@
>> identifier fn;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    *errp != NULL
>> +    *errp
>>       ...>
>>   }
>>
>> // Revert temporary ___ identifier.
>> @ disable optional_qualifier@
>> identifier fn;
>> @@
>>
>>   fn(..., Error **
>> -   ____
>> +   errp
>>      , ...)
>>   {
>>       ...
>>   }
>>
>
> OK, I almost OK with it, the only thing I doubt a bit is the following:
>
> We want to keep rule1.local_err inheritance to keep connection with
> local_err definition.

Yes.

> Interesting, when we have both rule1.fn and rule1.local_err inherited,
> do we inherit them in separate (i.e. all possible combinations of fn
> and local_err symbols from rule1) or do we inherit a pair, i.e. only
> fn/local_err pairs, found by rule1? If the latter is correct, that
> with your script we loss this pair inheritance, and go to all possible
> combinations of fn and local_err from rule1, possibly adding some wrong
> conversion (OK, you've checked that no such cases in current code tree).

The chaining "identifier rule1.FOO" is by name.  It's reliable only as
long as there is exactly one instance of the name.

We already discussed the case of the function name: if there are two
instances of foo(), and rule1 matches only one of them, then we
nevertheless apply the rules chained to rule1 to both.  Because that can
be wrong, you came up with the ___ trick, which chains reliably.

The same issue exists with the variable name: if there are two instances
of @local_err, and rule1 matches only one of them, then we nevertheless
apply the rules chained to rule1 to both.  Can also be wrong.

What are the conditions for "wrong"?

Because the ___ chaining is reliable, we know rule1 matched the
function, i.e. it has a parameter Error **errp, and it has a automatic
variable Error *local_err = NULL.

We're good as long as *all* identifiers @local_err in this function are
declared that way.  This seems quite likely.  It's not certain, though.

Since nested declarations of Error ** variables are rare, we can rely on
review to ensure we transform these functions correctly.

> So, dropping inheritance in check-rules makes sence, as it may match
> (and warn) more interesting cases.
>
> But for other rules, I'd prefere to be safer, and explictly inherit all
> actually inherited identifiers..

I still can't see what chaining by function name in addition to the ___
chaining buys us.

>                                  Still, I feel, we'll never be
> absolutely safe with coccinelle :)

Right, although this particular problem is not really Coccinelle's
fault.  Blindly treating all instances of a certain identifier in a
certain area the same regardless of how they are bound to declarations
is fundamentally unreliable, regardless of your actual tooling.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-16  8:21                 ` [Xen-devel] " Markus Armbruster
@ 2020-03-17  9:29                   ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-17  9:29 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

16.03.2020 11:21, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> On 14.03.2020 00:54, Markus Armbruster wrote:
>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>
>>>> 13.03.2020 18:42, Markus Armbruster wrote:
>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>
>>>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>>>> out now as is.
>>>>>>>
>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>>
>>>>>>>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>>>>>>>> does corresponding changes in code (look for details in
>>>>>>>> include/qapi/error.h)
>>>>>>>>
>>>>>>>> Usage example:
>>>>>>>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>>>>      --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>>>>>>>      --max-width 80 FILES...
>>>>>>>>
>>>>>>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>>>>>>> ---
>>>>>>>>
>>>>>>>> Cc: Eric Blake <eblake@redhat.com>
>>>>>>>> Cc: Kevin Wolf <kwolf@redhat.com>
>>>>>>>> Cc: Max Reitz <mreitz@redhat.com>
>>>>>>>> Cc: Greg Kurz <groug@kaod.org>
>>>>>>>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>>>>>>>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>>>>>>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>>>>>>> Cc: Paul Durrant <paul@xen.org>
>>>>>>>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>>>>>>>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>>>>>>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>>>>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>>>>>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>>>>>>>> Cc: Markus Armbruster <armbru@redhat.com>
>>>>>>>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>>>>>>>> Cc: qemu-devel@nongnu.org
>>>>>>>> Cc: qemu-block@nongnu.org
>>>>>>>> Cc: xen-devel@lists.xenproject.org
>>>>>>>>
>>>>>>>>      scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>>>>>>>      include/qapi/error.h                          |   3 +
>>>>>>>>      MAINTAINERS                                   |   1 +
>>>>>>>>      3 files changed, 331 insertions(+)
>>>>>>>>      create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>>>
>>>>>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>>> new file mode 100644
>>>>>>>> index 0000000000..7dac2dcfa4
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>>> @@ -0,0 +1,327 @@
>>>>>>>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>>>>>>> +//
>>>>>>>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>>>>>>>> +//
>>>>>>>> +// This program is free software; you can redistribute it and/or
>>>>>>>> +// modify it under the terms of the GNU General Public License as
>>>>>>>> +// published by the Free Software Foundation; either version 2 of the
>>>>>>>> +// License, or (at your option) any later version.
>>>>>>>> +//
>>>>>>>> +// This program is distributed in the hope that it will be useful,
>>>>>>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>>>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>>>>>> +// GNU General Public License for more details.
>>>>>>>> +//
>>>>>>>> +// You should have received a copy of the GNU General Public License
>>>>>>>> +// along with this program.  If not, see
>>>>>>>> +// <http://www.gnu.org/licenses/>.
>>>>>>>> +//
>>>>>>>> +// Usage example:
>>>>>>>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>>>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>>>>>>>> +//  --no-show-diff --max-width 80 FILES...
>>>>>>>> +//
>>>>>>>> +// Note: --max-width 80 is needed because coccinelle default is less
>>>>>>>> +// than 80, and without this parameter coccinelle may reindent some
>>>>>>>> +// lines which fit into 80 characters but not to coccinelle default,
>>>>>>>> +// which in turn produces extra patch hunks for no reason.
>>>>>>>
>>>>>>> This is about unwanted reformatting of parameter lists due to the ___
>>>>>>> chaining hack.  --max-width 80 makes that less likely, but not
>>>>>>> impossible.
>>>>>>>
>>>>>>> We can search for unwanted reformatting of parameter lists.  I think
>>>>>>> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
>>>>>>> tree, I get one false positive (not a parameter list), and one hit:
>>>>>>>
>>>>>>>         @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>>>>>>>              }
>>>>>>>          }
>>>>>>>
>>>>>>>         -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>>>>>>>         +void object_apply_global_props(Object *obj, const GPtrArray *props,
>>>>>>>         +                               Error **errp)
>>>>>>>          {
>>>>>>>         +    ERRP_AUTO_PROPAGATE();
>>>>>>>              int i;
>>>>>>>
>>>>>>>              if (!props) {
>>>>>>>
>>>>>>> Reformatting, but not unwanted.
>>>>>>
>>>>>> Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
>>>>>> ERRP_AUTO_PROPAGATE addition even for non-automatic patch.
>>>>>
>>>>> Agree.
>>>>>
>>>>>>>
>>>>>>> The --max-width 80 hack is good enough for me.
>>>>>>>
>>>>>>> It does result in slightly long transformed lines, e.g. this one in
>>>>>>> replication.c:
>>>>>>>
>>>>>>>         @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>>>>>>>                  s->mode = REPLICATION_MODE_PRIMARY;
>>>>>>>                  top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>>>>>>>                  if (top_id) {
>>>>>>>         -            error_setg(&local_err, "The primary side does not support option top-id");
>>>>>>>         +            error_setg(errp, "The primary side does not support option top-id");
>>>>>>>                      goto fail;
>>>>>>>                  }
>>>>>>>              } else if (!strcmp(mode, "secondary")) {
>>>>>>>
>>>>>>> v8 did break this line (that's how I found it).  However, v9 still
>>>>>>> shortens the line, just not below the target.  All your + lines look
>>>>>>> quite unlikely to lengthen lines.  Let's not worry about this.
>>>>>>>
>>>>>>>> +// Switch unusual Error ** parameter names to errp
>>>>>>>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>>>>>>>> +//
>>>>>>>> +// Disable optional_qualifier to skip functions with
>>>>>>>> +// "Error *const *errp" parameter.
>>>>>>>> +//
>>>>>>>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>>>>>>>> +// that signals unusual semantics, and the parameter name may well
>>>>>>>> +// serve a purpose. (like nbd_iter_channel_error()).
>>>>>>>> +//
>>>>>>>> +// Skip util/error.c to not touch, for example, error_propagate() and
>>>>>>>> +// error_propagate_prepend().
>>>>>>>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>>>>>>>> +identifier fn;
>>>>>>>> +identifier _errp != errp;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(...,
>>>>>>>> +-   Error **_errp
>>>>>>>> ++   Error **errp
>>>>>>>> +    ,...)
>>>>>>>> + {
>>>>>>>> +(
>>>>>>>> +     ... when != assert(_errp && *_errp)
>>>>>>>> +&
>>>>>>>> +     <...
>>>>>>>> +-    _errp
>>>>>>>> ++    errp
>>>>>>>> +     ...>
>>>>>>>> +)
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>>>>>>> +// necessary
>>>>>>>> +//
>>>>>>>> +// Note, that without "when any" the final "..." does not mach
>>>>>>>> +// something matched by previous pattern, i.e. the rule will not match
>>>>>>>> +// double error_prepend in control flow like in
>>>>>>>> +// vfio_set_irq_signaling().
>>>>>>>> +//
>>>>>>>> +// Note, "exists" says that we want apply rule even if it matches not
>>>>>>>> +// on all possible control flows (otherwise, it will not match
>>>>>>>> +// standard pattern when error_propagate() call is in if branch).
>>>>>>>> +@ disable optional_qualifier exists@
>>>>>>>> +identifier fn, local_err;
>>>>>>>> +symbol errp;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error **errp, ...)
>>>>>>>> + {
>>>>>>>> ++   ERRP_AUTO_PROPAGATE();
>>>>>>>> +    ...  when != ERRP_AUTO_PROPAGATE();
>>>>>>>> +(
>>>>>>>> +(
>>>>>>>> +    error_append_hint(errp, ...);
>>>>>>>> +|
>>>>>>>> +    error_prepend(errp, ...);
>>>>>>>> +|
>>>>>>>> +    error_vprepend(errp, ...);
>>>>>>>> +)
>>>>>>>> +    ... when any
>>>>>>>> +|
>>>>>>>> +    Error *local_err = NULL;
>>>>>>>> +    ...
>>>>>>>> +(
>>>>>>>> +    error_propagate_prepend(errp, local_err, ...);
>>>>>>>> +|
>>>>>>>> +    error_propagate(errp, local_err);
>>>>>>>> +)
>>>>>>>> +    ...
>>>>>>>> +)
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> +
>>>>>>>> +// Match functions with propagation of local error to errp.
>>>>>>>> +// We want to refer these functions in several following rules, but I
>>>>>>>> +// don't know a proper way to inherit a function, not just its name
>>>>>>>> +// (to not match another functions with same name in following rules).
>>>>>>>> +// Not-proper way is as follows: rename errp parameter in functions
>>>>>>>> +// header and match it in following rules. Rename it back after all
>>>>>>>> +// transformations.
>>>>>>>> +//
>>>>>>>> +// The simplest case of propagation scheme is single definition of
>>>>>>>> +// local_err with at most one error_propagate_prepend or
>>>>>>>> +// error_propagate on each control-flow. Still, we want to match more
>>>>>>>> +// complex schemes too. We'll warn them with help of further rules.
>>>>>>>
>>>>>>> I think what we actually want is to examine instances of this pattern to
>>>>>>> figure out whether and how we want to transform them.  Perhaps:
>>>>>>>
>>>>>>>         // The common case is a single definition of local_err with at most one
>>>>>>>         // error_propagate_prepend() or error_propagate() on each control-flow
>>>>>>>         // path. Instances of this case we convert with this script. Functions
>>>>>>
>>>>>> For me, sounds a bit like "other things we don't convert".
>>>>>> Actually we convert other things too.
>>>>>
>>>>> What other patterns of error propagation do we convert?
>>>>
>>>> Something like in xen_block_device_destroy, why not? Otherwise, it's better to avoid
>>>> matching things like xen_block_device_destroy, not just warn them.
>>>> But I'd prefer to proceed now as is to fit into 5.0.. Too much time already
>>>> spent on this. So, I'm OK with your wording too.
>>>
>>> Let's scratch "Instances of this case we convert with this script."
>>
>> OK
>>
>>>
>>>>>>>         // with multiple definitions or propagates we want to examine
>>>>>>>         // manually. Later rules emit warnings to guide us to them.
>>>>>>>
>>>>>>>> +@rule1 disable optional_qualifier exists@
>>>>>>>> +identifier fn, local_err;
>>>>>>>> +symbol errp;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error **
>>>>>>>> +-    errp
>>>>>>>> ++    ____
>>>>>>>> +    , ...)
>>>>>>>> + {
>>>>>>>> +     ...
>>>>>>>> +     Error *local_err = NULL;
>>>>>>>> +     ...
>>>>>>>> +(
>>>>>>>> +     error_propagate_prepend(errp, local_err, ...);
>>>>>>>> +|
>>>>>>>> +     error_propagate(errp, local_err);
>>>>>>>> +)
>>>>>>>> +     ...
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> +
>>>>>>>> +// Warn several Error * definitions.
>>>>>>>> +@check1 disable optional_qualifier exists@
>>>>>>>> +identifier fn = rule1.fn, local_err, local_err2;
>>>>>>>
>>>>>>> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
>>>>>>> particular reason for the difference?
>>>>>>
>>>>>> I didn't find other way to ref check1.fn in next python rule. It just don't
>>>>>> work if I write here just rule1.fn.
>>>>>>
>>>>>>>
>>>>>>> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
>>>>>>> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
>>>>>>> everywhere, then apply the script to the complete tree, I get the same
>>>>>>> result.
>>>>>>
>>>>>> I think, it's more efficient to reuse names from previous rules. I think it should
>>>>>> work faster (more information, less extra matching).
>>>>>
>>>>> Nope.  With my hacked up script (patch appended) Coccinelle is actually
>>>>> *faster* for the .[ch] touched by this series: with your unmodified
>>>>> script, it takes a bit over 12s on my box, with mine around 7s.  Output
>>>>> is identical.
>>>>>
>>>>> Never guess performance, always measure it :)
>>>>
>>>> Hmm, whole tree results would be better proof
>>>>
>>>>>
>>>>> Two notes on my script:
>>>>>
>>>>> * Unlike yours, it recognizes double-propagation in my test case.
>>>>>      Discussed below.
>>>>>
>>>>> * Its "several definitions of" warning includes positions.  That turned
>>>>>      out to be useless, but I've been too lazy to take that out again.
>>>>>
>>>>>>>
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>> + {
>>>>>>>> +     ...
>>>>>>>> +     Error *local_err = NULL;
>>>>>>>> +     ... when any
>>>>>>>> +     Error *local_err2 = NULL;
>>>>>>>> +     ... when any
>>>>>>>> + }
>>>
>>> This flags functions that have more than one declaration along any
>>> control flow path.  It doesn't flag this one:
>>>
>>>       void gnat(bool b, Error **errp)
>>>       {
>>>           if (b) {
>>>               Error *local_err = NULL;
>>>               foo(arg, &local_err);
>>>               error_propagate(errp, local_err);
>>>           } else {
>>>               Error *local_err = NULL;
>>>               bar(arg, &local_err);
>>>               error_propagate(errp, local_err);
>>>           }
>>>       }
>>>
>>> The Coccinelle script does the right thing for this one regardless.
>>>
>>> I'd prefer to have such functions flagged, too.  But spending time on
>>> convincing Coccinelle to do it for me is not worthwhile; I can simply
>>> search the diff produced by Coccinelle for deletions of declarations
>>> that are not indented exactly four spaces.
>>>
>>> But if we keep this rule, we should adjust its comment
>>>
>>>       // Warn several Error * definitions.
>>>
>>> because it sure suggests it also catches functions like the one I gave
>>> above.
>>
>> Hmm, yes.. We can write "Warn several Error * definitions in _one_
>> control flow (it's not so trivial to match _any_ case with several
>> definitions with coccinelle)" or something like this.
> 
> Ha, "trivial" reminds me of a story.  The math professor, after having
> spent a good chunk of his lecture developing a proof on the blackboad
> turns to the audience to explain why this little part doesn't require
> proof with the words familiar to any math student "and this is trivial."
> Pause, puzzled look...  "Is it trivial?"  Pause, storms out of the
> lecture hall.  A minute or three pass.  Professor comes back beaming,
> "it is trivial!", and proceeds with the proof.
> 
> My point is: it might be trivial with Coccinelle once you know how to do
> it.  We don't.
> 
> Suggest "(can't figure out how to match several definitions regardless
> of control flow)".

Wrong too, because I can:) for example, chaining two rules, catching the
positions of definition and check that they are different.. Or, some
cheating with python script.. That's why I wrote "not trivial",

So, most correct would be "(can't figure out how to simply match several definitions regardless
 > of control flow)".

But again, coccinelle is for matching control flows, so its probably impossible to match such thing..

> 
>>
>>>
>>>>>>>> +
>>>>>>>> +@ script:python @
>>>>>>>> +fn << check1.fn;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> +print('Warning: function {} has several definitions of '
>>>>>>>> +      'Error * local variable'.format(fn))
>>>>>>>> +
>>>>>>>> +// Warn several propagations in control flow.
>>>>>>>> +@check2 disable optional_qualifier exists@
>>>>>>>> +identifier fn = rule1.fn;
>>>>>>>> +symbol errp;
>>>>>>>> +position p1, p2;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>> + {
>>>>>>>> +     ...
>>>>>>>> +(
>>>>>>>> +     error_propagate_prepend(errp, ...);@p1
>>>>>>>> +|
>>>>>>>> +     error_propagate(errp, ...);@p1
>>>>>>>> +)
>>>>>>>> +     ...
>>>>>>>> +(
>>>>>>>> +     error_propagate_prepend(errp, ...);@p2
>>>>>>>> +|
>>>>>>>> +     error_propagate(errp, ...);@p2
>>>>>>>> +)
>>>>>>>> +     ... when any
>>>>>>>> + }
>>>>>>>> +
>>>>>>>
>>>>>>> Hmm, we don't catch the example I used in review of v8:
>>>>>>>
>>>>>>>         extern foo(int, Error **);
>>>>>>>         extern bar(int, Error **);
>>>>>>>
>>>>>>>         void frob(Error **errp)
>>>>>>>         {
>>>>>>>             Error *local_err = NULL;
>>>>>>>             int arg;
>>>>>>>
>>>>>>>             foo(arg, errp);
>>>>>>>             bar(arg, &local_err);
>>>>>>>             error_propagate(errp, local_err);
>>>>>>>             bar(arg + 1, &local_err);
>>>>>>>             error_propagate(errp, local_err);
>>>>>>>         }
>>>>>>>
>>>>>>> I believe this is because rule1 does not match here.
>>>>>>
>>>>>> Yes, rule1 wants at least one code flow with non-doubled propagation.
>>>>>>
>>>>>>>
>>>>>>> If I change the rule as follows, it catches the example:
>>>>>>>
>>>>>>>         @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
>>>>>>>
>>>>>>>          // Warn several propagations in control flow.
>>>>>>>          @check2 disable optional_qualifier exists@
>>>>>>>         -identifier fn = rule1.fn;
>>>>>>>         -symbol errp;
>>>>>>>         +identifier fn, _errp;
>>>>>>>          position p1, p2;
>>>>>>>          @@
>>>>>>>
>>>>>>>         - fn(..., Error ** ____, ...)
>>>>>>>         + fn(..., Error **_errp, ...)
>>>>>>>           {
>>>>>>>               ...
>>>>>>>          (
>>>>>>>         -     error_propagate_prepend(errp, ...);@p1
>>>>>>>         +     error_propagate_prepend(_errp, ...);@p1
>>>>>>>          |
>>>>>>>         -     error_propagate(errp, ...);@p1
>>>>>>>         +     error_propagate(_errp, ...);@p1
>>>>>>>          )
>>>>>>>               ...
>>>>>>>          (
>>>>>>>         -     error_propagate_prepend(errp, ...);@p2
>>>>>>>         +     error_propagate_prepend(_errp, ...);@p2
>>>>>>>          |
>>>>>>>         -     error_propagate(errp, ...);@p2
>>>>>>>         +     error_propagate(_errp, ...);@p2
>>>>>>>          )
>>>>>>>               ... when any
>>>>>>>           }
>>>>>>>
>>>>>>> To my mild surprise, it still doesn't find anything in our tree.
>>>>>>>
>>>>>>> Should we decouple the previous rule from rule1, too?  I tested the
>>>>>>> following on the whole tree:
>>>>>>
>>>>>> I don't think so. Why to check what we are not going to convert? If we want
>>>>>> to check side things, it's better to do it in other coccinelle script..
>>>>>
>>>>> Misunderstanding?  The rules are still chained together via the ___
>>>>> hack, just not via function name, because that's unreliable and
>>>>> redundant.
>>>>
>>>> Strange.. Then, how can it match something not matched by rule1?
>>>
>>> I think I got confused when I wrote the "Misunderstanding?" paragraph.
>>>
>>> Let me try again.
>>>
>>> First rule check2.
>>>
>>> The common case is a at most one propagation to @errp along any control
>>> flow path.  We trust your Coccinelle script to convert that alright.
>>>
>>> Any other propagation to @errp I want to review.  Whether the script
>>> attempts a conversion or not is unimportant, as long as it points me to
>>> the function to review.
>>>
>>> Rule rule1 matches functions that propagate to @errp once along at least
>>> one control flow path.
>>>
>>> Unchained from rule rule1, rule check2 flags any function that
>>> propagates to @errp multiple times along any control flow path.
>>>
>>> Chained to rule1, it flags only functions that also have a path with
>>> single propagation.
>>>
>>> In other words, the unchained rule flags *all* multi-propagations to
>>> @errp, while the chained rule flags only the ones the script attempts to
>>> convert.  The former is much more useful to me.
>>>
>>> Now rule check1.  It flags functions with multiple declarations along
>>> any control flow path.  Again, chaining it to rule1 restricts it to the
>>> functions we attempt to convert.  Makes it less useful to me.  However,
>>> because my desire to review multiple declarations in function we don't
>>> attempt to convert is lower than my desire to review multiple
>>> propagations to @errp in such functions, chaining check1 is tolerable
>>> for me.  But why chain check1 if we don't chain check2?
>>>
>>
>> OK, let's unchain them.
>>
>>>>
>>>>>
>>>>>>>
>>>>>>>         @@ -136,10 +136,10 @@ symbol errp;
>>>>>>>
>>>>>>>          // Warn several Error * definitions.
>>>>>>>          @check1 disable optional_qualifier exists@
>>>>>>>         -identifier fn = rule1.fn, local_err, local_err2;
>>>>>>>         +identifier fn, _errp, local_err, local_err2;
>>>>>>>          @@
>>>>>>>
>>>>>>>         - fn(..., Error ** ____, ...)
>>>>>>>         + fn(..., Error **_errp, ...)
>>>>>>>           {
>>>>>>>               ...
>>>>>>>               Error *local_err = NULL;
>>>>>>>
>>>>>>> Warnings remain unchanged.
>>>>>>>
>>>>>>>> +@ script:python @
>>>>>>>> +fn << check2.fn;
>>>>>>>> +p1 << check2.p1;
>>>>>>>> +p2 << check2.p2;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> +print('Warning: function {} propagates to errp several times in '
>>>>>>>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>>>>>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>>>>>> +
>>>>>>>> +// Convert special case with goto separately.
>>>>>>>> +// I tried merging this into the following rule the obvious way, but
>>>>>>>> +// it made Coccinelle hang on block.c
>>>>>>>> +//
>>>>>>>> +// Note interesting thing: if we don't do it here, and try to fixup
>>>>>>>> +// "out: }" things later after all transformations (the rule will be
>>>>>>>> +// the same, just without error_propagate() call), coccinelle fails to
>>>>>>>> +// match this "out: }".
>>>>>>>> +@ disable optional_qualifier@
>>>>>>>> +identifier rule1.fn, rule1.local_err, out;
>>>>>>>
>>>>>>> As explained above, I doubt the need for rule1.fn.  We do need
>>>>>>> rule1.local_err to avoid unwanted transformations.  More of the same
>>>>>>> below.
>>>>>>
>>>>>> Logically, I want to inherit from rule1. So why not to stress it by inheriting
>>>>>> fn variable? It's just a correct thing to do.
>>>>>> And I hope it helps coccinelle to work more efficiently.
>>>>>>
>>>>>>>
>>>>>>>> +symbol errp;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>> + {
>>>>>>>> +     <...
>>>>>>>> +-    goto out;
>>>>>>>> ++    return;
>>>>>>>> +     ...>
>>>>>>>> +- out:
>>>>>>>> +-    error_propagate(errp, local_err);
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> +// Convert most of local_err related stuff.
>>>>>>>> +//
>>>>>>>> +// Note, that we update everything related to matched by rule1
>>>>>>>> +// function name and local_err name. We may match something not
>>>>>>>> +// related to the pattern matched by rule1. For example, local_err may
>>>>>>>> +// be defined with the same name in different blocks inside one
>>>>>>>> +// function, and in one block follow the propagation pattern and in
>>>>>>>> +// other block doesn't. Or we may have several functions with the same
>>>>>>>> +// name (for different configurations).
>>>>>>>> +//
>>>>>>>> +// Note also that errp-cleaning functions
>>>>>>>> +//   error_free_errp
>>>>>>>> +//   error_report_errp
>>>>>>>> +//   error_reportf_errp
>>>>>>>> +//   warn_report_errp
>>>>>>>> +//   warn_reportf_errp
>>>>>>>> +// are not yet implemented. They must call corresponding Error* -
>>>>>>>> +// freeing function and then set *errp to NULL, to avoid further
>>>>>>>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>>>>>>> +// For example, error_free_errp may look like this:
>>>>>>>> +//
>>>>>>>> +//    void error_free_errp(Error **errp)
>>>>>>>> +//    {
>>>>>>>> +//        error_free(*errp);
>>>>>>>> +//        *errp = NULL;
>>>>>>>> +//    }
>>>>>>>> +@ disable optional_qualifier exists@
>>>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>>>> +expression list args;
>>>>>>>> +symbol errp;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>> + {
>>>>>>>> +     <...
>>>>>>>> +(
>>>>>>>> +-    Error *local_err = NULL;
>>>>>>>> +|
>>>>>>>> +
>>>>>>>> +// Convert error clearing functions
>>>>>>>> +(
>>>>>>>> +-    error_free(local_err);
>>>>>>>> ++    error_free_errp(errp);
>>>>>>>> +|
>>>>>>>> +-    error_report_err(local_err);
>>>>>>>> ++    error_report_errp(errp);
>>>>>>>> +|
>>>>>>>> +-    error_reportf_err(local_err, args);
>>>>>>>> ++    error_reportf_errp(errp, args);
>>>>>>>> +|
>>>>>>>> +-    warn_report_err(local_err);
>>>>>>>> ++    warn_report_errp(errp);
>>>>>>>> +|
>>>>>>>> +-    warn_reportf_err(local_err, args);
>>>>>>>> ++    warn_reportf_errp(errp, args);
>>>>>>>> +)
>>>>>>>> +?-    local_err = NULL;
>>>>>>>> +
>>>>>>>> +|
>>>>>>>> +-    error_propagate_prepend(errp, local_err, args);
>>>>>>>> ++    error_prepend(errp, args);
>>>>>>>> +|
>>>>>>>> +-    error_propagate(errp, local_err);
>>>>>>>> +|
>>>>>>>> +-    &local_err
>>>>>>>> ++    errp
>>>>>>>> +)
>>>>>>>> +     ...>
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> +// Convert remaining local_err usage. For example, different kinds of
>>>>>>>> +// error checking in if conditionals. We can't merge this into
>>>>>>>> +// previous hunk, as this conflicts with other substitutions in it (at
>>>>>>>> +// least with "- local_err = NULL").
>>>>>>>> +@ disable optional_qualifier@
>>>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>>>> +symbol errp;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>> + {
>>>>>>>> +     <...
>>>>>>>> +-    local_err
>>>>>>>> ++    *errp
>>>>>>>> +     ...>
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> +// Always use the same pattern for checking error
>>>>>>>> +@ disable optional_qualifier@
>>>>>>>> +identifier rule1.fn;
>>>>>>>> +symbol errp;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>> + {
>>>>>>>> +     <...
>>>>>>>> +-    *errp != NULL
>>>>>>>> ++    *errp
>>>>>>>> +     ...>
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> +// Revert temporary ___ identifier.
>>>>>>>> +@ disable optional_qualifier@
>>>>>>>> +identifier rule1.fn;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error **
>>>>>>>> +-   ____
>>>>>>>> ++   errp
>>>>>>>> +    , ...)
>>>>>>>> + {
>>>>>>>> +     ...
>>>>>>>> + }
>>>>>>>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>>>>>>>> index 30140d9bfe..56c133520d 100644
>>>>>>>> --- a/include/qapi/error.h
>>>>>>>> +++ b/include/qapi/error.h
>>>>>>>> @@ -214,6 +214,9 @@
>>>>>>>>       *         }
>>>>>>>>       *         ...
>>>>>>>>       *     }
>>>>>>>> + *
>>>>>>>> + * For mass-conversion use script
>>>>>>>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>>>       */
>>>>>>>>        #ifndef ERROR_H
>>>>>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>>>>>> index 857f969aa1..047f1b9714 100644
>>>>>>>> --- a/MAINTAINERS
>>>>>>>> +++ b/MAINTAINERS
>>>>>>>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>>>>>>>      F: qapi/error.json
>>>>>>>>      F: util/error.c
>>>>>>>>      F: util/qemu-error.c
>>>>>>>> +F: scripts/coccinelle/*err*.cocci
>>>>>>>>        GDB stub
>>>>>>>>      M: Alex Bennée <alex.bennee@linaro.org>
>>>>>>>
>>>>>
>>>>>
>>>>>    From 42a08c529024337d1b859839c9ce7f797f784555 Mon Sep 17 00:00:00 2001
>>>>> From: Markus Armbruster <armbru@redhat.com>
>>>>> Date: Fri, 13 Mar 2020 14:27:57 +0100
>>>>> Subject: [PATCH] fixup! scripts: Coccinelle script to use
>>>>>     ERRP_AUTO_PROPAGATE()
>>>>>
>>>>> ---
>>>>>     scripts/coccinelle/auto-propagated-errp.cocci | 37 ++++++++++---------
>>>>>     1 file changed, 20 insertions(+), 17 deletions(-)
>>>>>
>>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>> index 7dac2dcfa4..43b0b0e63b 100644
>>>>> --- a/scripts/coccinelle/auto-propagated-errp.cocci
>>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>> @@ -136,45 +136,48 @@ symbol errp;
>>>>>       // Warn several Error * definitions.
>>>>>     @check1 disable optional_qualifier exists@
>>>>> -identifier fn = rule1.fn, local_err, local_err2;
>>>>> +identifier fn, _errp, local_err, local_err2;
>>>>> +position p1, p2;
>>>>
>>>>
>>>> Hmm, seems like I forget to define ____ as symbol in my patch
>>>
>>> Coccinelle defaults to symbol.
>>
>> But for errp we saw warnings simetimes.
> 
> I believe it warns when you use rely on the symbol default while also
> using it as something else in other rules.
> 
> Feel free to explicitly define it as symbol.
> 
>>>>>     @@
>>>>>     - fn(..., Error ** ____, ...)
>>>>> + fn(..., Error **_errp, ...)
>>>>
>>>> Ahmm.. it will break compilation?
>>>>
>>>> Or, how will it work when _errp defined as meta variable is only in "+..." line? Should it be symbol instead, or just not defined?
>>>
>>> Misunderstanding?  It's a diff between your .cocci and mine.
>>
>> Oops, yes, sorry. Patches to coccinelle scripts are tricky thing.
>>
>>> My version
>>> is
>>>
>>>       // Warn several Error * definitions.
>>>       @check1 disable optional_qualifier exists@
>>>       identifier fn, _errp, local_err, local_err2;
>>>       position p1, p2;
>>>       @@
>>>
>>>        fn(..., Error **_errp, ...)
>>>        {
>>>            ...
>>>            Error *local_err = NULL;@p1
>>>            ... when any
>>>            Error *local_err2 = NULL;@p2
>>>            ... when any
>>>        }
>>>
>>>       @ script:python @
>>>       fn << check1.fn;
>>>       p1 << check1.p1;
>>>       p2 << check1.p2;
>>>       @@
>>>
>>>>>      {
>>>>>          ...
>>>>> -     Error *local_err = NULL;
>>>>> +     Error *local_err = NULL;@p1
>>>>
>>>> Why to do -/+ here? Nothing changed..
>>>>
>>>>>          ... when any
>>>>> -     Error *local_err2 = NULL;
>>>>> +     Error *local_err2 = NULL;@p2
>>>>>          ... when any
>>>>>      }
>>>>>       @ script:python @
>>>>>     fn << check1.fn;
>>>>> +p1 << check1.p1;
>>>>> +p2 << check1.p2;
>>>>>     @@
>>>>>       print('Warning: function {} has several definitions of '
>>>>> -      'Error * local variable'.format(fn))
>>>>> +      'Error * local variable: at {}:{} and then at {}:{}'.format(
>>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>>>       // Warn several propagations in control flow.
>>>>>     @check2 disable optional_qualifier exists@
>>>>> -identifier fn = rule1.fn;
>>>>> -symbol errp;
>>>>> +identifier fn, _errp;
>>>>>     position p1, p2;
>>>>>     @@
>>>>>     - fn(..., Error ** ____, ...)
>>>>> + fn(..., Error **_errp, ...)
>>>>>      {
>>>>>          ...
>>>>>     (
>>>>> -     error_propagate_prepend(errp, ...);@p1
>>>>> +     error_propagate_prepend(_errp, ...);@p1
>>>>>     |
>>>>> -     error_propagate(errp, ...);@p1
>>>>> +     error_propagate(_errp, ...);@p1
>>>>>     )
>>>>>          ...
>>>>>     (
>>>>> -     error_propagate_prepend(errp, ...);@p2
>>>>> +     error_propagate_prepend(_errp, ...);@p2
>>>>>     |
>>>>> -     error_propagate(errp, ...);@p2
>>>>> +     error_propagate(_errp, ...);@p2
>>>>>     )
>>>>
>>>> You change some occurrences of errp to _errp, but not all. It breaks compilation.
>>>>
>>>>>          ... when any
>>>>>      }
>>>>> @@ -198,7 +201,7 @@ print('Warning: function {} propagates to errp several times in '
>>>>>     // the same, just without error_propagate() call), coccinelle fails to
>>>>>     // match this "out: }".
>>>>>     @ disable optional_qualifier@
>>>>> -identifier rule1.fn, rule1.local_err, out;
>>>>> +identifier fn, rule1.local_err, out;
>>>>
>>>> Hmm. If it improves performance it is strange.. But I can live with this change.
>>>>
>>>>>     symbol errp;
>>>>>     @@
>>>>>     @@ -239,7 +242,7 @@ symbol errp;
>>>>>     //        *errp = NULL;
>>>>>     //    }
>>>>>     @ disable optional_qualifier exists@
>>>>> -identifier rule1.fn, rule1.local_err;
>>>>> +identifier fn, rule1.local_err;
>>>>>     expression list args;
>>>>>     symbol errp;
>>>>>     @@
>>>>> @@ -287,7 +290,7 @@ symbol errp;
>>>>>     // previous hunk, as this conflicts with other substitutions in it (at
>>>>>     // least with "- local_err = NULL").
>>>>>     @ disable optional_qualifier@
>>>>> -identifier rule1.fn, rule1.local_err;
>>>>> +identifier fn, rule1.local_err;
>>>>>     symbol errp;
>>>>>     @@
>>>>>     @@ -301,7 +304,7 @@ symbol errp;
>>>>>       // Always use the same pattern for checking error
>>>>>     @ disable optional_qualifier@
>>>>> -identifier rule1.fn;
>>>>> +identifier fn;
>>>>>     symbol errp;
>>>>>     @@
>>>>>     @@ -315,7 +318,7 @@ symbol errp;
>>>>>       // Revert temporary ___ identifier.
>>>>>     @ disable optional_qualifier@
>>>>> -identifier rule1.fn;
>>>>> +identifier fn;
>>>>>     @@
>>>>>        fn(..., Error **
>>>>>
>>>
>>> I append my hacked up version of auto-propagated-errp.cocci.  It
>>> produces the same patch as yours for the complete tree.
>>>
>>>
>>>
>>> // Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>> //
>>> // Copyright (c) 2020 Virtuozzo International GmbH.
>>> //
>>> // This program is free software; you can redistribute it and/or
>>> // modify it under the terms of the GNU General Public License as
>>> // published by the Free Software Foundation; either version 2 of the
>>> // License, or (at your option) any later version.
>>> //
>>> // This program is distributed in the hope that it will be useful,
>>> // but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> // GNU General Public License for more details.
>>> //
>>> // You should have received a copy of the GNU General Public License
>>> // along with this program.  If not, see
>>> // <http://www.gnu.org/licenses/>.
>>> //
>>> // Usage example:
>>> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>> //  --macro-file scripts/cocci-macro-file.h --in-place \
>>> //  --no-show-diff --max-width 80 FILES...
>>> //
>>> // Note: --max-width 80 is needed because coccinelle default is less
>>> // than 80, and without this parameter coccinelle may reindent some
>>> // lines which fit into 80 characters but not to coccinelle default,
>>> // which in turn produces extra patch hunks for no reason.
>>>
>>> // Switch unusual Error ** parameter names to errp
>>> // (this is necessary to use ERRP_AUTO_PROPAGATE).
>>> //
>>> // Disable optional_qualifier to skip functions with
>>> // "Error *const *errp" parameter.
>>> //
>>> // Skip functions with "assert(_errp && *_errp)" statement, because
>>> // that signals unusual semantics, and the parameter name may well
>>> // serve a purpose. (like nbd_iter_channel_error()).
>>> //
>>> // Skip util/error.c to not touch, for example, error_propagate() and
>>> // error_propagate_prepend().
>>> @ depends on !(file in "util/error.c") disable optional_qualifier@
>>> identifier fn;
>>> identifier _errp != errp;
>>> @@
>>>
>>>    fn(...,
>>> -   Error **_errp
>>> +   Error **errp
>>>       ,...)
>>>    {
>>> (
>>>        ... when != assert(_errp && *_errp)
>>> &
>>>        <...
>>> -    _errp
>>> +    errp
>>>        ...>
>>> )
>>>    }
>>>
>>> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>> // necessary
>>> //
>>> // Note, that without "when any" the final "..." does not mach
>>> // something matched by previous pattern, i.e. the rule will not match
>>> // double error_prepend in control flow like in
>>> // vfio_set_irq_signaling().
>>> //
>>> // Note, "exists" says that we want apply rule even if it matches not
>>> // on all possible control flows (otherwise, it will not match
>>> // standard pattern when error_propagate() call is in if branch).
>>> @ disable optional_qualifier exists@
>>> identifier fn, local_err;
>>> symbol errp;
>>> @@
>>>
>>>    fn(..., Error **errp, ...)
>>>    {
>>> +   ERRP_AUTO_PROPAGATE();
>>>       ...  when != ERRP_AUTO_PROPAGATE();
>>> (
>>> (
>>>       error_append_hint(errp, ...);
>>> |
>>>       error_prepend(errp, ...);
>>> |
>>>       error_vprepend(errp, ...);
>>> )
>>>       ... when any
>>> |
>>>       Error *local_err = NULL;
>>>       ...
>>> (
>>>       error_propagate_prepend(errp, local_err, ...);
>>> |
>>>       error_propagate(errp, local_err);
>>> )
>>>       ...
>>> )
>>>    }
>>>
>>>
>>> // Match functions with propagation of local error to errp.
>>> // We want to refer these functions in several following rules, but I
>>> // don't know a proper way to inherit a function, not just its name
>>> // (to not match another functions with same name in following rules).
>>> // Not-proper way is as follows: rename errp parameter in functions
>>> // header and match it in following rules. Rename it back after all
>>> // transformations.
>>> //
>>> // The simplest case of propagation scheme is single definition of
>>> // local_err with at most one error_propagate_prepend or
>>> // error_propagate on each control-flow. Still, we want to match more
>>> // complex schemes too. We'll warn them with help of further rules.
>>> @rule1 disable optional_qualifier exists@
>>> identifier fn, local_err;
>>> symbol errp;
>>> @@
>>>
>>>    fn(..., Error **
>>> -    errp
>>> +    ____
>>>       , ...)
>>>    {
>>>        ...
>>>        Error *local_err = NULL;
>>>        ...
>>> (
>>>        error_propagate_prepend(errp, local_err, ...);
>>> |
>>>        error_propagate(errp, local_err);
>>> )
>>>        ...
>>>    }
>>>
>>>
>>> // Warn several Error * definitions.
>>> @check1 disable optional_qualifier exists@
>>> identifier fn, _errp, local_err, local_err2;
>>> position p1, p2;
>>> @@
>>>
>>>    fn(..., Error **_errp, ...)
>>>    {
>>>        ...
>>>        Error *local_err = NULL;@p1
>>>        ... when any
>>>        Error *local_err2 = NULL;@p2
>>>        ... when any
>>>    }
>>>
>>> @ script:python @
>>> fn << check1.fn;
>>> p1 << check1.p1;
>>> p2 << check1.p2;
>>> @@
>>>
>>> print('Warning: function {} has several definitions of '
>>>         'Error * local variable: at {}:{} and then at {}:{}'.format(
>>>             fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>
>>> // Warn several propagations in control flow.
>>> @check2 disable optional_qualifier exists@
>>> identifier fn, _errp;
>>> position p1, p2;
>>> @@
>>>
>>>    fn(..., Error **_errp, ...)
>>>    {
>>>        ...
>>> (
>>>        error_propagate_prepend(_errp, ...);@p1
>>> |
>>>        error_propagate(_errp, ...);@p1
>>> )
>>>        ...
>>> (
>>>        error_propagate_prepend(_errp, ...);@p2
>>> |
>>>        error_propagate(_errp, ...);@p2
>>> )
>>>        ... when any
>>>    }
>>>
>>> @ script:python @
>>> fn << check2.fn;
>>> p1 << check2.p1;
>>> p2 << check2.p2;
>>> @@
>>>
>>> print('Warning: function {} propagates to errp several times in '
>>>         'one control flow: at {}:{} and then at {}:{}'.format(
>>>             fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>
>>> // Convert special case with goto separately.
>>> // I tried merging this into the following rule the obvious way, but
>>> // it made Coccinelle hang on block.c
>>> //
>>> // Note interesting thing: if we don't do it here, and try to fixup
>>> // "out: }" things later after all transformations (the rule will be
>>> // the same, just without error_propagate() call), coccinelle fails to
>>> // match this "out: }".
>>> @ disable optional_qualifier@
>>> identifier fn, rule1.local_err, out;
>>> symbol errp;
>>> @@
>>>
>>>    fn(..., Error ** ____, ...)
>>>    {
>>>        <...
>>> -    goto out;
>>> +    return;
>>>        ...>
>>> - out:
>>> -    error_propagate(errp, local_err);
>>>    }
>>>
>>> // Convert most of local_err related stuff.
>>> //
>>> // Note, that we update everything related to matched by rule1
>>> // function name and local_err name. We may match something not
>>> // related to the pattern matched by rule1. For example, local_err may
>>> // be defined with the same name in different blocks inside one
>>> // function, and in one block follow the propagation pattern and in
>>> // other block doesn't. Or we may have several functions with the same
>>> // name (for different configurations).
>>> //
>>> // Note also that errp-cleaning functions
>>> //   error_free_errp
>>> //   error_report_errp
>>> //   error_reportf_errp
>>> //   warn_report_errp
>>> //   warn_reportf_errp
>>> // are not yet implemented. They must call corresponding Error* -
>>> // freeing function and then set *errp to NULL, to avoid further
>>> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>> // For example, error_free_errp may look like this:
>>> //
>>> //    void error_free_errp(Error **errp)
>>> //    {
>>> //        error_free(*errp);
>>> //        *errp = NULL;
>>> //    }
>>> @ disable optional_qualifier exists@
>>> identifier fn, rule1.local_err;
>>> expression list args;
>>> symbol errp;
>>> @@
>>>
>>>    fn(..., Error ** ____, ...)
>>>    {
>>>        <...
>>> (
>>> -    Error *local_err = NULL;
>>> |
>>>
>>> // Convert error clearing functions
>>> (
>>> -    error_free(local_err);
>>> +    error_free_errp(errp);
>>> |
>>> -    error_report_err(local_err);
>>> +    error_report_errp(errp);
>>> |
>>> -    error_reportf_err(local_err, args);
>>> +    error_reportf_errp(errp, args);
>>> |
>>> -    warn_report_err(local_err);
>>> +    warn_report_errp(errp);
>>> |
>>> -    warn_reportf_err(local_err, args);// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>> //
>> // Copyright (c) 2020 Virtuozzo International GmbH.
>> //
>> // This program is free software; you can redistribute it and/or
>> // modify it under the terms of the GNU General Public License as
>> // published by the Free Software Foundation; either version 2 of the
>> // License, or (at your option) any later version.
>> //
>> // This program is distributed in the hope that it will be useful,
>> // but WITHOUT ANY WARRANTY; without even the implied warranty of
>> // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> // GNU General Public License for more details.
>> //
>> // You should have received a copy of the GNU General Public License
>> // along with this program.  If not, see
>> // <http://www.gnu.org/licenses/>.
>> //
>> // Usage example:
>> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>> //  --macro-file scripts/cocci-macro-file.h --in-place \
>> //  --no-show-diff --max-width 80 FILES...
>> //
>> // Note: --max-width 80 is needed because coccinelle default is less
>> // than 80, and without this parameter coccinelle may reindent some
>> // lines which fit into 80 characters but not to coccinelle default,
>> // which in turn produces extra patch hunks for no reason.
>>
>> // Switch unusual Error ** parameter names to errp
>> // (this is necessary to use ERRP_AUTO_PROPAGATE).
>> //
>> // Disable optional_qualifier to skip functions with
>> // "Error *const *errp" parameter.
>> //
>> // Skip functions with "assert(_errp && *_errp)" statement, because
>> // that signals unusual semantics, and the parameter name may well
>> // serve a purpose. (like nbd_iter_channel_error()).
>> //
>> // Skip util/error.c to not touch, for example, error_propagate() and
>> // error_propagate_prepend().
>> @ depends on !(file in "util/error.c") disable optional_qualifier@
>> identifier fn;
>> identifier _errp != errp;
>> @@
>>
>>   fn(...,
>> -   Error **_errp
>> +   Error **errp
>>      ,...)
>>   {
>> (
>>       ... when != assert(_errp && *_errp)
>> &
>>       <...
>> -    _errp
>> +    errp
>>       ...>
>> )
>>   }
>>
>> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>> // necessary
>> //
>> // Note, that without "when any" the final "..." does not mach
>> // something matched by previous pattern, i.e. the rule will not match
>> // double error_prepend in control flow like in
>> // vfio_set_irq_signaling().
>> //
>> // Note, "exists" says that we want apply rule even if it matches not
>> // on all possible control flows (otherwise, it will not match
>> // standard pattern when error_propagate() call is in if branch).
>> @ disable optional_qualifier exists@
>> identifier fn, local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error **errp, ...)
>>   {
>> +   ERRP_AUTO_PROPAGATE();
>>      ...  when != ERRP_AUTO_PROPAGATE();
>> (
>> (
>>      error_append_hint(errp, ...);
>> |
>>      error_prepend(errp, ...);
>> |
>>      error_vprepend(errp, ...);
>> )
>>      ... when any
>> |
>>      Error *local_err = NULL;
>>      ...
>> (
>>      error_propagate_prepend(errp, local_err, ...);
>> |
>>      error_propagate(errp, local_err);
>> )
>>      ...
>> )
>>   }
>>
>>
>> // Match functions with propagation of local error to errp.
>> // We want to refer these functions in several following rules, but I
>> // don't know a proper way to inherit a function, not just its name
>> // (to not match another functions with same name in following rules).
>> // Not-proper way is as follows: rename errp parameter in functions
>> // header and match it in following rules. Rename it back after all
>> // transformations.
>> //
>> // The simplest case of propagation scheme is single definition of
>> // local_err with at most one error_propagate_prepend or
>> // error_propagate on each control-flow. Still, we want to match more
>> // complex schemes too. We'll warn them with help of further rules.
>> @rule1 disable optional_qualifier exists@
>> identifier fn, local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error **
>> -    errp
>> +    ____
>>      , ...)
>>   {
>>       ...
>>       Error *local_err = NULL;
>>       ...
>> (
>>       error_propagate_prepend(errp, local_err, ...);
>> |
>>       error_propagate(errp, local_err);
>> )
>>       ...
>>   }
>>
>>
>> // Warn several Error * definitions.
>> @check1 disable optional_qualifier exists@
>> identifier fn, _errp, local_err, local_err2;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>>   {
>>       ...
>>       Error *local_err = NULL;@p1
>>       ... when any
>>       Error *local_err2 = NULL;@p2
>>       ... when any
>>   }
>>
>> @ script:python @
>> fn << check1.fn;
>> p1 << check1.p1;
>> p2 << check1.p2;
>> @@
>>
>> print('Warning: function {} has several definitions of '
>>        'Error * local variable: at {}:{} and then at {}:{}'.format(
>>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>
>> // Warn several propagations in control flow.
>> @check2 disable optional_qualifier exists@
>> identifier fn, _errp;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>>   {
>>       ...
>> (
>>       error_propagate_prepend(_errp, ...);@p1
>> |
>>       error_propagate(_errp, ...);@p1
>> )
>>       ...
>> (
>>       error_propagate_prepend(_errp, ...);@p2
>> |
>>       error_propagate(_errp, ...);@p2
>> )
>>       ... when any
>>   }
>>
>> @ script:python @
>> fn << check2.fn;
>> p1 << check2.p1;
>> p2 << check2.p2;
>> @@
>>
>> print('Warning: function {} propagates to errp several times in '
>>        'one control flow: at {}:{} and then at {}:{}'.format(
>>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>
>> // Convert special case with goto separately.
>> // I tried merging this into the following rule the obvious way, but
>> // it made Coccinelle hang on block.c
>> //
>> // Note interesting thing: if we don't do it here, and try to fixup
>> // "out: }" things later after all transformations (the rule will be
>> // the same, just without error_propagate() call), coccinelle fails to
>> // match this "out: }".
>> @ disable optional_qualifier@
>> identifier fn, rule1.local_err, out;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    goto out;
>> +    return;
>>       ...>
>> - out:
>> -    error_propagate(errp, local_err);
>>   }
>>
>> // Convert most of local_err related stuff.
>> //
>> // Note, that we update everything related to matched by rule1
>> // function name and local_err name. We may match something not
>> // related to the pattern matched by rule1. For example, local_err may
>> // be defined with the same name in different blocks inside one
>> // function, and in one block follow the propagation pattern and in
>> // other block doesn't. Or we may have several functions with the same
>> // name (for different configurations).
>> //
>> // Note also that errp-cleaning functions
>> //   error_free_errp
>> //   error_report_errp
>> //   error_reportf_errp
>> //   warn_report_errp
>> //   warn_reportf_errp
>> // are not yet implemented. They must call corresponding Error* -
>> // freeing function and then set *errp to NULL, to avoid further
>> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>> // For example, error_free_errp may look like this:
>> //
>> //    void error_free_errp(Error **errp)
>> //    {
>> //        error_free(*errp);
>> //        *errp = NULL;
>> //    }
>> @ disable optional_qualifier exists@
>> identifier fn, rule1.local_err;
>> expression list args;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> (
>> -    Error *local_err = NULL;
>> |
>>
>> // Convert error clearing functions
>> (
>> -    error_free(local_err);
>> +    error_free_errp(errp);
>> |
>> -    error_report_err(local_err);
>> +    error_report_errp(errp);
>> |
>> -    error_reportf_err(local_err, args);
>> +    error_reportf_errp(errp, args);
>> |
>> -    warn_report_err(local_err);
>> +    warn_report_errp(errp);
>> |
>> -    warn_reportf_err(local_err, args);
>> +    warn_reportf_errp(errp, args);
>> )
>> ?-    local_err = NULL;
>>
>> |
>> -    error_propagate_prepend(errp, local_err, args);
>> +    error_prepend(errp, args);
>> |
>> -    error_propagate(errp, local_err);
>> |
>> -    &local_err
>> +    errp
>> )
>>       ...>
>>   }
>>
>> // Convert remaining local_err usage. For example, different kinds of
>> // error checking in if conditionals. We can't merge this into
>> // previous hunk, as this conflicts with other substitutions in it (at
>> // least with "- local_err = NULL").
>> @ disable optional_qualifier@
>> identifier fn, rule1.local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    local_err
>> +    *errp
>>       ...>
>>   }
>>
>> // Always use the same pattern for checking error
>> @ disable optional_qualifier@
>> identifier fn;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    *errp != NULL
>> +    *errp
>>       ...>
>>   }
>>
>> // Revert temporary ___ identifier.
>> @ disable optional_qualifier@
>> identifier fn;
>> @@
>>
>>   fn(..., Error **
>> -   ____
>> +   errp
>>      , ...)
>>   {
>>       ...
>>   }
>>
>>> +    warn_reportf_errp(errp, args);
>>> )
>>> ?-    local_err = NULL;
>>>
>>> |
>>> -    error_propagate_prepend(errp, local_err, args);
>>> +    error_prepend(errp, args);
>>> |
>>> -    error_propagate(errp, local_err);
>>> |
>>> -    &local_err
>>> +    errp
>>> )
>>>        ...>
>>>    }
>>>
>>> // Convert remaining local_err usage. For example, different kinds of
>>> // error checking in if conditionals. We can't merge this into
>>> // previous hunk, as this conflicts with other substitutions in it (at
>>> // least with "- local_err = NULL").
>>> @ disable optional_qualifier@
>>> identifier fn, rule1.local_err;
>>> symbol errp;
>>> @@
>>>
>>>    fn(..., Error ** ____, ...)
>>>    {
>>>        <...
>>> -    local_err
>>> +    *errp
>>>        ...>
>>>    }
>>>
>>> // Always use the same pattern for checking error
>>> @ disable optional_qualifier@
>>> identifier fn;
>>> symbol errp;
>>> @@
>>>
>>>    fn(..., Error ** ____, ...)
>>>    {
>>>        <...
>>> -    *errp != NULL
>>> +    *errp
>>>        ...>
>>>    }
>>>
>>> // Revert temporary ___ identifier.
>>> @ disable optional_qualifier@
>>> identifier fn;
>>> @@
>>>
>>>    fn(..., Error **
>>> -   ____
>>> +   errp
>>>       , ...)
>>>    {
>>>        ...
>>>    }
>>>
>>
>> OK, I almost OK with it, the only thing I doubt a bit is the following:
>>
>> We want to keep rule1.local_err inheritance to keep connection with
>> local_err definition.
> 
> Yes.
> 
>> Interesting, when we have both rule1.fn and rule1.local_err inherited,
>> do we inherit them in separate (i.e. all possible combinations of fn
>> and local_err symbols from rule1) or do we inherit a pair, i.e. only
>> fn/local_err pairs, found by rule1? If the latter is correct, that
>> with your script we loss this pair inheritance, and go to all possible
>> combinations of fn and local_err from rule1, possibly adding some wrong
>> conversion (OK, you've checked that no such cases in current code tree).
> 
> The chaining "identifier rule1.FOO" is by name.  It's reliable only as
> long as there is exactly one instance of the name.
> 
> We already discussed the case of the function name: if there are two
> instances of foo(), and rule1 matches only one of them, then we
> nevertheless apply the rules chained to rule1 to both.  Because that can
> be wrong, you came up with the ___ trick, which chains reliably.
> 
> The same issue exists with the variable name: if there are two instances
> of @local_err, and rule1 matches only one of them, then we nevertheless
> apply the rules chained to rule1 to both.  Can also be wrong.
> 
> What are the conditions for "wrong"?
> 
> Because the ___ chaining is reliable, we know rule1 matched the
> function, i.e. it has a parameter Error **errp, and it has a automatic
> variable Error *local_err = NULL.
> 
> We're good as long as *all* identifiers @local_err in this function are
> declared that way.  This seems quite likely.  It's not certain, though.
> 
> Since nested declarations of Error ** variables are rare, we can rely on
> review to ensure we transform these functions correctly.
> 
>> So, dropping inheritance in check-rules makes sence, as it may match
>> (and warn) more interesting cases.
>>
>> But for other rules, I'd prefere to be safer, and explictly inherit all
>> actually inherited identifiers..
> 
> I still can't see what chaining by function name in addition to the ___
> chaining buys us.

I'll check this thing soon. And resend today.

> 
>>                                   Still, I feel, we'll never be
>> absolutely safe with coccinelle :)
> 
> Right, although this particular problem is not really Coccinelle's
> fault.  Blindly treating all instances of a certain identifier in a
> certain area the same regardless of how they are bound to declarations
> is fundamentally unreliable, regardless of your actual tooling.
> 

Yes, still interesting, can coccinelle do more smart inheritance to match
exactly same object... I think, I need to CC coccinelle mailing list
to the next version

-- 
Best regards,
Vladimir


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-17  9:29                   ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-17  9:29 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

16.03.2020 11:21, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> On 14.03.2020 00:54, Markus Armbruster wrote:
>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>
>>>> 13.03.2020 18:42, Markus Armbruster wrote:
>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>
>>>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>>>> out now as is.
>>>>>>>
>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>>
>>>>>>>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>>>>>>>> does corresponding changes in code (look for details in
>>>>>>>> include/qapi/error.h)
>>>>>>>>
>>>>>>>> Usage example:
>>>>>>>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>>>>      --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>>>>>>>      --max-width 80 FILES...
>>>>>>>>
>>>>>>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>>>>>>> ---
>>>>>>>>
>>>>>>>> Cc: Eric Blake <eblake@redhat.com>
>>>>>>>> Cc: Kevin Wolf <kwolf@redhat.com>
>>>>>>>> Cc: Max Reitz <mreitz@redhat.com>
>>>>>>>> Cc: Greg Kurz <groug@kaod.org>
>>>>>>>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>>>>>>>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>>>>>>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>>>>>>> Cc: Paul Durrant <paul@xen.org>
>>>>>>>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>>>>>>>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>>>>>>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>>>>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>>>>>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>>>>>>>> Cc: Markus Armbruster <armbru@redhat.com>
>>>>>>>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>>>>>>>> Cc: qemu-devel@nongnu.org
>>>>>>>> Cc: qemu-block@nongnu.org
>>>>>>>> Cc: xen-devel@lists.xenproject.org
>>>>>>>>
>>>>>>>>      scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>>>>>>>      include/qapi/error.h                          |   3 +
>>>>>>>>      MAINTAINERS                                   |   1 +
>>>>>>>>      3 files changed, 331 insertions(+)
>>>>>>>>      create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>>>
>>>>>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>>> new file mode 100644
>>>>>>>> index 0000000000..7dac2dcfa4
>>>>>>>> --- /dev/null
>>>>>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>>> @@ -0,0 +1,327 @@
>>>>>>>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>>>>>>> +//
>>>>>>>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>>>>>>>> +//
>>>>>>>> +// This program is free software; you can redistribute it and/or
>>>>>>>> +// modify it under the terms of the GNU General Public License as
>>>>>>>> +// published by the Free Software Foundation; either version 2 of the
>>>>>>>> +// License, or (at your option) any later version.
>>>>>>>> +//
>>>>>>>> +// This program is distributed in the hope that it will be useful,
>>>>>>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>>>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>>>>>> +// GNU General Public License for more details.
>>>>>>>> +//
>>>>>>>> +// You should have received a copy of the GNU General Public License
>>>>>>>> +// along with this program.  If not, see
>>>>>>>> +// <http://www.gnu.org/licenses/>.
>>>>>>>> +//
>>>>>>>> +// Usage example:
>>>>>>>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>>>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>>>>>>>> +//  --no-show-diff --max-width 80 FILES...
>>>>>>>> +//
>>>>>>>> +// Note: --max-width 80 is needed because coccinelle default is less
>>>>>>>> +// than 80, and without this parameter coccinelle may reindent some
>>>>>>>> +// lines which fit into 80 characters but not to coccinelle default,
>>>>>>>> +// which in turn produces extra patch hunks for no reason.
>>>>>>>
>>>>>>> This is about unwanted reformatting of parameter lists due to the ___
>>>>>>> chaining hack.  --max-width 80 makes that less likely, but not
>>>>>>> impossible.
>>>>>>>
>>>>>>> We can search for unwanted reformatting of parameter lists.  I think
>>>>>>> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
>>>>>>> tree, I get one false positive (not a parameter list), and one hit:
>>>>>>>
>>>>>>>         @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>>>>>>>              }
>>>>>>>          }
>>>>>>>
>>>>>>>         -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>>>>>>>         +void object_apply_global_props(Object *obj, const GPtrArray *props,
>>>>>>>         +                               Error **errp)
>>>>>>>          {
>>>>>>>         +    ERRP_AUTO_PROPAGATE();
>>>>>>>              int i;
>>>>>>>
>>>>>>>              if (!props) {
>>>>>>>
>>>>>>> Reformatting, but not unwanted.
>>>>>>
>>>>>> Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
>>>>>> ERRP_AUTO_PROPAGATE addition even for non-automatic patch.
>>>>>
>>>>> Agree.
>>>>>
>>>>>>>
>>>>>>> The --max-width 80 hack is good enough for me.
>>>>>>>
>>>>>>> It does result in slightly long transformed lines, e.g. this one in
>>>>>>> replication.c:
>>>>>>>
>>>>>>>         @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>>>>>>>                  s->mode = REPLICATION_MODE_PRIMARY;
>>>>>>>                  top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>>>>>>>                  if (top_id) {
>>>>>>>         -            error_setg(&local_err, "The primary side does not support option top-id");
>>>>>>>         +            error_setg(errp, "The primary side does not support option top-id");
>>>>>>>                      goto fail;
>>>>>>>                  }
>>>>>>>              } else if (!strcmp(mode, "secondary")) {
>>>>>>>
>>>>>>> v8 did break this line (that's how I found it).  However, v9 still
>>>>>>> shortens the line, just not below the target.  All your + lines look
>>>>>>> quite unlikely to lengthen lines.  Let's not worry about this.
>>>>>>>
>>>>>>>> +// Switch unusual Error ** parameter names to errp
>>>>>>>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>>>>>>>> +//
>>>>>>>> +// Disable optional_qualifier to skip functions with
>>>>>>>> +// "Error *const *errp" parameter.
>>>>>>>> +//
>>>>>>>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>>>>>>>> +// that signals unusual semantics, and the parameter name may well
>>>>>>>> +// serve a purpose. (like nbd_iter_channel_error()).
>>>>>>>> +//
>>>>>>>> +// Skip util/error.c to not touch, for example, error_propagate() and
>>>>>>>> +// error_propagate_prepend().
>>>>>>>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>>>>>>>> +identifier fn;
>>>>>>>> +identifier _errp != errp;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(...,
>>>>>>>> +-   Error **_errp
>>>>>>>> ++   Error **errp
>>>>>>>> +    ,...)
>>>>>>>> + {
>>>>>>>> +(
>>>>>>>> +     ... when != assert(_errp && *_errp)
>>>>>>>> +&
>>>>>>>> +     <...
>>>>>>>> +-    _errp
>>>>>>>> ++    errp
>>>>>>>> +     ...>
>>>>>>>> +)
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>>>>>>> +// necessary
>>>>>>>> +//
>>>>>>>> +// Note, that without "when any" the final "..." does not mach
>>>>>>>> +// something matched by previous pattern, i.e. the rule will not match
>>>>>>>> +// double error_prepend in control flow like in
>>>>>>>> +// vfio_set_irq_signaling().
>>>>>>>> +//
>>>>>>>> +// Note, "exists" says that we want apply rule even if it matches not
>>>>>>>> +// on all possible control flows (otherwise, it will not match
>>>>>>>> +// standard pattern when error_propagate() call is in if branch).
>>>>>>>> +@ disable optional_qualifier exists@
>>>>>>>> +identifier fn, local_err;
>>>>>>>> +symbol errp;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error **errp, ...)
>>>>>>>> + {
>>>>>>>> ++   ERRP_AUTO_PROPAGATE();
>>>>>>>> +    ...  when != ERRP_AUTO_PROPAGATE();
>>>>>>>> +(
>>>>>>>> +(
>>>>>>>> +    error_append_hint(errp, ...);
>>>>>>>> +|
>>>>>>>> +    error_prepend(errp, ...);
>>>>>>>> +|
>>>>>>>> +    error_vprepend(errp, ...);
>>>>>>>> +)
>>>>>>>> +    ... when any
>>>>>>>> +|
>>>>>>>> +    Error *local_err = NULL;
>>>>>>>> +    ...
>>>>>>>> +(
>>>>>>>> +    error_propagate_prepend(errp, local_err, ...);
>>>>>>>> +|
>>>>>>>> +    error_propagate(errp, local_err);
>>>>>>>> +)
>>>>>>>> +    ...
>>>>>>>> +)
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> +
>>>>>>>> +// Match functions with propagation of local error to errp.
>>>>>>>> +// We want to refer these functions in several following rules, but I
>>>>>>>> +// don't know a proper way to inherit a function, not just its name
>>>>>>>> +// (to not match another functions with same name in following rules).
>>>>>>>> +// Not-proper way is as follows: rename errp parameter in functions
>>>>>>>> +// header and match it in following rules. Rename it back after all
>>>>>>>> +// transformations.
>>>>>>>> +//
>>>>>>>> +// The simplest case of propagation scheme is single definition of
>>>>>>>> +// local_err with at most one error_propagate_prepend or
>>>>>>>> +// error_propagate on each control-flow. Still, we want to match more
>>>>>>>> +// complex schemes too. We'll warn them with help of further rules.
>>>>>>>
>>>>>>> I think what we actually want is to examine instances of this pattern to
>>>>>>> figure out whether and how we want to transform them.  Perhaps:
>>>>>>>
>>>>>>>         // The common case is a single definition of local_err with at most one
>>>>>>>         // error_propagate_prepend() or error_propagate() on each control-flow
>>>>>>>         // path. Instances of this case we convert with this script. Functions
>>>>>>
>>>>>> For me, sounds a bit like "other things we don't convert".
>>>>>> Actually we convert other things too.
>>>>>
>>>>> What other patterns of error propagation do we convert?
>>>>
>>>> Something like in xen_block_device_destroy, why not? Otherwise, it's better to avoid
>>>> matching things like xen_block_device_destroy, not just warn them.
>>>> But I'd prefer to proceed now as is to fit into 5.0.. Too much time already
>>>> spent on this. So, I'm OK with your wording too.
>>>
>>> Let's scratch "Instances of this case we convert with this script."
>>
>> OK
>>
>>>
>>>>>>>         // with multiple definitions or propagates we want to examine
>>>>>>>         // manually. Later rules emit warnings to guide us to them.
>>>>>>>
>>>>>>>> +@rule1 disable optional_qualifier exists@
>>>>>>>> +identifier fn, local_err;
>>>>>>>> +symbol errp;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error **
>>>>>>>> +-    errp
>>>>>>>> ++    ____
>>>>>>>> +    , ...)
>>>>>>>> + {
>>>>>>>> +     ...
>>>>>>>> +     Error *local_err = NULL;
>>>>>>>> +     ...
>>>>>>>> +(
>>>>>>>> +     error_propagate_prepend(errp, local_err, ...);
>>>>>>>> +|
>>>>>>>> +     error_propagate(errp, local_err);
>>>>>>>> +)
>>>>>>>> +     ...
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> +
>>>>>>>> +// Warn several Error * definitions.
>>>>>>>> +@check1 disable optional_qualifier exists@
>>>>>>>> +identifier fn = rule1.fn, local_err, local_err2;
>>>>>>>
>>>>>>> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
>>>>>>> particular reason for the difference?
>>>>>>
>>>>>> I didn't find other way to ref check1.fn in next python rule. It just don't
>>>>>> work if I write here just rule1.fn.
>>>>>>
>>>>>>>
>>>>>>> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
>>>>>>> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
>>>>>>> everywhere, then apply the script to the complete tree, I get the same
>>>>>>> result.
>>>>>>
>>>>>> I think, it's more efficient to reuse names from previous rules. I think it should
>>>>>> work faster (more information, less extra matching).
>>>>>
>>>>> Nope.  With my hacked up script (patch appended) Coccinelle is actually
>>>>> *faster* for the .[ch] touched by this series: with your unmodified
>>>>> script, it takes a bit over 12s on my box, with mine around 7s.  Output
>>>>> is identical.
>>>>>
>>>>> Never guess performance, always measure it :)
>>>>
>>>> Hmm, whole tree results would be better proof
>>>>
>>>>>
>>>>> Two notes on my script:
>>>>>
>>>>> * Unlike yours, it recognizes double-propagation in my test case.
>>>>>      Discussed below.
>>>>>
>>>>> * Its "several definitions of" warning includes positions.  That turned
>>>>>      out to be useless, but I've been too lazy to take that out again.
>>>>>
>>>>>>>
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>> + {
>>>>>>>> +     ...
>>>>>>>> +     Error *local_err = NULL;
>>>>>>>> +     ... when any
>>>>>>>> +     Error *local_err2 = NULL;
>>>>>>>> +     ... when any
>>>>>>>> + }
>>>
>>> This flags functions that have more than one declaration along any
>>> control flow path.  It doesn't flag this one:
>>>
>>>       void gnat(bool b, Error **errp)
>>>       {
>>>           if (b) {
>>>               Error *local_err = NULL;
>>>               foo(arg, &local_err);
>>>               error_propagate(errp, local_err);
>>>           } else {
>>>               Error *local_err = NULL;
>>>               bar(arg, &local_err);
>>>               error_propagate(errp, local_err);
>>>           }
>>>       }
>>>
>>> The Coccinelle script does the right thing for this one regardless.
>>>
>>> I'd prefer to have such functions flagged, too.  But spending time on
>>> convincing Coccinelle to do it for me is not worthwhile; I can simply
>>> search the diff produced by Coccinelle for deletions of declarations
>>> that are not indented exactly four spaces.
>>>
>>> But if we keep this rule, we should adjust its comment
>>>
>>>       // Warn several Error * definitions.
>>>
>>> because it sure suggests it also catches functions like the one I gave
>>> above.
>>
>> Hmm, yes.. We can write "Warn several Error * definitions in _one_
>> control flow (it's not so trivial to match _any_ case with several
>> definitions with coccinelle)" or something like this.
> 
> Ha, "trivial" reminds me of a story.  The math professor, after having
> spent a good chunk of his lecture developing a proof on the blackboad
> turns to the audience to explain why this little part doesn't require
> proof with the words familiar to any math student "and this is trivial."
> Pause, puzzled look...  "Is it trivial?"  Pause, storms out of the
> lecture hall.  A minute or three pass.  Professor comes back beaming,
> "it is trivial!", and proceeds with the proof.
> 
> My point is: it might be trivial with Coccinelle once you know how to do
> it.  We don't.
> 
> Suggest "(can't figure out how to match several definitions regardless
> of control flow)".

Wrong too, because I can:) for example, chaining two rules, catching the
positions of definition and check that they are different.. Or, some
cheating with python script.. That's why I wrote "not trivial",

So, most correct would be "(can't figure out how to simply match several definitions regardless
 > of control flow)".

But again, coccinelle is for matching control flows, so its probably impossible to match such thing..

> 
>>
>>>
>>>>>>>> +
>>>>>>>> +@ script:python @
>>>>>>>> +fn << check1.fn;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> +print('Warning: function {} has several definitions of '
>>>>>>>> +      'Error * local variable'.format(fn))
>>>>>>>> +
>>>>>>>> +// Warn several propagations in control flow.
>>>>>>>> +@check2 disable optional_qualifier exists@
>>>>>>>> +identifier fn = rule1.fn;
>>>>>>>> +symbol errp;
>>>>>>>> +position p1, p2;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>> + {
>>>>>>>> +     ...
>>>>>>>> +(
>>>>>>>> +     error_propagate_prepend(errp, ...);@p1
>>>>>>>> +|
>>>>>>>> +     error_propagate(errp, ...);@p1
>>>>>>>> +)
>>>>>>>> +     ...
>>>>>>>> +(
>>>>>>>> +     error_propagate_prepend(errp, ...);@p2
>>>>>>>> +|
>>>>>>>> +     error_propagate(errp, ...);@p2
>>>>>>>> +)
>>>>>>>> +     ... when any
>>>>>>>> + }
>>>>>>>> +
>>>>>>>
>>>>>>> Hmm, we don't catch the example I used in review of v8:
>>>>>>>
>>>>>>>         extern foo(int, Error **);
>>>>>>>         extern bar(int, Error **);
>>>>>>>
>>>>>>>         void frob(Error **errp)
>>>>>>>         {
>>>>>>>             Error *local_err = NULL;
>>>>>>>             int arg;
>>>>>>>
>>>>>>>             foo(arg, errp);
>>>>>>>             bar(arg, &local_err);
>>>>>>>             error_propagate(errp, local_err);
>>>>>>>             bar(arg + 1, &local_err);
>>>>>>>             error_propagate(errp, local_err);
>>>>>>>         }
>>>>>>>
>>>>>>> I believe this is because rule1 does not match here.
>>>>>>
>>>>>> Yes, rule1 wants at least one code flow with non-doubled propagation.
>>>>>>
>>>>>>>
>>>>>>> If I change the rule as follows, it catches the example:
>>>>>>>
>>>>>>>         @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
>>>>>>>
>>>>>>>          // Warn several propagations in control flow.
>>>>>>>          @check2 disable optional_qualifier exists@
>>>>>>>         -identifier fn = rule1.fn;
>>>>>>>         -symbol errp;
>>>>>>>         +identifier fn, _errp;
>>>>>>>          position p1, p2;
>>>>>>>          @@
>>>>>>>
>>>>>>>         - fn(..., Error ** ____, ...)
>>>>>>>         + fn(..., Error **_errp, ...)
>>>>>>>           {
>>>>>>>               ...
>>>>>>>          (
>>>>>>>         -     error_propagate_prepend(errp, ...);@p1
>>>>>>>         +     error_propagate_prepend(_errp, ...);@p1
>>>>>>>          |
>>>>>>>         -     error_propagate(errp, ...);@p1
>>>>>>>         +     error_propagate(_errp, ...);@p1
>>>>>>>          )
>>>>>>>               ...
>>>>>>>          (
>>>>>>>         -     error_propagate_prepend(errp, ...);@p2
>>>>>>>         +     error_propagate_prepend(_errp, ...);@p2
>>>>>>>          |
>>>>>>>         -     error_propagate(errp, ...);@p2
>>>>>>>         +     error_propagate(_errp, ...);@p2
>>>>>>>          )
>>>>>>>               ... when any
>>>>>>>           }
>>>>>>>
>>>>>>> To my mild surprise, it still doesn't find anything in our tree.
>>>>>>>
>>>>>>> Should we decouple the previous rule from rule1, too?  I tested the
>>>>>>> following on the whole tree:
>>>>>>
>>>>>> I don't think so. Why to check what we are not going to convert? If we want
>>>>>> to check side things, it's better to do it in other coccinelle script..
>>>>>
>>>>> Misunderstanding?  The rules are still chained together via the ___
>>>>> hack, just not via function name, because that's unreliable and
>>>>> redundant.
>>>>
>>>> Strange.. Then, how can it match something not matched by rule1?
>>>
>>> I think I got confused when I wrote the "Misunderstanding?" paragraph.
>>>
>>> Let me try again.
>>>
>>> First rule check2.
>>>
>>> The common case is a at most one propagation to @errp along any control
>>> flow path.  We trust your Coccinelle script to convert that alright.
>>>
>>> Any other propagation to @errp I want to review.  Whether the script
>>> attempts a conversion or not is unimportant, as long as it points me to
>>> the function to review.
>>>
>>> Rule rule1 matches functions that propagate to @errp once along at least
>>> one control flow path.
>>>
>>> Unchained from rule rule1, rule check2 flags any function that
>>> propagates to @errp multiple times along any control flow path.
>>>
>>> Chained to rule1, it flags only functions that also have a path with
>>> single propagation.
>>>
>>> In other words, the unchained rule flags *all* multi-propagations to
>>> @errp, while the chained rule flags only the ones the script attempts to
>>> convert.  The former is much more useful to me.
>>>
>>> Now rule check1.  It flags functions with multiple declarations along
>>> any control flow path.  Again, chaining it to rule1 restricts it to the
>>> functions we attempt to convert.  Makes it less useful to me.  However,
>>> because my desire to review multiple declarations in function we don't
>>> attempt to convert is lower than my desire to review multiple
>>> propagations to @errp in such functions, chaining check1 is tolerable
>>> for me.  But why chain check1 if we don't chain check2?
>>>
>>
>> OK, let's unchain them.
>>
>>>>
>>>>>
>>>>>>>
>>>>>>>         @@ -136,10 +136,10 @@ symbol errp;
>>>>>>>
>>>>>>>          // Warn several Error * definitions.
>>>>>>>          @check1 disable optional_qualifier exists@
>>>>>>>         -identifier fn = rule1.fn, local_err, local_err2;
>>>>>>>         +identifier fn, _errp, local_err, local_err2;
>>>>>>>          @@
>>>>>>>
>>>>>>>         - fn(..., Error ** ____, ...)
>>>>>>>         + fn(..., Error **_errp, ...)
>>>>>>>           {
>>>>>>>               ...
>>>>>>>               Error *local_err = NULL;
>>>>>>>
>>>>>>> Warnings remain unchanged.
>>>>>>>
>>>>>>>> +@ script:python @
>>>>>>>> +fn << check2.fn;
>>>>>>>> +p1 << check2.p1;
>>>>>>>> +p2 << check2.p2;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> +print('Warning: function {} propagates to errp several times in '
>>>>>>>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>>>>>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>>>>>> +
>>>>>>>> +// Convert special case with goto separately.
>>>>>>>> +// I tried merging this into the following rule the obvious way, but
>>>>>>>> +// it made Coccinelle hang on block.c
>>>>>>>> +//
>>>>>>>> +// Note interesting thing: if we don't do it here, and try to fixup
>>>>>>>> +// "out: }" things later after all transformations (the rule will be
>>>>>>>> +// the same, just without error_propagate() call), coccinelle fails to
>>>>>>>> +// match this "out: }".
>>>>>>>> +@ disable optional_qualifier@
>>>>>>>> +identifier rule1.fn, rule1.local_err, out;
>>>>>>>
>>>>>>> As explained above, I doubt the need for rule1.fn.  We do need
>>>>>>> rule1.local_err to avoid unwanted transformations.  More of the same
>>>>>>> below.
>>>>>>
>>>>>> Logically, I want to inherit from rule1. So why not to stress it by inheriting
>>>>>> fn variable? It's just a correct thing to do.
>>>>>> And I hope it helps coccinelle to work more efficiently.
>>>>>>
>>>>>>>
>>>>>>>> +symbol errp;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>> + {
>>>>>>>> +     <...
>>>>>>>> +-    goto out;
>>>>>>>> ++    return;
>>>>>>>> +     ...>
>>>>>>>> +- out:
>>>>>>>> +-    error_propagate(errp, local_err);
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> +// Convert most of local_err related stuff.
>>>>>>>> +//
>>>>>>>> +// Note, that we update everything related to matched by rule1
>>>>>>>> +// function name and local_err name. We may match something not
>>>>>>>> +// related to the pattern matched by rule1. For example, local_err may
>>>>>>>> +// be defined with the same name in different blocks inside one
>>>>>>>> +// function, and in one block follow the propagation pattern and in
>>>>>>>> +// other block doesn't. Or we may have several functions with the same
>>>>>>>> +// name (for different configurations).
>>>>>>>> +//
>>>>>>>> +// Note also that errp-cleaning functions
>>>>>>>> +//   error_free_errp
>>>>>>>> +//   error_report_errp
>>>>>>>> +//   error_reportf_errp
>>>>>>>> +//   warn_report_errp
>>>>>>>> +//   warn_reportf_errp
>>>>>>>> +// are not yet implemented. They must call corresponding Error* -
>>>>>>>> +// freeing function and then set *errp to NULL, to avoid further
>>>>>>>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>>>>>>> +// For example, error_free_errp may look like this:
>>>>>>>> +//
>>>>>>>> +//    void error_free_errp(Error **errp)
>>>>>>>> +//    {
>>>>>>>> +//        error_free(*errp);
>>>>>>>> +//        *errp = NULL;
>>>>>>>> +//    }
>>>>>>>> +@ disable optional_qualifier exists@
>>>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>>>> +expression list args;
>>>>>>>> +symbol errp;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>> + {
>>>>>>>> +     <...
>>>>>>>> +(
>>>>>>>> +-    Error *local_err = NULL;
>>>>>>>> +|
>>>>>>>> +
>>>>>>>> +// Convert error clearing functions
>>>>>>>> +(
>>>>>>>> +-    error_free(local_err);
>>>>>>>> ++    error_free_errp(errp);
>>>>>>>> +|
>>>>>>>> +-    error_report_err(local_err);
>>>>>>>> ++    error_report_errp(errp);
>>>>>>>> +|
>>>>>>>> +-    error_reportf_err(local_err, args);
>>>>>>>> ++    error_reportf_errp(errp, args);
>>>>>>>> +|
>>>>>>>> +-    warn_report_err(local_err);
>>>>>>>> ++    warn_report_errp(errp);
>>>>>>>> +|
>>>>>>>> +-    warn_reportf_err(local_err, args);
>>>>>>>> ++    warn_reportf_errp(errp, args);
>>>>>>>> +)
>>>>>>>> +?-    local_err = NULL;
>>>>>>>> +
>>>>>>>> +|
>>>>>>>> +-    error_propagate_prepend(errp, local_err, args);
>>>>>>>> ++    error_prepend(errp, args);
>>>>>>>> +|
>>>>>>>> +-    error_propagate(errp, local_err);
>>>>>>>> +|
>>>>>>>> +-    &local_err
>>>>>>>> ++    errp
>>>>>>>> +)
>>>>>>>> +     ...>
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> +// Convert remaining local_err usage. For example, different kinds of
>>>>>>>> +// error checking in if conditionals. We can't merge this into
>>>>>>>> +// previous hunk, as this conflicts with other substitutions in it (at
>>>>>>>> +// least with "- local_err = NULL").
>>>>>>>> +@ disable optional_qualifier@
>>>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>>>> +symbol errp;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>> + {
>>>>>>>> +     <...
>>>>>>>> +-    local_err
>>>>>>>> ++    *errp
>>>>>>>> +     ...>
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> +// Always use the same pattern for checking error
>>>>>>>> +@ disable optional_qualifier@
>>>>>>>> +identifier rule1.fn;
>>>>>>>> +symbol errp;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>> + {
>>>>>>>> +     <...
>>>>>>>> +-    *errp != NULL
>>>>>>>> ++    *errp
>>>>>>>> +     ...>
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> +// Revert temporary ___ identifier.
>>>>>>>> +@ disable optional_qualifier@
>>>>>>>> +identifier rule1.fn;
>>>>>>>> +@@
>>>>>>>> +
>>>>>>>> + fn(..., Error **
>>>>>>>> +-   ____
>>>>>>>> ++   errp
>>>>>>>> +    , ...)
>>>>>>>> + {
>>>>>>>> +     ...
>>>>>>>> + }
>>>>>>>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>>>>>>>> index 30140d9bfe..56c133520d 100644
>>>>>>>> --- a/include/qapi/error.h
>>>>>>>> +++ b/include/qapi/error.h
>>>>>>>> @@ -214,6 +214,9 @@
>>>>>>>>       *         }
>>>>>>>>       *         ...
>>>>>>>>       *     }
>>>>>>>> + *
>>>>>>>> + * For mass-conversion use script
>>>>>>>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>>>       */
>>>>>>>>        #ifndef ERROR_H
>>>>>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>>>>>> index 857f969aa1..047f1b9714 100644
>>>>>>>> --- a/MAINTAINERS
>>>>>>>> +++ b/MAINTAINERS
>>>>>>>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>>>>>>>      F: qapi/error.json
>>>>>>>>      F: util/error.c
>>>>>>>>      F: util/qemu-error.c
>>>>>>>> +F: scripts/coccinelle/*err*.cocci
>>>>>>>>        GDB stub
>>>>>>>>      M: Alex Bennée <alex.bennee@linaro.org>
>>>>>>>
>>>>>
>>>>>
>>>>>    From 42a08c529024337d1b859839c9ce7f797f784555 Mon Sep 17 00:00:00 2001
>>>>> From: Markus Armbruster <armbru@redhat.com>
>>>>> Date: Fri, 13 Mar 2020 14:27:57 +0100
>>>>> Subject: [PATCH] fixup! scripts: Coccinelle script to use
>>>>>     ERRP_AUTO_PROPAGATE()
>>>>>
>>>>> ---
>>>>>     scripts/coccinelle/auto-propagated-errp.cocci | 37 ++++++++++---------
>>>>>     1 file changed, 20 insertions(+), 17 deletions(-)
>>>>>
>>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>> index 7dac2dcfa4..43b0b0e63b 100644
>>>>> --- a/scripts/coccinelle/auto-propagated-errp.cocci
>>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>> @@ -136,45 +136,48 @@ symbol errp;
>>>>>       // Warn several Error * definitions.
>>>>>     @check1 disable optional_qualifier exists@
>>>>> -identifier fn = rule1.fn, local_err, local_err2;
>>>>> +identifier fn, _errp, local_err, local_err2;
>>>>> +position p1, p2;
>>>>
>>>>
>>>> Hmm, seems like I forget to define ____ as symbol in my patch
>>>
>>> Coccinelle defaults to symbol.
>>
>> But for errp we saw warnings simetimes.
> 
> I believe it warns when you use rely on the symbol default while also
> using it as something else in other rules.
> 
> Feel free to explicitly define it as symbol.
> 
>>>>>     @@
>>>>>     - fn(..., Error ** ____, ...)
>>>>> + fn(..., Error **_errp, ...)
>>>>
>>>> Ahmm.. it will break compilation?
>>>>
>>>> Or, how will it work when _errp defined as meta variable is only in "+..." line? Should it be symbol instead, or just not defined?
>>>
>>> Misunderstanding?  It's a diff between your .cocci and mine.
>>
>> Oops, yes, sorry. Patches to coccinelle scripts are tricky thing.
>>
>>> My version
>>> is
>>>
>>>       // Warn several Error * definitions.
>>>       @check1 disable optional_qualifier exists@
>>>       identifier fn, _errp, local_err, local_err2;
>>>       position p1, p2;
>>>       @@
>>>
>>>        fn(..., Error **_errp, ...)
>>>        {
>>>            ...
>>>            Error *local_err = NULL;@p1
>>>            ... when any
>>>            Error *local_err2 = NULL;@p2
>>>            ... when any
>>>        }
>>>
>>>       @ script:python @
>>>       fn << check1.fn;
>>>       p1 << check1.p1;
>>>       p2 << check1.p2;
>>>       @@
>>>
>>>>>      {
>>>>>          ...
>>>>> -     Error *local_err = NULL;
>>>>> +     Error *local_err = NULL;@p1
>>>>
>>>> Why to do -/+ here? Nothing changed..
>>>>
>>>>>          ... when any
>>>>> -     Error *local_err2 = NULL;
>>>>> +     Error *local_err2 = NULL;@p2
>>>>>          ... when any
>>>>>      }
>>>>>       @ script:python @
>>>>>     fn << check1.fn;
>>>>> +p1 << check1.p1;
>>>>> +p2 << check1.p2;
>>>>>     @@
>>>>>       print('Warning: function {} has several definitions of '
>>>>> -      'Error * local variable'.format(fn))
>>>>> +      'Error * local variable: at {}:{} and then at {}:{}'.format(
>>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>>>       // Warn several propagations in control flow.
>>>>>     @check2 disable optional_qualifier exists@
>>>>> -identifier fn = rule1.fn;
>>>>> -symbol errp;
>>>>> +identifier fn, _errp;
>>>>>     position p1, p2;
>>>>>     @@
>>>>>     - fn(..., Error ** ____, ...)
>>>>> + fn(..., Error **_errp, ...)
>>>>>      {
>>>>>          ...
>>>>>     (
>>>>> -     error_propagate_prepend(errp, ...);@p1
>>>>> +     error_propagate_prepend(_errp, ...);@p1
>>>>>     |
>>>>> -     error_propagate(errp, ...);@p1
>>>>> +     error_propagate(_errp, ...);@p1
>>>>>     )
>>>>>          ...
>>>>>     (
>>>>> -     error_propagate_prepend(errp, ...);@p2
>>>>> +     error_propagate_prepend(_errp, ...);@p2
>>>>>     |
>>>>> -     error_propagate(errp, ...);@p2
>>>>> +     error_propagate(_errp, ...);@p2
>>>>>     )
>>>>
>>>> You change some occurrences of errp to _errp, but not all. It breaks compilation.
>>>>
>>>>>          ... when any
>>>>>      }
>>>>> @@ -198,7 +201,7 @@ print('Warning: function {} propagates to errp several times in '
>>>>>     // the same, just without error_propagate() call), coccinelle fails to
>>>>>     // match this "out: }".
>>>>>     @ disable optional_qualifier@
>>>>> -identifier rule1.fn, rule1.local_err, out;
>>>>> +identifier fn, rule1.local_err, out;
>>>>
>>>> Hmm. If it improves performance it is strange.. But I can live with this change.
>>>>
>>>>>     symbol errp;
>>>>>     @@
>>>>>     @@ -239,7 +242,7 @@ symbol errp;
>>>>>     //        *errp = NULL;
>>>>>     //    }
>>>>>     @ disable optional_qualifier exists@
>>>>> -identifier rule1.fn, rule1.local_err;
>>>>> +identifier fn, rule1.local_err;
>>>>>     expression list args;
>>>>>     symbol errp;
>>>>>     @@
>>>>> @@ -287,7 +290,7 @@ symbol errp;
>>>>>     // previous hunk, as this conflicts with other substitutions in it (at
>>>>>     // least with "- local_err = NULL").
>>>>>     @ disable optional_qualifier@
>>>>> -identifier rule1.fn, rule1.local_err;
>>>>> +identifier fn, rule1.local_err;
>>>>>     symbol errp;
>>>>>     @@
>>>>>     @@ -301,7 +304,7 @@ symbol errp;
>>>>>       // Always use the same pattern for checking error
>>>>>     @ disable optional_qualifier@
>>>>> -identifier rule1.fn;
>>>>> +identifier fn;
>>>>>     symbol errp;
>>>>>     @@
>>>>>     @@ -315,7 +318,7 @@ symbol errp;
>>>>>       // Revert temporary ___ identifier.
>>>>>     @ disable optional_qualifier@
>>>>> -identifier rule1.fn;
>>>>> +identifier fn;
>>>>>     @@
>>>>>        fn(..., Error **
>>>>>
>>>
>>> I append my hacked up version of auto-propagated-errp.cocci.  It
>>> produces the same patch as yours for the complete tree.
>>>
>>>
>>>
>>> // Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>> //
>>> // Copyright (c) 2020 Virtuozzo International GmbH.
>>> //
>>> // This program is free software; you can redistribute it and/or
>>> // modify it under the terms of the GNU General Public License as
>>> // published by the Free Software Foundation; either version 2 of the
>>> // License, or (at your option) any later version.
>>> //
>>> // This program is distributed in the hope that it will be useful,
>>> // but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> // GNU General Public License for more details.
>>> //
>>> // You should have received a copy of the GNU General Public License
>>> // along with this program.  If not, see
>>> // <http://www.gnu.org/licenses/>.
>>> //
>>> // Usage example:
>>> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>> //  --macro-file scripts/cocci-macro-file.h --in-place \
>>> //  --no-show-diff --max-width 80 FILES...
>>> //
>>> // Note: --max-width 80 is needed because coccinelle default is less
>>> // than 80, and without this parameter coccinelle may reindent some
>>> // lines which fit into 80 characters but not to coccinelle default,
>>> // which in turn produces extra patch hunks for no reason.
>>>
>>> // Switch unusual Error ** parameter names to errp
>>> // (this is necessary to use ERRP_AUTO_PROPAGATE).
>>> //
>>> // Disable optional_qualifier to skip functions with
>>> // "Error *const *errp" parameter.
>>> //
>>> // Skip functions with "assert(_errp && *_errp)" statement, because
>>> // that signals unusual semantics, and the parameter name may well
>>> // serve a purpose. (like nbd_iter_channel_error()).
>>> //
>>> // Skip util/error.c to not touch, for example, error_propagate() and
>>> // error_propagate_prepend().
>>> @ depends on !(file in "util/error.c") disable optional_qualifier@
>>> identifier fn;
>>> identifier _errp != errp;
>>> @@
>>>
>>>    fn(...,
>>> -   Error **_errp
>>> +   Error **errp
>>>       ,...)
>>>    {
>>> (
>>>        ... when != assert(_errp && *_errp)
>>> &
>>>        <...
>>> -    _errp
>>> +    errp
>>>        ...>
>>> )
>>>    }
>>>
>>> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>> // necessary
>>> //
>>> // Note, that without "when any" the final "..." does not mach
>>> // something matched by previous pattern, i.e. the rule will not match
>>> // double error_prepend in control flow like in
>>> // vfio_set_irq_signaling().
>>> //
>>> // Note, "exists" says that we want apply rule even if it matches not
>>> // on all possible control flows (otherwise, it will not match
>>> // standard pattern when error_propagate() call is in if branch).
>>> @ disable optional_qualifier exists@
>>> identifier fn, local_err;
>>> symbol errp;
>>> @@
>>>
>>>    fn(..., Error **errp, ...)
>>>    {
>>> +   ERRP_AUTO_PROPAGATE();
>>>       ...  when != ERRP_AUTO_PROPAGATE();
>>> (
>>> (
>>>       error_append_hint(errp, ...);
>>> |
>>>       error_prepend(errp, ...);
>>> |
>>>       error_vprepend(errp, ...);
>>> )
>>>       ... when any
>>> |
>>>       Error *local_err = NULL;
>>>       ...
>>> (
>>>       error_propagate_prepend(errp, local_err, ...);
>>> |
>>>       error_propagate(errp, local_err);
>>> )
>>>       ...
>>> )
>>>    }
>>>
>>>
>>> // Match functions with propagation of local error to errp.
>>> // We want to refer these functions in several following rules, but I
>>> // don't know a proper way to inherit a function, not just its name
>>> // (to not match another functions with same name in following rules).
>>> // Not-proper way is as follows: rename errp parameter in functions
>>> // header and match it in following rules. Rename it back after all
>>> // transformations.
>>> //
>>> // The simplest case of propagation scheme is single definition of
>>> // local_err with at most one error_propagate_prepend or
>>> // error_propagate on each control-flow. Still, we want to match more
>>> // complex schemes too. We'll warn them with help of further rules.
>>> @rule1 disable optional_qualifier exists@
>>> identifier fn, local_err;
>>> symbol errp;
>>> @@
>>>
>>>    fn(..., Error **
>>> -    errp
>>> +    ____
>>>       , ...)
>>>    {
>>>        ...
>>>        Error *local_err = NULL;
>>>        ...
>>> (
>>>        error_propagate_prepend(errp, local_err, ...);
>>> |
>>>        error_propagate(errp, local_err);
>>> )
>>>        ...
>>>    }
>>>
>>>
>>> // Warn several Error * definitions.
>>> @check1 disable optional_qualifier exists@
>>> identifier fn, _errp, local_err, local_err2;
>>> position p1, p2;
>>> @@
>>>
>>>    fn(..., Error **_errp, ...)
>>>    {
>>>        ...
>>>        Error *local_err = NULL;@p1
>>>        ... when any
>>>        Error *local_err2 = NULL;@p2
>>>        ... when any
>>>    }
>>>
>>> @ script:python @
>>> fn << check1.fn;
>>> p1 << check1.p1;
>>> p2 << check1.p2;
>>> @@
>>>
>>> print('Warning: function {} has several definitions of '
>>>         'Error * local variable: at {}:{} and then at {}:{}'.format(
>>>             fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>
>>> // Warn several propagations in control flow.
>>> @check2 disable optional_qualifier exists@
>>> identifier fn, _errp;
>>> position p1, p2;
>>> @@
>>>
>>>    fn(..., Error **_errp, ...)
>>>    {
>>>        ...
>>> (
>>>        error_propagate_prepend(_errp, ...);@p1
>>> |
>>>        error_propagate(_errp, ...);@p1
>>> )
>>>        ...
>>> (
>>>        error_propagate_prepend(_errp, ...);@p2
>>> |
>>>        error_propagate(_errp, ...);@p2
>>> )
>>>        ... when any
>>>    }
>>>
>>> @ script:python @
>>> fn << check2.fn;
>>> p1 << check2.p1;
>>> p2 << check2.p2;
>>> @@
>>>
>>> print('Warning: function {} propagates to errp several times in '
>>>         'one control flow: at {}:{} and then at {}:{}'.format(
>>>             fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>
>>> // Convert special case with goto separately.
>>> // I tried merging this into the following rule the obvious way, but
>>> // it made Coccinelle hang on block.c
>>> //
>>> // Note interesting thing: if we don't do it here, and try to fixup
>>> // "out: }" things later after all transformations (the rule will be
>>> // the same, just without error_propagate() call), coccinelle fails to
>>> // match this "out: }".
>>> @ disable optional_qualifier@
>>> identifier fn, rule1.local_err, out;
>>> symbol errp;
>>> @@
>>>
>>>    fn(..., Error ** ____, ...)
>>>    {
>>>        <...
>>> -    goto out;
>>> +    return;
>>>        ...>
>>> - out:
>>> -    error_propagate(errp, local_err);
>>>    }
>>>
>>> // Convert most of local_err related stuff.
>>> //
>>> // Note, that we update everything related to matched by rule1
>>> // function name and local_err name. We may match something not
>>> // related to the pattern matched by rule1. For example, local_err may
>>> // be defined with the same name in different blocks inside one
>>> // function, and in one block follow the propagation pattern and in
>>> // other block doesn't. Or we may have several functions with the same
>>> // name (for different configurations).
>>> //
>>> // Note also that errp-cleaning functions
>>> //   error_free_errp
>>> //   error_report_errp
>>> //   error_reportf_errp
>>> //   warn_report_errp
>>> //   warn_reportf_errp
>>> // are not yet implemented. They must call corresponding Error* -
>>> // freeing function and then set *errp to NULL, to avoid further
>>> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>> // For example, error_free_errp may look like this:
>>> //
>>> //    void error_free_errp(Error **errp)
>>> //    {
>>> //        error_free(*errp);
>>> //        *errp = NULL;
>>> //    }
>>> @ disable optional_qualifier exists@
>>> identifier fn, rule1.local_err;
>>> expression list args;
>>> symbol errp;
>>> @@
>>>
>>>    fn(..., Error ** ____, ...)
>>>    {
>>>        <...
>>> (
>>> -    Error *local_err = NULL;
>>> |
>>>
>>> // Convert error clearing functions
>>> (
>>> -    error_free(local_err);
>>> +    error_free_errp(errp);
>>> |
>>> -    error_report_err(local_err);
>>> +    error_report_errp(errp);
>>> |
>>> -    error_reportf_err(local_err, args);
>>> +    error_reportf_errp(errp, args);
>>> |
>>> -    warn_report_err(local_err);
>>> +    warn_report_errp(errp);
>>> |
>>> -    warn_reportf_err(local_err, args);// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>> //
>> // Copyright (c) 2020 Virtuozzo International GmbH.
>> //
>> // This program is free software; you can redistribute it and/or
>> // modify it under the terms of the GNU General Public License as
>> // published by the Free Software Foundation; either version 2 of the
>> // License, or (at your option) any later version.
>> //
>> // This program is distributed in the hope that it will be useful,
>> // but WITHOUT ANY WARRANTY; without even the implied warranty of
>> // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> // GNU General Public License for more details.
>> //
>> // You should have received a copy of the GNU General Public License
>> // along with this program.  If not, see
>> // <http://www.gnu.org/licenses/>.
>> //
>> // Usage example:
>> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>> //  --macro-file scripts/cocci-macro-file.h --in-place \
>> //  --no-show-diff --max-width 80 FILES...
>> //
>> // Note: --max-width 80 is needed because coccinelle default is less
>> // than 80, and without this parameter coccinelle may reindent some
>> // lines which fit into 80 characters but not to coccinelle default,
>> // which in turn produces extra patch hunks for no reason.
>>
>> // Switch unusual Error ** parameter names to errp
>> // (this is necessary to use ERRP_AUTO_PROPAGATE).
>> //
>> // Disable optional_qualifier to skip functions with
>> // "Error *const *errp" parameter.
>> //
>> // Skip functions with "assert(_errp && *_errp)" statement, because
>> // that signals unusual semantics, and the parameter name may well
>> // serve a purpose. (like nbd_iter_channel_error()).
>> //
>> // Skip util/error.c to not touch, for example, error_propagate() and
>> // error_propagate_prepend().
>> @ depends on !(file in "util/error.c") disable optional_qualifier@
>> identifier fn;
>> identifier _errp != errp;
>> @@
>>
>>   fn(...,
>> -   Error **_errp
>> +   Error **errp
>>      ,...)
>>   {
>> (
>>       ... when != assert(_errp && *_errp)
>> &
>>       <...
>> -    _errp
>> +    errp
>>       ...>
>> )
>>   }
>>
>> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>> // necessary
>> //
>> // Note, that without "when any" the final "..." does not mach
>> // something matched by previous pattern, i.e. the rule will not match
>> // double error_prepend in control flow like in
>> // vfio_set_irq_signaling().
>> //
>> // Note, "exists" says that we want apply rule even if it matches not
>> // on all possible control flows (otherwise, it will not match
>> // standard pattern when error_propagate() call is in if branch).
>> @ disable optional_qualifier exists@
>> identifier fn, local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error **errp, ...)
>>   {
>> +   ERRP_AUTO_PROPAGATE();
>>      ...  when != ERRP_AUTO_PROPAGATE();
>> (
>> (
>>      error_append_hint(errp, ...);
>> |
>>      error_prepend(errp, ...);
>> |
>>      error_vprepend(errp, ...);
>> )
>>      ... when any
>> |
>>      Error *local_err = NULL;
>>      ...
>> (
>>      error_propagate_prepend(errp, local_err, ...);
>> |
>>      error_propagate(errp, local_err);
>> )
>>      ...
>> )
>>   }
>>
>>
>> // Match functions with propagation of local error to errp.
>> // We want to refer these functions in several following rules, but I
>> // don't know a proper way to inherit a function, not just its name
>> // (to not match another functions with same name in following rules).
>> // Not-proper way is as follows: rename errp parameter in functions
>> // header and match it in following rules. Rename it back after all
>> // transformations.
>> //
>> // The simplest case of propagation scheme is single definition of
>> // local_err with at most one error_propagate_prepend or
>> // error_propagate on each control-flow. Still, we want to match more
>> // complex schemes too. We'll warn them with help of further rules.
>> @rule1 disable optional_qualifier exists@
>> identifier fn, local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error **
>> -    errp
>> +    ____
>>      , ...)
>>   {
>>       ...
>>       Error *local_err = NULL;
>>       ...
>> (
>>       error_propagate_prepend(errp, local_err, ...);
>> |
>>       error_propagate(errp, local_err);
>> )
>>       ...
>>   }
>>
>>
>> // Warn several Error * definitions.
>> @check1 disable optional_qualifier exists@
>> identifier fn, _errp, local_err, local_err2;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>>   {
>>       ...
>>       Error *local_err = NULL;@p1
>>       ... when any
>>       Error *local_err2 = NULL;@p2
>>       ... when any
>>   }
>>
>> @ script:python @
>> fn << check1.fn;
>> p1 << check1.p1;
>> p2 << check1.p2;
>> @@
>>
>> print('Warning: function {} has several definitions of '
>>        'Error * local variable: at {}:{} and then at {}:{}'.format(
>>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>
>> // Warn several propagations in control flow.
>> @check2 disable optional_qualifier exists@
>> identifier fn, _errp;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>>   {
>>       ...
>> (
>>       error_propagate_prepend(_errp, ...);@p1
>> |
>>       error_propagate(_errp, ...);@p1
>> )
>>       ...
>> (
>>       error_propagate_prepend(_errp, ...);@p2
>> |
>>       error_propagate(_errp, ...);@p2
>> )
>>       ... when any
>>   }
>>
>> @ script:python @
>> fn << check2.fn;
>> p1 << check2.p1;
>> p2 << check2.p2;
>> @@
>>
>> print('Warning: function {} propagates to errp several times in '
>>        'one control flow: at {}:{} and then at {}:{}'.format(
>>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>
>> // Convert special case with goto separately.
>> // I tried merging this into the following rule the obvious way, but
>> // it made Coccinelle hang on block.c
>> //
>> // Note interesting thing: if we don't do it here, and try to fixup
>> // "out: }" things later after all transformations (the rule will be
>> // the same, just without error_propagate() call), coccinelle fails to
>> // match this "out: }".
>> @ disable optional_qualifier@
>> identifier fn, rule1.local_err, out;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    goto out;
>> +    return;
>>       ...>
>> - out:
>> -    error_propagate(errp, local_err);
>>   }
>>
>> // Convert most of local_err related stuff.
>> //
>> // Note, that we update everything related to matched by rule1
>> // function name and local_err name. We may match something not
>> // related to the pattern matched by rule1. For example, local_err may
>> // be defined with the same name in different blocks inside one
>> // function, and in one block follow the propagation pattern and in
>> // other block doesn't. Or we may have several functions with the same
>> // name (for different configurations).
>> //
>> // Note also that errp-cleaning functions
>> //   error_free_errp
>> //   error_report_errp
>> //   error_reportf_errp
>> //   warn_report_errp
>> //   warn_reportf_errp
>> // are not yet implemented. They must call corresponding Error* -
>> // freeing function and then set *errp to NULL, to avoid further
>> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>> // For example, error_free_errp may look like this:
>> //
>> //    void error_free_errp(Error **errp)
>> //    {
>> //        error_free(*errp);
>> //        *errp = NULL;
>> //    }
>> @ disable optional_qualifier exists@
>> identifier fn, rule1.local_err;
>> expression list args;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> (
>> -    Error *local_err = NULL;
>> |
>>
>> // Convert error clearing functions
>> (
>> -    error_free(local_err);
>> +    error_free_errp(errp);
>> |
>> -    error_report_err(local_err);
>> +    error_report_errp(errp);
>> |
>> -    error_reportf_err(local_err, args);
>> +    error_reportf_errp(errp, args);
>> |
>> -    warn_report_err(local_err);
>> +    warn_report_errp(errp);
>> |
>> -    warn_reportf_err(local_err, args);
>> +    warn_reportf_errp(errp, args);
>> )
>> ?-    local_err = NULL;
>>
>> |
>> -    error_propagate_prepend(errp, local_err, args);
>> +    error_prepend(errp, args);
>> |
>> -    error_propagate(errp, local_err);
>> |
>> -    &local_err
>> +    errp
>> )
>>       ...>
>>   }
>>
>> // Convert remaining local_err usage. For example, different kinds of
>> // error checking in if conditionals. We can't merge this into
>> // previous hunk, as this conflicts with other substitutions in it (at
>> // least with "- local_err = NULL").
>> @ disable optional_qualifier@
>> identifier fn, rule1.local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    local_err
>> +    *errp
>>       ...>
>>   }
>>
>> // Always use the same pattern for checking error
>> @ disable optional_qualifier@
>> identifier fn;
>> symbol errp;
>> @@
>>
>>   fn(..., Error ** ____, ...)
>>   {
>>       <...
>> -    *errp != NULL
>> +    *errp
>>       ...>
>>   }
>>
>> // Revert temporary ___ identifier.
>> @ disable optional_qualifier@
>> identifier fn;
>> @@
>>
>>   fn(..., Error **
>> -   ____
>> +   errp
>>      , ...)
>>   {
>>       ...
>>   }
>>
>>> +    warn_reportf_errp(errp, args);
>>> )
>>> ?-    local_err = NULL;
>>>
>>> |
>>> -    error_propagate_prepend(errp, local_err, args);
>>> +    error_prepend(errp, args);
>>> |
>>> -    error_propagate(errp, local_err);
>>> |
>>> -    &local_err
>>> +    errp
>>> )
>>>        ...>
>>>    }
>>>
>>> // Convert remaining local_err usage. For example, different kinds of
>>> // error checking in if conditionals. We can't merge this into
>>> // previous hunk, as this conflicts with other substitutions in it (at
>>> // least with "- local_err = NULL").
>>> @ disable optional_qualifier@
>>> identifier fn, rule1.local_err;
>>> symbol errp;
>>> @@
>>>
>>>    fn(..., Error ** ____, ...)
>>>    {
>>>        <...
>>> -    local_err
>>> +    *errp
>>>        ...>
>>>    }
>>>
>>> // Always use the same pattern for checking error
>>> @ disable optional_qualifier@
>>> identifier fn;
>>> symbol errp;
>>> @@
>>>
>>>    fn(..., Error ** ____, ...)
>>>    {
>>>        <...
>>> -    *errp != NULL
>>> +    *errp
>>>        ...>
>>>    }
>>>
>>> // Revert temporary ___ identifier.
>>> @ disable optional_qualifier@
>>> identifier fn;
>>> @@
>>>
>>>    fn(..., Error **
>>> -   ____
>>> +   errp
>>>       , ...)
>>>    {
>>>        ...
>>>    }
>>>
>>
>> OK, I almost OK with it, the only thing I doubt a bit is the following:
>>
>> We want to keep rule1.local_err inheritance to keep connection with
>> local_err definition.
> 
> Yes.
> 
>> Interesting, when we have both rule1.fn and rule1.local_err inherited,
>> do we inherit them in separate (i.e. all possible combinations of fn
>> and local_err symbols from rule1) or do we inherit a pair, i.e. only
>> fn/local_err pairs, found by rule1? If the latter is correct, that
>> with your script we loss this pair inheritance, and go to all possible
>> combinations of fn and local_err from rule1, possibly adding some wrong
>> conversion (OK, you've checked that no such cases in current code tree).
> 
> The chaining "identifier rule1.FOO" is by name.  It's reliable only as
> long as there is exactly one instance of the name.
> 
> We already discussed the case of the function name: if there are two
> instances of foo(), and rule1 matches only one of them, then we
> nevertheless apply the rules chained to rule1 to both.  Because that can
> be wrong, you came up with the ___ trick, which chains reliably.
> 
> The same issue exists with the variable name: if there are two instances
> of @local_err, and rule1 matches only one of them, then we nevertheless
> apply the rules chained to rule1 to both.  Can also be wrong.
> 
> What are the conditions for "wrong"?
> 
> Because the ___ chaining is reliable, we know rule1 matched the
> function, i.e. it has a parameter Error **errp, and it has a automatic
> variable Error *local_err = NULL.
> 
> We're good as long as *all* identifiers @local_err in this function are
> declared that way.  This seems quite likely.  It's not certain, though.
> 
> Since nested declarations of Error ** variables are rare, we can rely on
> review to ensure we transform these functions correctly.
> 
>> So, dropping inheritance in check-rules makes sence, as it may match
>> (and warn) more interesting cases.
>>
>> But for other rules, I'd prefere to be safer, and explictly inherit all
>> actually inherited identifiers..
> 
> I still can't see what chaining by function name in addition to the ___
> chaining buys us.

I'll check this thing soon. And resend today.

> 
>>                                   Still, I feel, we'll never be
>> absolutely safe with coccinelle :)
> 
> Right, although this particular problem is not really Coccinelle's
> fault.  Blindly treating all instances of a certain identifier in a
> certain area the same regardless of how they are bound to declarations
> is fundamentally unreliable, regardless of your actual tooling.
> 

Yes, still interesting, can coccinelle do more smart inheritance to match
exactly same object... I think, I need to CC coccinelle mailing list
to the next version

-- 
Best regards,
Vladimir

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-17  9:29                   ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-17 10:39                     ` Markus Armbruster
  -1 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-17 10:39 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Laszlo Ersek, Christian Schoenebeck, Michael Roth, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 16.03.2020 11:21, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>
>>> On 14.03.2020 00:54, Markus Armbruster wrote:
>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>
>>>>> 13.03.2020 18:42, Markus Armbruster wrote:
>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>
>>>>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>>>>> out now as is.
>>>>>>>>
>>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
[...]
>>>>>>>>> +@@
>>>>>>>>> +
>>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>>> + {
>>>>>>>>> +     ...
>>>>>>>>> +     Error *local_err = NULL;
>>>>>>>>> +     ... when any
>>>>>>>>> +     Error *local_err2 = NULL;
>>>>>>>>> +     ... when any
>>>>>>>>> + }
>>>>
>>>> This flags functions that have more than one declaration along any
>>>> control flow path.  It doesn't flag this one:
>>>>
>>>>       void gnat(bool b, Error **errp)
>>>>       {
>>>>           if (b) {
>>>>               Error *local_err = NULL;
>>>>               foo(arg, &local_err);
>>>>               error_propagate(errp, local_err);
>>>>           } else {
>>>>               Error *local_err = NULL;
>>>>               bar(arg, &local_err);
>>>>               error_propagate(errp, local_err);
>>>>           }
>>>>       }
>>>>
>>>> The Coccinelle script does the right thing for this one regardless.
>>>>
>>>> I'd prefer to have such functions flagged, too.  But spending time on
>>>> convincing Coccinelle to do it for me is not worthwhile; I can simply
>>>> search the diff produced by Coccinelle for deletions of declarations
>>>> that are not indented exactly four spaces.
>>>>
>>>> But if we keep this rule, we should adjust its comment
>>>>
>>>>       // Warn several Error * definitions.
>>>>
>>>> because it sure suggests it also catches functions like the one I gave
>>>> above.
>>>
>>> Hmm, yes.. We can write "Warn several Error * definitions in _one_
>>> control flow (it's not so trivial to match _any_ case with several
>>> definitions with coccinelle)" or something like this.
>>
>> Ha, "trivial" reminds me of a story.  The math professor, after having
>> spent a good chunk of his lecture developing a proof on the blackboad
>> turns to the audience to explain why this little part doesn't require
>> proof with the words familiar to any math student "and this is trivial."
>> Pause, puzzled look...  "Is it trivial?"  Pause, storms out of the
>> lecture hall.  A minute or three pass.  Professor comes back beaming,
>> "it is trivial!", and proceeds with the proof.
>>
>> My point is: it might be trivial with Coccinelle once you know how to do
>> it.  We don't.
>>
>> Suggest "(can't figure out how to match several definitions regardless
>> of control flow)".
>
> Wrong too, because I can:) for example, chaining two rules, catching the
> positions of definition and check that they are different.. Or, some
> cheating with python script.. That's why I wrote "not trivial",
>
> So, most correct would be "(can't figure out how to simply match several definitions regardless
>> of control flow)".

Works for me.

> But again, coccinelle is for matching control flows, so its probably impossible to match such thing..
[...]
>>> OK, I almost OK with it, the only thing I doubt a bit is the following:
>>>
>>> We want to keep rule1.local_err inheritance to keep connection with
>>> local_err definition.
>>
>> Yes.
>>
>>> Interesting, when we have both rule1.fn and rule1.local_err inherited,
>>> do we inherit them in separate (i.e. all possible combinations of fn
>>> and local_err symbols from rule1) or do we inherit a pair, i.e. only
>>> fn/local_err pairs, found by rule1? If the latter is correct, that
>>> with your script we loss this pair inheritance, and go to all possible
>>> combinations of fn and local_err from rule1, possibly adding some wrong
>>> conversion (OK, you've checked that no such cases in current code tree).
>>
>> The chaining "identifier rule1.FOO" is by name.  It's reliable only as
>> long as there is exactly one instance of the name.
>>
>> We already discussed the case of the function name: if there are two
>> instances of foo(), and rule1 matches only one of them, then we
>> nevertheless apply the rules chained to rule1 to both.  Because that can
>> be wrong, you came up with the ___ trick, which chains reliably.
>>
>> The same issue exists with the variable name: if there are two instances
>> of @local_err, and rule1 matches only one of them, then we nevertheless
>> apply the rules chained to rule1 to both.  Can also be wrong.
>>
>> What are the conditions for "wrong"?
>>
>> Because the ___ chaining is reliable, we know rule1 matched the
>> function, i.e. it has a parameter Error **errp, and it has a automatic
>> variable Error *local_err = NULL.
>>
>> We're good as long as *all* identifiers @local_err in this function are
>> declared that way.  This seems quite likely.  It's not certain, though.
>>
>> Since nested declarations of Error ** variables are rare, we can rely on
>> review to ensure we transform these functions correctly.
>>
>>> So, dropping inheritance in check-rules makes sence, as it may match
>>> (and warn) more interesting cases.
>>>
>>> But for other rules, I'd prefere to be safer, and explictly inherit all
>>> actually inherited identifiers..
>>
>> I still can't see what chaining by function name in addition to the ___
>> chaining buys us.
>
> I'll check this thing soon. And resend today.
>
>>
>>>                                   Still, I feel, we'll never be
>>> absolutely safe with coccinelle :)
>>
>> Right, although this particular problem is not really Coccinelle's
>> fault.  Blindly treating all instances of a certain identifier in a
>> certain area the same regardless of how they are bound to declarations
>> is fundamentally unreliable, regardless of your actual tooling.
>>
>
> Yes, still interesting, can coccinelle do more smart inheritance to match
> exactly same object... I think, I need to CC coccinelle mailing list
> to the next version

I'love to get taught how to chain reliably.



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-17 10:39                     ` Markus Armbruster
  0 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-17 10:39 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Laszlo Ersek, Christian Schoenebeck, Michael Roth, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 16.03.2020 11:21, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>
>>> On 14.03.2020 00:54, Markus Armbruster wrote:
>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>
>>>>> 13.03.2020 18:42, Markus Armbruster wrote:
>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>
>>>>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>>>>> out now as is.
>>>>>>>>
>>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
[...]
>>>>>>>>> +@@
>>>>>>>>> +
>>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>>> + {
>>>>>>>>> +     ...
>>>>>>>>> +     Error *local_err = NULL;
>>>>>>>>> +     ... when any
>>>>>>>>> +     Error *local_err2 = NULL;
>>>>>>>>> +     ... when any
>>>>>>>>> + }
>>>>
>>>> This flags functions that have more than one declaration along any
>>>> control flow path.  It doesn't flag this one:
>>>>
>>>>       void gnat(bool b, Error **errp)
>>>>       {
>>>>           if (b) {
>>>>               Error *local_err = NULL;
>>>>               foo(arg, &local_err);
>>>>               error_propagate(errp, local_err);
>>>>           } else {
>>>>               Error *local_err = NULL;
>>>>               bar(arg, &local_err);
>>>>               error_propagate(errp, local_err);
>>>>           }
>>>>       }
>>>>
>>>> The Coccinelle script does the right thing for this one regardless.
>>>>
>>>> I'd prefer to have such functions flagged, too.  But spending time on
>>>> convincing Coccinelle to do it for me is not worthwhile; I can simply
>>>> search the diff produced by Coccinelle for deletions of declarations
>>>> that are not indented exactly four spaces.
>>>>
>>>> But if we keep this rule, we should adjust its comment
>>>>
>>>>       // Warn several Error * definitions.
>>>>
>>>> because it sure suggests it also catches functions like the one I gave
>>>> above.
>>>
>>> Hmm, yes.. We can write "Warn several Error * definitions in _one_
>>> control flow (it's not so trivial to match _any_ case with several
>>> definitions with coccinelle)" or something like this.
>>
>> Ha, "trivial" reminds me of a story.  The math professor, after having
>> spent a good chunk of his lecture developing a proof on the blackboad
>> turns to the audience to explain why this little part doesn't require
>> proof with the words familiar to any math student "and this is trivial."
>> Pause, puzzled look...  "Is it trivial?"  Pause, storms out of the
>> lecture hall.  A minute or three pass.  Professor comes back beaming,
>> "it is trivial!", and proceeds with the proof.
>>
>> My point is: it might be trivial with Coccinelle once you know how to do
>> it.  We don't.
>>
>> Suggest "(can't figure out how to match several definitions regardless
>> of control flow)".
>
> Wrong too, because I can:) for example, chaining two rules, catching the
> positions of definition and check that they are different.. Or, some
> cheating with python script.. That's why I wrote "not trivial",
>
> So, most correct would be "(can't figure out how to simply match several definitions regardless
>> of control flow)".

Works for me.

> But again, coccinelle is for matching control flows, so its probably impossible to match such thing..
[...]
>>> OK, I almost OK with it, the only thing I doubt a bit is the following:
>>>
>>> We want to keep rule1.local_err inheritance to keep connection with
>>> local_err definition.
>>
>> Yes.
>>
>>> Interesting, when we have both rule1.fn and rule1.local_err inherited,
>>> do we inherit them in separate (i.e. all possible combinations of fn
>>> and local_err symbols from rule1) or do we inherit a pair, i.e. only
>>> fn/local_err pairs, found by rule1? If the latter is correct, that
>>> with your script we loss this pair inheritance, and go to all possible
>>> combinations of fn and local_err from rule1, possibly adding some wrong
>>> conversion (OK, you've checked that no such cases in current code tree).
>>
>> The chaining "identifier rule1.FOO" is by name.  It's reliable only as
>> long as there is exactly one instance of the name.
>>
>> We already discussed the case of the function name: if there are two
>> instances of foo(), and rule1 matches only one of them, then we
>> nevertheless apply the rules chained to rule1 to both.  Because that can
>> be wrong, you came up with the ___ trick, which chains reliably.
>>
>> The same issue exists with the variable name: if there are two instances
>> of @local_err, and rule1 matches only one of them, then we nevertheless
>> apply the rules chained to rule1 to both.  Can also be wrong.
>>
>> What are the conditions for "wrong"?
>>
>> Because the ___ chaining is reliable, we know rule1 matched the
>> function, i.e. it has a parameter Error **errp, and it has a automatic
>> variable Error *local_err = NULL.
>>
>> We're good as long as *all* identifiers @local_err in this function are
>> declared that way.  This seems quite likely.  It's not certain, though.
>>
>> Since nested declarations of Error ** variables are rare, we can rely on
>> review to ensure we transform these functions correctly.
>>
>>> So, dropping inheritance in check-rules makes sence, as it may match
>>> (and warn) more interesting cases.
>>>
>>> But for other rules, I'd prefere to be safer, and explictly inherit all
>>> actually inherited identifiers..
>>
>> I still can't see what chaining by function name in addition to the ___
>> chaining buys us.
>
> I'll check this thing soon. And resend today.
>
>>
>>>                                   Still, I feel, we'll never be
>>> absolutely safe with coccinelle :)
>>
>> Right, although this particular problem is not really Coccinelle's
>> fault.  Blindly treating all instances of a certain identifier in a
>> certain area the same regardless of how they are bound to declarations
>> is fundamentally unreliable, regardless of your actual tooling.
>>
>
> Yes, still interesting, can coccinelle do more smart inheritance to match
> exactly same object... I think, I need to CC coccinelle mailing list
> to the next version

I'love to get taught how to chain reliably.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-17 10:39                     ` [Xen-devel] " Markus Armbruster
@ 2020-03-17 11:35                       ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-17 11:35 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Laszlo Ersek, Christian Schoenebeck, Michael Roth, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

17.03.2020 13:39, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> 16.03.2020 11:21, Markus Armbruster wrote:
>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>
>>>> On 14.03.2020 00:54, Markus Armbruster wrote:
>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>
>>>>>> 13.03.2020 18:42, Markus Armbruster wrote:
>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>>
>>>>>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>>>>>> out now as is.
>>>>>>>>>
>>>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> [...]
>>>>>>>>>> +@@
>>>>>>>>>> +
>>>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>>>> + {
>>>>>>>>>> +     ...
>>>>>>>>>> +     Error *local_err = NULL;
>>>>>>>>>> +     ... when any
>>>>>>>>>> +     Error *local_err2 = NULL;
>>>>>>>>>> +     ... when any
>>>>>>>>>> + }
>>>>>
>>>>> This flags functions that have more than one declaration along any
>>>>> control flow path.  It doesn't flag this one:
>>>>>
>>>>>        void gnat(bool b, Error **errp)
>>>>>        {
>>>>>            if (b) {
>>>>>                Error *local_err = NULL;
>>>>>                foo(arg, &local_err);
>>>>>                error_propagate(errp, local_err);
>>>>>            } else {
>>>>>                Error *local_err = NULL;
>>>>>                bar(arg, &local_err);
>>>>>                error_propagate(errp, local_err);
>>>>>            }
>>>>>        }
>>>>>
>>>>> The Coccinelle script does the right thing for this one regardless.
>>>>>
>>>>> I'd prefer to have such functions flagged, too.  But spending time on
>>>>> convincing Coccinelle to do it for me is not worthwhile; I can simply
>>>>> search the diff produced by Coccinelle for deletions of declarations
>>>>> that are not indented exactly four spaces.
>>>>>
>>>>> But if we keep this rule, we should adjust its comment
>>>>>
>>>>>        // Warn several Error * definitions.
>>>>>
>>>>> because it sure suggests it also catches functions like the one I gave
>>>>> above.
>>>>
>>>> Hmm, yes.. We can write "Warn several Error * definitions in _one_
>>>> control flow (it's not so trivial to match _any_ case with several
>>>> definitions with coccinelle)" or something like this.
>>>
>>> Ha, "trivial" reminds me of a story.  The math professor, after having
>>> spent a good chunk of his lecture developing a proof on the blackboad
>>> turns to the audience to explain why this little part doesn't require
>>> proof with the words familiar to any math student "and this is trivial."
>>> Pause, puzzled look...  "Is it trivial?"  Pause, storms out of the
>>> lecture hall.  A minute or three pass.  Professor comes back beaming,
>>> "it is trivial!", and proceeds with the proof.
>>>
>>> My point is: it might be trivial with Coccinelle once you know how to do
>>> it.  We don't.
>>>
>>> Suggest "(can't figure out how to match several definitions regardless
>>> of control flow)".
>>
>> Wrong too, because I can:) for example, chaining two rules, catching the
>> positions of definition and check that they are different.. Or, some
>> cheating with python script.. That's why I wrote "not trivial",
>>
>> So, most correct would be "(can't figure out how to simply match several definitions regardless
>>> of control flow)".
> 
> Works for me.
> 
>> But again, coccinelle is for matching control flows, so its probably impossible to match such thing..
> [...]
>>>> OK, I almost OK with it, the only thing I doubt a bit is the following:
>>>>
>>>> We want to keep rule1.local_err inheritance to keep connection with
>>>> local_err definition.
>>>
>>> Yes.
>>>
>>>> Interesting, when we have both rule1.fn and rule1.local_err inherited,
>>>> do we inherit them in separate (i.e. all possible combinations of fn
>>>> and local_err symbols from rule1) or do we inherit a pair, i.e. only
>>>> fn/local_err pairs, found by rule1? If the latter is correct, that
>>>> with your script we loss this pair inheritance, and go to all possible
>>>> combinations of fn and local_err from rule1, possibly adding some wrong
>>>> conversion (OK, you've checked that no such cases in current code tree).
>>>
>>> The chaining "identifier rule1.FOO" is by name.  It's reliable only as
>>> long as there is exactly one instance of the name.
>>>
>>> We already discussed the case of the function name: if there are two
>>> instances of foo(), and rule1 matches only one of them, then we
>>> nevertheless apply the rules chained to rule1 to both.  Because that can
>>> be wrong, you came up with the ___ trick, which chains reliably.
>>>
>>> The same issue exists with the variable name: if there are two instances
>>> of @local_err, and rule1 matches only one of them, then we nevertheless
>>> apply the rules chained to rule1 to both.  Can also be wrong.
>>>
>>> What are the conditions for "wrong"?
>>>
>>> Because the ___ chaining is reliable, we know rule1 matched the
>>> function, i.e. it has a parameter Error **errp, and it has a automatic
>>> variable Error *local_err = NULL.
>>>
>>> We're good as long as *all* identifiers @local_err in this function are
>>> declared that way.  This seems quite likely.  It's not certain, though.
>>>
>>> Since nested declarations of Error ** variables are rare, we can rely on
>>> review to ensure we transform these functions correctly.
>>>
>>>> So, dropping inheritance in check-rules makes sence, as it may match
>>>> (and warn) more interesting cases.
>>>>
>>>> But for other rules, I'd prefere to be safer, and explictly inherit all
>>>> actually inherited identifiers..
>>>
>>> I still can't see what chaining by function name in addition to the ___
>>> chaining buys us.
>>
>> I'll check this thing soon. And resend today.

Checked.

Yes, it inherits pair of fn and local_err, and it definitely makes sense. It more stable.

Consider the following example:

# cat a.c
int f1(Error **errp)
{
     Error *err1 = NULL;
     int err2 = 0;

     error_propagate(errp, err1);

     return err2;
}

int f2(Error **errp)
{
     Error *err2 = NULL;
     int err1 = 0;

     error_propagate(errp, err2);

     return err1;
}


My script works correct and produces this change:
--- a.c
+++ /tmp/cocci-output-1753-10842a-a.c
@@ -1,19 +1,15 @@
  int f1(Error **errp)
  {
-    Error *err1 = NULL;
+    ERRP_AUTO_PROPAGATE();
      int err2 = 0;

-    error_propagate(errp, err1);
-
      return err2;
  }

  int f2(Error **errp)
  {
-    Error *err2 = NULL;
+    ERRP_AUTO_PROPAGATE();
      int err1 = 0;

-    error_propagate(errp, err2);
-
      return err1;
  }


But yours script is caught:
--- a.c
+++ /tmp/cocci-output-1814-b9b681-a.c
@@ -1,19 +1,15 @@
  int f1(Error **errp)
  {
-    Error *err1 = NULL;
+    ERRP_AUTO_PROPAGATE();
      int err2 = 0;

-    error_propagate(errp, err1);
-
-    return err2;
+    return *errp;
  }

  int f2(Error **errp)
  {
-    Error *err2 = NULL;
+    ERRP_AUTO_PROPAGATE();
      int err1 = 0;

-    error_propagate(errp, err2);
-
-    return err1;
+    return *errp;
  }


- see, it touches err1, which is unrelated to Error in f2. Hmm, interesting that it doesn't want to convert err1 declaration:)

- this is because relation between local_err and fn is lost.

So, understanding that there no such cases in the whole tree, and even if your patch works faster on the whole tree, I still don't want to drop inheritance, because it's just a correct thing to do. Yes, we've added ____ helper. It helps to avoid some problems. Pair-inheritance helps to avoid another problems. I understand, that there still may other, not-covered problems, but better to be as safe as possible. And inheritance here is native and correct thing to do, even with our ____ additional helper. What do you think?

>>
>>>
>>>>                                    Still, I feel, we'll never be
>>>> absolutely safe with coccinelle :)
>>>
>>> Right, although this particular problem is not really Coccinelle's
>>> fault.  Blindly treating all instances of a certain identifier in a
>>> certain area the same regardless of how they are bound to declarations
>>> is fundamentally unreliable, regardless of your actual tooling.
>>>
>>
>> Yes, still interesting, can coccinelle do more smart inheritance to match
>> exactly same object... I think, I need to CC coccinelle mailing list
>> to the next version
> 
> I'love to get taught how to chain reliably.
> 


-- 
Best regards,
Vladimir


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-17 11:35                       ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-17 11:35 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Laszlo Ersek, Christian Schoenebeck, Michael Roth, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

17.03.2020 13:39, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> 16.03.2020 11:21, Markus Armbruster wrote:
>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>
>>>> On 14.03.2020 00:54, Markus Armbruster wrote:
>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>
>>>>>> 13.03.2020 18:42, Markus Armbruster wrote:
>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>>
>>>>>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>>>>>> out now as is.
>>>>>>>>>
>>>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> [...]
>>>>>>>>>> +@@
>>>>>>>>>> +
>>>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>>>> + {
>>>>>>>>>> +     ...
>>>>>>>>>> +     Error *local_err = NULL;
>>>>>>>>>> +     ... when any
>>>>>>>>>> +     Error *local_err2 = NULL;
>>>>>>>>>> +     ... when any
>>>>>>>>>> + }
>>>>>
>>>>> This flags functions that have more than one declaration along any
>>>>> control flow path.  It doesn't flag this one:
>>>>>
>>>>>        void gnat(bool b, Error **errp)
>>>>>        {
>>>>>            if (b) {
>>>>>                Error *local_err = NULL;
>>>>>                foo(arg, &local_err);
>>>>>                error_propagate(errp, local_err);
>>>>>            } else {
>>>>>                Error *local_err = NULL;
>>>>>                bar(arg, &local_err);
>>>>>                error_propagate(errp, local_err);
>>>>>            }
>>>>>        }
>>>>>
>>>>> The Coccinelle script does the right thing for this one regardless.
>>>>>
>>>>> I'd prefer to have such functions flagged, too.  But spending time on
>>>>> convincing Coccinelle to do it for me is not worthwhile; I can simply
>>>>> search the diff produced by Coccinelle for deletions of declarations
>>>>> that are not indented exactly four spaces.
>>>>>
>>>>> But if we keep this rule, we should adjust its comment
>>>>>
>>>>>        // Warn several Error * definitions.
>>>>>
>>>>> because it sure suggests it also catches functions like the one I gave
>>>>> above.
>>>>
>>>> Hmm, yes.. We can write "Warn several Error * definitions in _one_
>>>> control flow (it's not so trivial to match _any_ case with several
>>>> definitions with coccinelle)" or something like this.
>>>
>>> Ha, "trivial" reminds me of a story.  The math professor, after having
>>> spent a good chunk of his lecture developing a proof on the blackboad
>>> turns to the audience to explain why this little part doesn't require
>>> proof with the words familiar to any math student "and this is trivial."
>>> Pause, puzzled look...  "Is it trivial?"  Pause, storms out of the
>>> lecture hall.  A minute or three pass.  Professor comes back beaming,
>>> "it is trivial!", and proceeds with the proof.
>>>
>>> My point is: it might be trivial with Coccinelle once you know how to do
>>> it.  We don't.
>>>
>>> Suggest "(can't figure out how to match several definitions regardless
>>> of control flow)".
>>
>> Wrong too, because I can:) for example, chaining two rules, catching the
>> positions of definition and check that they are different.. Or, some
>> cheating with python script.. That's why I wrote "not trivial",
>>
>> So, most correct would be "(can't figure out how to simply match several definitions regardless
>>> of control flow)".
> 
> Works for me.
> 
>> But again, coccinelle is for matching control flows, so its probably impossible to match such thing..
> [...]
>>>> OK, I almost OK with it, the only thing I doubt a bit is the following:
>>>>
>>>> We want to keep rule1.local_err inheritance to keep connection with
>>>> local_err definition.
>>>
>>> Yes.
>>>
>>>> Interesting, when we have both rule1.fn and rule1.local_err inherited,
>>>> do we inherit them in separate (i.e. all possible combinations of fn
>>>> and local_err symbols from rule1) or do we inherit a pair, i.e. only
>>>> fn/local_err pairs, found by rule1? If the latter is correct, that
>>>> with your script we loss this pair inheritance, and go to all possible
>>>> combinations of fn and local_err from rule1, possibly adding some wrong
>>>> conversion (OK, you've checked that no such cases in current code tree).
>>>
>>> The chaining "identifier rule1.FOO" is by name.  It's reliable only as
>>> long as there is exactly one instance of the name.
>>>
>>> We already discussed the case of the function name: if there are two
>>> instances of foo(), and rule1 matches only one of them, then we
>>> nevertheless apply the rules chained to rule1 to both.  Because that can
>>> be wrong, you came up with the ___ trick, which chains reliably.
>>>
>>> The same issue exists with the variable name: if there are two instances
>>> of @local_err, and rule1 matches only one of them, then we nevertheless
>>> apply the rules chained to rule1 to both.  Can also be wrong.
>>>
>>> What are the conditions for "wrong"?
>>>
>>> Because the ___ chaining is reliable, we know rule1 matched the
>>> function, i.e. it has a parameter Error **errp, and it has a automatic
>>> variable Error *local_err = NULL.
>>>
>>> We're good as long as *all* identifiers @local_err in this function are
>>> declared that way.  This seems quite likely.  It's not certain, though.
>>>
>>> Since nested declarations of Error ** variables are rare, we can rely on
>>> review to ensure we transform these functions correctly.
>>>
>>>> So, dropping inheritance in check-rules makes sence, as it may match
>>>> (and warn) more interesting cases.
>>>>
>>>> But for other rules, I'd prefere to be safer, and explictly inherit all
>>>> actually inherited identifiers..
>>>
>>> I still can't see what chaining by function name in addition to the ___
>>> chaining buys us.
>>
>> I'll check this thing soon. And resend today.

Checked.

Yes, it inherits pair of fn and local_err, and it definitely makes sense. It more stable.

Consider the following example:

# cat a.c
int f1(Error **errp)
{
     Error *err1 = NULL;
     int err2 = 0;

     error_propagate(errp, err1);

     return err2;
}

int f2(Error **errp)
{
     Error *err2 = NULL;
     int err1 = 0;

     error_propagate(errp, err2);

     return err1;
}


My script works correct and produces this change:
--- a.c
+++ /tmp/cocci-output-1753-10842a-a.c
@@ -1,19 +1,15 @@
  int f1(Error **errp)
  {
-    Error *err1 = NULL;
+    ERRP_AUTO_PROPAGATE();
      int err2 = 0;

-    error_propagate(errp, err1);
-
      return err2;
  }

  int f2(Error **errp)
  {
-    Error *err2 = NULL;
+    ERRP_AUTO_PROPAGATE();
      int err1 = 0;

-    error_propagate(errp, err2);
-
      return err1;
  }


But yours script is caught:
--- a.c
+++ /tmp/cocci-output-1814-b9b681-a.c
@@ -1,19 +1,15 @@
  int f1(Error **errp)
  {
-    Error *err1 = NULL;
+    ERRP_AUTO_PROPAGATE();
      int err2 = 0;

-    error_propagate(errp, err1);
-
-    return err2;
+    return *errp;
  }

  int f2(Error **errp)
  {
-    Error *err2 = NULL;
+    ERRP_AUTO_PROPAGATE();
      int err1 = 0;

-    error_propagate(errp, err2);
-
-    return err1;
+    return *errp;
  }


- see, it touches err1, which is unrelated to Error in f2. Hmm, interesting that it doesn't want to convert err1 declaration:)

- this is because relation between local_err and fn is lost.

So, understanding that there no such cases in the whole tree, and even if your patch works faster on the whole tree, I still don't want to drop inheritance, because it's just a correct thing to do. Yes, we've added ____ helper. It helps to avoid some problems. Pair-inheritance helps to avoid another problems. I understand, that there still may other, not-covered problems, but better to be as safe as possible. And inheritance here is native and correct thing to do, even with our ____ additional helper. What do you think?

>>
>>>
>>>>                                    Still, I feel, we'll never be
>>>> absolutely safe with coccinelle :)
>>>
>>> Right, although this particular problem is not really Coccinelle's
>>> fault.  Blindly treating all instances of a certain identifier in a
>>> certain area the same regardless of how they are bound to declarations
>>> is fundamentally unreliable, regardless of your actual tooling.
>>>
>>
>> Yes, still interesting, can coccinelle do more smart inheritance to match
>> exactly same object... I think, I need to CC coccinelle mailing list
>> to the next version
> 
> I'love to get taught how to chain reliably.
> 


-- 
Best regards,
Vladimir

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-13 21:54             ` [Xen-devel] " Markus Armbruster
@ 2020-03-17 13:54               ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-17 13:54 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Laszlo Ersek, Christian Schoenebeck, Michael Roth, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

14.03.2020 0:54, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> 13.03.2020 18:42, Markus Armbruster wrote:
>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>
>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>> out now as is.
>>>>>
>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>
>>>>>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>>>>>> does corresponding changes in code (look for details in
>>>>>> include/qapi/error.h)
>>>>>>
>>>>>> Usage example:
>>>>>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>>     --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>>>>>     --max-width 80 FILES...
>>>>>>
>>>>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>>>>> ---
>>>>>>
>>>>>> Cc: Eric Blake <eblake@redhat.com>
>>>>>> Cc: Kevin Wolf <kwolf@redhat.com>
>>>>>> Cc: Max Reitz <mreitz@redhat.com>
>>>>>> Cc: Greg Kurz <groug@kaod.org>
>>>>>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>>>>>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>>>>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>>>>> Cc: Paul Durrant <paul@xen.org>
>>>>>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>>>>>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>>>>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>>>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>>>>>> Cc: Markus Armbruster <armbru@redhat.com>
>>>>>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>>>>>> Cc: qemu-devel@nongnu.org
>>>>>> Cc: qemu-block@nongnu.org
>>>>>> Cc: xen-devel@lists.xenproject.org
>>>>>>
>>>>>>     scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>>>>>     include/qapi/error.h                          |   3 +
>>>>>>     MAINTAINERS                                   |   1 +
>>>>>>     3 files changed, 331 insertions(+)
>>>>>>     create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>
>>>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>> new file mode 100644
>>>>>> index 0000000000..7dac2dcfa4
>>>>>> --- /dev/null
>>>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>> @@ -0,0 +1,327 @@
>>>>>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>>>>> +//
>>>>>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>>>>>> +//
>>>>>> +// This program is free software; you can redistribute it and/or
>>>>>> +// modify it under the terms of the GNU General Public License as
>>>>>> +// published by the Free Software Foundation; either version 2 of the
>>>>>> +// License, or (at your option) any later version.
>>>>>> +//
>>>>>> +// This program is distributed in the hope that it will be useful,
>>>>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>>>> +// GNU General Public License for more details.
>>>>>> +//
>>>>>> +// You should have received a copy of the GNU General Public License
>>>>>> +// along with this program.  If not, see
>>>>>> +// <http://www.gnu.org/licenses/>.
>>>>>> +//
>>>>>> +// Usage example:
>>>>>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>>>>>> +//  --no-show-diff --max-width 80 FILES...
>>>>>> +//
>>>>>> +// Note: --max-width 80 is needed because coccinelle default is less
>>>>>> +// than 80, and without this parameter coccinelle may reindent some
>>>>>> +// lines which fit into 80 characters but not to coccinelle default,
>>>>>> +// which in turn produces extra patch hunks for no reason.
>>>>>
>>>>> This is about unwanted reformatting of parameter lists due to the ___
>>>>> chaining hack.  --max-width 80 makes that less likely, but not
>>>>> impossible.
>>>>>
>>>>> We can search for unwanted reformatting of parameter lists.  I think
>>>>> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
>>>>> tree, I get one false positive (not a parameter list), and one hit:
>>>>>
>>>>>        @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>>>>>             }
>>>>>         }
>>>>>
>>>>>        -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>>>>>        +void object_apply_global_props(Object *obj, const GPtrArray *props,
>>>>>        +                               Error **errp)
>>>>>         {
>>>>>        +    ERRP_AUTO_PROPAGATE();
>>>>>             int i;
>>>>>
>>>>>             if (!props) {
>>>>>
>>>>> Reformatting, but not unwanted.
>>>>
>>>> Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
>>>> ERRP_AUTO_PROPAGATE addition even for non-automatic patch.
>>>
>>> Agree.
>>>
>>>>>
>>>>> The --max-width 80 hack is good enough for me.
>>>>>
>>>>> It does result in slightly long transformed lines, e.g. this one in
>>>>> replication.c:
>>>>>
>>>>>        @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>>>>>                 s->mode = REPLICATION_MODE_PRIMARY;
>>>>>                 top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>>>>>                 if (top_id) {
>>>>>        -            error_setg(&local_err, "The primary side does not support option top-id");
>>>>>        +            error_setg(errp, "The primary side does not support option top-id");
>>>>>                     goto fail;
>>>>>                 }
>>>>>             } else if (!strcmp(mode, "secondary")) {
>>>>>
>>>>> v8 did break this line (that's how I found it).  However, v9 still
>>>>> shortens the line, just not below the target.  All your + lines look
>>>>> quite unlikely to lengthen lines.  Let's not worry about this.
>>>>>
>>>>>> +// Switch unusual Error ** parameter names to errp
>>>>>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>>>>>> +//
>>>>>> +// Disable optional_qualifier to skip functions with
>>>>>> +// "Error *const *errp" parameter.
>>>>>> +//
>>>>>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>>>>>> +// that signals unusual semantics, and the parameter name may well
>>>>>> +// serve a purpose. (like nbd_iter_channel_error()).
>>>>>> +//
>>>>>> +// Skip util/error.c to not touch, for example, error_propagate() and
>>>>>> +// error_propagate_prepend().
>>>>>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>>>>>> +identifier fn;
>>>>>> +identifier _errp != errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(...,
>>>>>> +-   Error **_errp
>>>>>> ++   Error **errp
>>>>>> +    ,...)
>>>>>> + {
>>>>>> +(
>>>>>> +     ... when != assert(_errp && *_errp)
>>>>>> +&
>>>>>> +     <...
>>>>>> +-    _errp
>>>>>> ++    errp
>>>>>> +     ...>
>>>>>> +)
>>>>>> + }
>>>>>> +
>>>>>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>>>>> +// necessary
>>>>>> +//
>>>>>> +// Note, that without "when any" the final "..." does not mach
>>>>>> +// something matched by previous pattern, i.e. the rule will not match
>>>>>> +// double error_prepend in control flow like in
>>>>>> +// vfio_set_irq_signaling().
>>>>>> +//
>>>>>> +// Note, "exists" says that we want apply rule even if it matches not
>>>>>> +// on all possible control flows (otherwise, it will not match
>>>>>> +// standard pattern when error_propagate() call is in if branch).
>>>>>> +@ disable optional_qualifier exists@
>>>>>> +identifier fn, local_err;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error **errp, ...)
>>>>>> + {
>>>>>> ++   ERRP_AUTO_PROPAGATE();
>>>>>> +    ...  when != ERRP_AUTO_PROPAGATE();
>>>>>> +(
>>>>>> +(
>>>>>> +    error_append_hint(errp, ...);
>>>>>> +|
>>>>>> +    error_prepend(errp, ...);
>>>>>> +|
>>>>>> +    error_vprepend(errp, ...);
>>>>>> +)
>>>>>> +    ... when any
>>>>>> +|
>>>>>> +    Error *local_err = NULL;
>>>>>> +    ...
>>>>>> +(
>>>>>> +    error_propagate_prepend(errp, local_err, ...);
>>>>>> +|
>>>>>> +    error_propagate(errp, local_err);
>>>>>> +)
>>>>>> +    ...
>>>>>> +)
>>>>>> + }
>>>>>> +
>>>>>> +
>>>>>> +// Match functions with propagation of local error to errp.
>>>>>> +// We want to refer these functions in several following rules, but I
>>>>>> +// don't know a proper way to inherit a function, not just its name
>>>>>> +// (to not match another functions with same name in following rules).
>>>>>> +// Not-proper way is as follows: rename errp parameter in functions
>>>>>> +// header and match it in following rules. Rename it back after all
>>>>>> +// transformations.
>>>>>> +//
>>>>>> +// The simplest case of propagation scheme is single definition of
>>>>>> +// local_err with at most one error_propagate_prepend or
>>>>>> +// error_propagate on each control-flow. Still, we want to match more
>>>>>> +// complex schemes too. We'll warn them with help of further rules.
>>>>>
>>>>> I think what we actually want is to examine instances of this pattern to
>>>>> figure out whether and how we want to transform them.  Perhaps:
>>>>>
>>>>>        // The common case is a single definition of local_err with at most one
>>>>>        // error_propagate_prepend() or error_propagate() on each control-flow
>>>>>        // path. Instances of this case we convert with this script. Functions
>>>>
>>>> For me, sounds a bit like "other things we don't convert".
>>>> Actually we convert other things too.
>>>
>>> What other patterns of error propagation do we convert?
>>
>> Something like in xen_block_device_destroy, why not? Otherwise, it's better to avoid
>> matching things like xen_block_device_destroy, not just warn them.
>> But I'd prefer to proceed now as is to fit into 5.0.. Too much time already
>> spent on this. So, I'm OK with your wording too.
> 
> Let's scratch "Instances of this case we convert with this script."
> 
>>>>>        // with multiple definitions or propagates we want to examine
>>>>>        // manually. Later rules emit warnings to guide us to them.
>>>>>
>>>>>> +@rule1 disable optional_qualifier exists@
>>>>>> +identifier fn, local_err;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error **
>>>>>> +-    errp
>>>>>> ++    ____
>>>>>> +    , ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> +     Error *local_err = NULL;
>>>>>> +     ...
>>>>>> +(
>>>>>> +     error_propagate_prepend(errp, local_err, ...);
>>>>>> +|
>>>>>> +     error_propagate(errp, local_err);
>>>>>> +)
>>>>>> +     ...
>>>>>> + }
>>>>>> +
>>>>>> +
>>>>>> +// Warn several Error * definitions.
>>>>>> +@check1 disable optional_qualifier exists@
>>>>>> +identifier fn = rule1.fn, local_err, local_err2;
>>>>>
>>>>> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
>>>>> particular reason for the difference?
>>>>
>>>> I didn't find other way to ref check1.fn in next python rule. It just don't
>>>> work if I write here just rule1.fn.
>>>>
>>>>>
>>>>> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
>>>>> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
>>>>> everywhere, then apply the script to the complete tree, I get the same
>>>>> result.
>>>>
>>>> I think, it's more efficient to reuse names from previous rules. I think it should
>>>> work faster (more information, less extra matching).
>>>
>>> Nope.  With my hacked up script (patch appended) Coccinelle is actually
>>> *faster* for the .[ch] touched by this series: with your unmodified
>>> script, it takes a bit over 12s on my box, with mine around 7s.  Output
>>> is identical.
>>>
>>> Never guess performance, always measure it :)
>>
>> Hmm, whole tree results would be better proof
>>
>>>
>>> Two notes on my script:
>>>
>>> * Unlike yours, it recognizes double-propagation in my test case.
>>>     Discussed below.
>>>
>>> * Its "several definitions of" warning includes positions.  That turned
>>>     out to be useless, but I've been too lazy to take that out again.
>>>
>>>>>
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> +     Error *local_err = NULL;
>>>>>> +     ... when any
>>>>>> +     Error *local_err2 = NULL;
>>>>>> +     ... when any
>>>>>> + }
> 
> This flags functions that have more than one declaration along any
> control flow path.  It doesn't flag this one:
> 
>      void gnat(bool b, Error **errp)
>      {
>          if (b) {
>              Error *local_err = NULL;
>              foo(arg, &local_err);
>              error_propagate(errp, local_err);
>          } else {
>              Error *local_err = NULL;
>              bar(arg, &local_err);
>              error_propagate(errp, local_err);
>          }
>      }
> 
> The Coccinelle script does the right thing for this one regardless.
> 
> I'd prefer to have such functions flagged, too.  But spending time on
> convincing Coccinelle to do it for me is not worthwhile; I can simply
> search the diff produced by Coccinelle for deletions of declarations
> that are not indented exactly four spaces.
> 
> But if we keep this rule, we should adjust its comment
> 
>      // Warn several Error * definitions.
> 
> because it sure suggests it also catches functions like the one I gave
> above.
> 
>>>>>> +
>>>>>> +@ script:python @
>>>>>> +fn << check1.fn;
>>>>>> +@@
>>>>>> +
>>>>>> +print('Warning: function {} has several definitions of '
>>>>>> +      'Error * local variable'.format(fn))
>>>>>> +
>>>>>> +// Warn several propagations in control flow.
>>>>>> +@check2 disable optional_qualifier exists@
>>>>>> +identifier fn = rule1.fn;
>>>>>> +symbol errp;
>>>>>> +position p1, p2;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> +(
>>>>>> +     error_propagate_prepend(errp, ...);@p1
>>>>>> +|
>>>>>> +     error_propagate(errp, ...);@p1
>>>>>> +)
>>>>>> +     ...
>>>>>> +(
>>>>>> +     error_propagate_prepend(errp, ...);@p2
>>>>>> +|
>>>>>> +     error_propagate(errp, ...);@p2
>>>>>> +)
>>>>>> +     ... when any
>>>>>> + }
>>>>>> +
>>>>>
>>>>> Hmm, we don't catch the example I used in review of v8:
>>>>>
>>>>>        extern foo(int, Error **);
>>>>>        extern bar(int, Error **);
>>>>>
>>>>>        void frob(Error **errp)
>>>>>        {
>>>>>            Error *local_err = NULL;
>>>>>            int arg;
>>>>>
>>>>>            foo(arg, errp);
>>>>>            bar(arg, &local_err);
>>>>>            error_propagate(errp, local_err);
>>>>>            bar(arg + 1, &local_err);
>>>>>            error_propagate(errp, local_err);
>>>>>        }
>>>>>
>>>>> I believe this is because rule1 does not match here.
>>>>
>>>> Yes, rule1 wants at least one code flow with non-doubled propagation.
>>>>
>>>>>
>>>>> If I change the rule as follows, it catches the example:
>>>>>
>>>>>        @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
>>>>>
>>>>>         // Warn several propagations in control flow.
>>>>>         @check2 disable optional_qualifier exists@
>>>>>        -identifier fn = rule1.fn;
>>>>>        -symbol errp;
>>>>>        +identifier fn, _errp;
>>>>>         position p1, p2;
>>>>>         @@
>>>>>
>>>>>        - fn(..., Error ** ____, ...)
>>>>>        + fn(..., Error **_errp, ...)
>>>>>          {
>>>>>              ...
>>>>>         (
>>>>>        -     error_propagate_prepend(errp, ...);@p1
>>>>>        +     error_propagate_prepend(_errp, ...);@p1
>>>>>         |
>>>>>        -     error_propagate(errp, ...);@p1
>>>>>        +     error_propagate(_errp, ...);@p1
>>>>>         )
>>>>>              ...
>>>>>         (
>>>>>        -     error_propagate_prepend(errp, ...);@p2
>>>>>        +     error_propagate_prepend(_errp, ...);@p2
>>>>>         |
>>>>>        -     error_propagate(errp, ...);@p2
>>>>>        +     error_propagate(_errp, ...);@p2
>>>>>         )
>>>>>              ... when any
>>>>>          }
>>>>>
>>>>> To my mild surprise, it still doesn't find anything in our tree.
>>>>>
>>>>> Should we decouple the previous rule from rule1, too?  I tested the
>>>>> following on the whole tree:
>>>>
>>>> I don't think so. Why to check what we are not going to convert? If we want
>>>> to check side things, it's better to do it in other coccinelle script..
>>>
>>> Misunderstanding?  The rules are still chained together via the ___
>>> hack, just not via function name, because that's unreliable and
>>> redundant.
>>
>> Strange.. Then, how can it match something not matched by rule1?
> 
> I think I got confused when I wrote the "Misunderstanding?" paragraph.
> 
> Let me try again.
> 
> First rule check2.
> 
> The common case is a at most one propagation to @errp along any control
> flow path.  We trust your Coccinelle script to convert that alright.
> 
> Any other propagation to @errp I want to review.  Whether the script
> attempts a conversion or not is unimportant, as long as it points me to
> the function to review.
> 
> Rule rule1 matches functions that propagate to @errp once along at least
> one control flow path.
> 
> Unchained from rule rule1, rule check2 flags any function that
> propagates to @errp multiple times along any control flow path.
> 
> Chained to rule1, it flags only functions that also have a path with
> single propagation.
> 
> In other words, the unchained rule flags *all* multi-propagations to
> @errp, while the chained rule flags only the ones the script attempts to
> convert.  The former is much more useful to me.
> 
> Now rule check1.  It flags functions with multiple declarations along
> any control flow path.  Again, chaining it to rule1 restricts it to the
> functions we attempt to convert.  Makes it less useful to me.  However,
> because my desire to review multiple declarations in function we don't
> attempt to convert is lower than my desire to review multiple
> propagations to @errp in such functions, chaining check1 is tolerable
> for me.  But why chain check1 if we don't chain check2?
> 
>>
>>>
>>>>>
>>>>>        @@ -136,10 +136,10 @@ symbol errp;
>>>>>
>>>>>         // Warn several Error * definitions.
>>>>>         @check1 disable optional_qualifier exists@
>>>>>        -identifier fn = rule1.fn, local_err, local_err2;
>>>>>        +identifier fn, _errp, local_err, local_err2;
>>>>>         @@
>>>>>
>>>>>        - fn(..., Error ** ____, ...)
>>>>>        + fn(..., Error **_errp, ...)
>>>>>          {
>>>>>              ...
>>>>>              Error *local_err = NULL;
>>>>>
>>>>> Warnings remain unchanged.
>>>>>
>>>>>> +@ script:python @
>>>>>> +fn << check2.fn;
>>>>>> +p1 << check2.p1;
>>>>>> +p2 << check2.p2;
>>>>>> +@@
>>>>>> +
>>>>>> +print('Warning: function {} propagates to errp several times in '
>>>>>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>>>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>>>> +
>>>>>> +// Convert special case with goto separately.
>>>>>> +// I tried merging this into the following rule the obvious way, but
>>>>>> +// it made Coccinelle hang on block.c
>>>>>> +//
>>>>>> +// Note interesting thing: if we don't do it here, and try to fixup
>>>>>> +// "out: }" things later after all transformations (the rule will be
>>>>>> +// the same, just without error_propagate() call), coccinelle fails to
>>>>>> +// match this "out: }".
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn, rule1.local_err, out;
>>>>>
>>>>> As explained above, I doubt the need for rule1.fn.  We do need
>>>>> rule1.local_err to avoid unwanted transformations.  More of the same
>>>>> below.
>>>>
>>>> Logically, I want to inherit from rule1. So why not to stress it by inheriting
>>>> fn variable? It's just a correct thing to do.
>>>> And I hope it helps coccinelle to work more efficiently.
>>>>
>>>>>
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +-    goto out;
>>>>>> ++    return;
>>>>>> +     ...>
>>>>>> +- out:
>>>>>> +-    error_propagate(errp, local_err);
>>>>>> + }
>>>>>> +
>>>>>> +// Convert most of local_err related stuff.
>>>>>> +//
>>>>>> +// Note, that we update everything related to matched by rule1
>>>>>> +// function name and local_err name. We may match something not
>>>>>> +// related to the pattern matched by rule1. For example, local_err may
>>>>>> +// be defined with the same name in different blocks inside one
>>>>>> +// function, and in one block follow the propagation pattern and in
>>>>>> +// other block doesn't. Or we may have several functions with the same
>>>>>> +// name (for different configurations).
>>>>>> +//
>>>>>> +// Note also that errp-cleaning functions
>>>>>> +//   error_free_errp
>>>>>> +//   error_report_errp
>>>>>> +//   error_reportf_errp
>>>>>> +//   warn_report_errp
>>>>>> +//   warn_reportf_errp
>>>>>> +// are not yet implemented. They must call corresponding Error* -
>>>>>> +// freeing function and then set *errp to NULL, to avoid further
>>>>>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>>>>> +// For example, error_free_errp may look like this:
>>>>>> +//
>>>>>> +//    void error_free_errp(Error **errp)
>>>>>> +//    {
>>>>>> +//        error_free(*errp);
>>>>>> +//        *errp = NULL;
>>>>>> +//    }
>>>>>> +@ disable optional_qualifier exists@
>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>> +expression list args;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +(
>>>>>> +-    Error *local_err = NULL;
>>>>>> +|
>>>>>> +
>>>>>> +// Convert error clearing functions
>>>>>> +(
>>>>>> +-    error_free(local_err);
>>>>>> ++    error_free_errp(errp);
>>>>>> +|
>>>>>> +-    error_report_err(local_err);
>>>>>> ++    error_report_errp(errp);
>>>>>> +|
>>>>>> +-    error_reportf_err(local_err, args);
>>>>>> ++    error_reportf_errp(errp, args);
>>>>>> +|
>>>>>> +-    warn_report_err(local_err);
>>>>>> ++    warn_report_errp(errp);
>>>>>> +|
>>>>>> +-    warn_reportf_err(local_err, args);
>>>>>> ++    warn_reportf_errp(errp, args);
>>>>>> +)
>>>>>> +?-    local_err = NULL;
>>>>>> +
>>>>>> +|
>>>>>> +-    error_propagate_prepend(errp, local_err, args);
>>>>>> ++    error_prepend(errp, args);
>>>>>> +|
>>>>>> +-    error_propagate(errp, local_err);
>>>>>> +|
>>>>>> +-    &local_err
>>>>>> ++    errp
>>>>>> +)
>>>>>> +     ...>
>>>>>> + }
>>>>>> +
>>>>>> +// Convert remaining local_err usage. For example, different kinds of
>>>>>> +// error checking in if conditionals. We can't merge this into
>>>>>> +// previous hunk, as this conflicts with other substitutions in it (at
>>>>>> +// least with "- local_err = NULL").
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +-    local_err
>>>>>> ++    *errp
>>>>>> +     ...>
>>>>>> + }
>>>>>> +
>>>>>> +// Always use the same pattern for checking error
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +-    *errp != NULL
>>>>>> ++    *errp
>>>>>> +     ...>
>>>>>> + }
>>>>>> +
>>>>>> +// Revert temporary ___ identifier.
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error **
>>>>>> +-   ____
>>>>>> ++   errp
>>>>>> +    , ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> + }
>>>>>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>>>>>> index 30140d9bfe..56c133520d 100644
>>>>>> --- a/include/qapi/error.h
>>>>>> +++ b/include/qapi/error.h
>>>>>> @@ -214,6 +214,9 @@
>>>>>>      *         }
>>>>>>      *         ...
>>>>>>      *     }
>>>>>> + *
>>>>>> + * For mass-conversion use script
>>>>>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>      */
>>>>>>       #ifndef ERROR_H
>>>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>>>> index 857f969aa1..047f1b9714 100644
>>>>>> --- a/MAINTAINERS
>>>>>> +++ b/MAINTAINERS
>>>>>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>>>>>     F: qapi/error.json
>>>>>>     F: util/error.c
>>>>>>     F: util/qemu-error.c
>>>>>> +F: scripts/coccinelle/*err*.cocci
>>>>>>       GDB stub
>>>>>>     M: Alex Bennée <alex.bennee@linaro.org>
>>>>>
>>>
>>>
>>>   From 42a08c529024337d1b859839c9ce7f797f784555 Mon Sep 17 00:00:00 2001
>>> From: Markus Armbruster <armbru@redhat.com>
>>> Date: Fri, 13 Mar 2020 14:27:57 +0100
>>> Subject: [PATCH] fixup! scripts: Coccinelle script to use
>>>    ERRP_AUTO_PROPAGATE()
>>>
>>> ---
>>>    scripts/coccinelle/auto-propagated-errp.cocci | 37 ++++++++++---------
>>>    1 file changed, 20 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>> index 7dac2dcfa4..43b0b0e63b 100644
>>> --- a/scripts/coccinelle/auto-propagated-errp.cocci
>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>> @@ -136,45 +136,48 @@ symbol errp;
>>>      // Warn several Error * definitions.
>>>    @check1 disable optional_qualifier exists@
>>> -identifier fn = rule1.fn, local_err, local_err2;
>>> +identifier fn, _errp, local_err, local_err2;
>>> +position p1, p2;
>>
>>
>> Hmm, seems like I forget to define ____ as symbol in my patch
> 
> Coccinelle defaults to symbol.
> 
>>>    @@
>>>    - fn(..., Error ** ____, ...)
>>> + fn(..., Error **_errp, ...)
>>
>> Ahmm.. it will break compilation?
>>
>> Or, how will it work when _errp defined as meta variable is only in "+..." line? Should it be symbol instead, or just not defined?
> 
> Misunderstanding?  It's a diff between your .cocci and mine.  My version
> is
> 
>      // Warn several Error * definitions.
>      @check1 disable optional_qualifier exists@
>      identifier fn, _errp, local_err, local_err2;
>      position p1, p2;
>      @@
> 
>       fn(..., Error **_errp, ...)
>       {
>           ...
>           Error *local_err = NULL;@p1
>           ... when any
>           Error *local_err2 = NULL;@p2
>           ... when any
>       }
> 
>      @ script:python @
>      fn << check1.fn;
>      p1 << check1.p1;
>      p2 << check1.p2;
>      @@
> 
>>>     {
>>>         ...
>>> -     Error *local_err = NULL;
>>> +     Error *local_err = NULL;@p1
>>
>> Why to do -/+ here? Nothing changed..
>>
>>>         ... when any
>>> -     Error *local_err2 = NULL;
>>> +     Error *local_err2 = NULL;@p2
>>>         ... when any
>>>     }
>>>      @ script:python @
>>>    fn << check1.fn;
>>> +p1 << check1.p1;
>>> +p2 << check1.p2;
>>>    @@
>>>      print('Warning: function {} has several definitions of '
>>> -      'Error * local variable'.format(fn))
>>> +      'Error * local variable: at {}:{} and then at {}:{}'.format(
>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>      // Warn several propagations in control flow.
>>>    @check2 disable optional_qualifier exists@
>>> -identifier fn = rule1.fn;
>>> -symbol errp;
>>> +identifier fn, _errp;
>>>    position p1, p2;
>>>    @@
>>>    - fn(..., Error ** ____, ...)
>>> + fn(..., Error **_errp, ...)
>>>     {
>>>         ...
>>>    (
>>> -     error_propagate_prepend(errp, ...);@p1
>>> +     error_propagate_prepend(_errp, ...);@p1
>>>    |
>>> -     error_propagate(errp, ...);@p1
>>> +     error_propagate(_errp, ...);@p1
>>>    )
>>>         ...
>>>    (
>>> -     error_propagate_prepend(errp, ...);@p2
>>> +     error_propagate_prepend(_errp, ...);@p2
>>>    |
>>> -     error_propagate(errp, ...);@p2
>>> +     error_propagate(_errp, ...);@p2
>>>    )
>>
>> You change some occurrences of errp to _errp, but not all. It breaks compilation.
>>
>>>         ... when any
>>>     }
>>> @@ -198,7 +201,7 @@ print('Warning: function {} propagates to errp several times in '
>>>    // the same, just without error_propagate() call), coccinelle fails to
>>>    // match this "out: }".
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn, rule1.local_err, out;
>>> +identifier fn, rule1.local_err, out;
>>
>> Hmm. If it improves performance it is strange.. But I can live with this change.
>>
>>>    symbol errp;
>>>    @@
>>>    @@ -239,7 +242,7 @@ symbol errp;
>>>    //        *errp = NULL;
>>>    //    }
>>>    @ disable optional_qualifier exists@
>>> -identifier rule1.fn, rule1.local_err;
>>> +identifier fn, rule1.local_err;
>>>    expression list args;
>>>    symbol errp;
>>>    @@
>>> @@ -287,7 +290,7 @@ symbol errp;
>>>    // previous hunk, as this conflicts with other substitutions in it (at
>>>    // least with "- local_err = NULL").
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn, rule1.local_err;
>>> +identifier fn, rule1.local_err;
>>>    symbol errp;
>>>    @@
>>>    @@ -301,7 +304,7 @@ symbol errp;
>>>      // Always use the same pattern for checking error
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn;
>>> +identifier fn;
>>>    symbol errp;
>>>    @@
>>>    @@ -315,7 +318,7 @@ symbol errp;
>>>      // Revert temporary ___ identifier.
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn;
>>> +identifier fn;
>>>    @@
>>>       fn(..., Error **
>>>
> 
> I append my hacked up version of auto-propagated-errp.cocci.  It
> produces the same patch as yours for the complete tree.
> 
> 
> 
> // Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
> //
> // Copyright (c) 2020 Virtuozzo International GmbH.
> //
> // This program is free software; you can redistribute it and/or
> // modify it under the terms of the GNU General Public License as
> // published by the Free Software Foundation; either version 2 of the
> // License, or (at your option) any later version.
> //
> // This program is distributed in the hope that it will be useful,
> // but WITHOUT ANY WARRANTY; without even the implied warranty of
> // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> // GNU General Public License for more details.
> //
> // You should have received a copy of the GNU General Public License
> // along with this program.  If not, see
> // <http://www.gnu.org/licenses/>.
> //
> // Usage example:
> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
> //  --macro-file scripts/cocci-macro-file.h --in-place \
> //  --no-show-diff --max-width 80 FILES...
> //
> // Note: --max-width 80 is needed because coccinelle default is less
> // than 80, and without this parameter coccinelle may reindent some
> // lines which fit into 80 characters but not to coccinelle default,
> // which in turn produces extra patch hunks for no reason.
> 
> // Switch unusual Error ** parameter names to errp
> // (this is necessary to use ERRP_AUTO_PROPAGATE).
> //
> // Disable optional_qualifier to skip functions with
> // "Error *const *errp" parameter.
> //
> // Skip functions with "assert(_errp && *_errp)" statement, because
> // that signals unusual semantics, and the parameter name may well
> // serve a purpose. (like nbd_iter_channel_error()).
> //
> // Skip util/error.c to not touch, for example, error_propagate() and
> // error_propagate_prepend().
> @ depends on !(file in "util/error.c") disable optional_qualifier@
> identifier fn;
> identifier _errp != errp;
> @@
> 
>   fn(...,
> -   Error **_errp
> +   Error **errp
>      ,...)
>   {
> (
>       ... when != assert(_errp && *_errp)
> &
>       <...
> -    _errp
> +    errp
>       ...>
> )
>   }
> 
> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
> // necessary
> //
> // Note, that without "when any" the final "..." does not mach
> // something matched by previous pattern, i.e. the rule will not match
> // double error_prepend in control flow like in
> // vfio_set_irq_signaling().
> //
> // Note, "exists" says that we want apply rule even if it matches not
> // on all possible control flows (otherwise, it will not match
> // standard pattern when error_propagate() call is in if branch).
> @ disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
> 
>   fn(..., Error **errp, ...)
>   {
> +   ERRP_AUTO_PROPAGATE();
>      ...  when != ERRP_AUTO_PROPAGATE();
> (
> (
>      error_append_hint(errp, ...);
> |
>      error_prepend(errp, ...);
> |
>      error_vprepend(errp, ...);
> )
>      ... when any
> |
>      Error *local_err = NULL;
>      ...
> (
>      error_propagate_prepend(errp, local_err, ...);
> |
>      error_propagate(errp, local_err);
> )
>      ...
> )
>   }
> 
> 
> // Match functions with propagation of local error to errp.
> // We want to refer these functions in several following rules, but I
> // don't know a proper way to inherit a function, not just its name
> // (to not match another functions with same name in following rules).
> // Not-proper way is as follows: rename errp parameter in functions
> // header and match it in following rules. Rename it back after all
> // transformations.
> //
> // The simplest case of propagation scheme is single definition of
> // local_err with at most one error_propagate_prepend or
> // error_propagate on each control-flow. Still, we want to match more
> // complex schemes too. We'll warn them with help of further rules.
> @rule1 disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
> 
>   fn(..., Error **
> -    errp
> +    ____
>      , ...)
>   {
>       ...
>       Error *local_err = NULL;
>       ...
> (
>       error_propagate_prepend(errp, local_err, ...);
> |
>       error_propagate(errp, local_err);
> )
>       ...
>   }
> 
> 
> // Warn several Error * definitions.
> @check1 disable optional_qualifier exists@
> identifier fn, _errp, local_err, local_err2;
> position p1, p2;
> @@
> 
>   fn(..., Error **_errp, ...)
>   {
>       ...
>       Error *local_err = NULL;@p1
>       ... when any
>       Error *local_err2 = NULL;@p2
>       ... when any
>   }
> 
> @ script:python @
> fn << check1.fn;
> p1 << check1.p1;
> p2 << check1.p2;
> @@
> 
> print('Warning: function {} has several definitions of '
>        'Error * local variable: at {}:{} and then at {}:{}'.format(
>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> 
> // Warn several propagations in control flow.
> @check2 disable optional_qualifier exists@
> identifier fn, _errp;
> position p1, p2;
> @@
> 
>   fn(..., Error **_errp, ...)

Hmm, for this to work, we should move the rule above rule1, because now paramter
definition is different from it usage in the function body.

>   {
>       ...
> (
>       error_propagate_prepend(_errp, ...);@p1
> |
>       error_propagate(_errp, ...);@p1
> )
>       ...
> (
>       error_propagate_prepend(_errp, ...);@p2
> |
>       error_propagate(_errp, ...);@p2
> )
>       ... when any
>   }
> 
> @ script:python @
> fn << check2.fn;
> p1 << check2.p1;
> p2 << check2.p2;
> @@
> 
> print('Warning: function {} propagates to errp several times in '
>        'one control flow: at {}:{} and then at {}:{}'.format(
>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> 
> // Convert special case with goto separately.
> // I tried merging this into the following rule the obvious way, but
> // it made Coccinelle hang on block.c
> //
> // Note interesting thing: if we don't do it here, and try to fixup
> // "out: }" things later after all transformations (the rule will be
> // the same, just without error_propagate() call), coccinelle fails to
> // match this "out: }".
> @ disable optional_qualifier@
> identifier fn, rule1.local_err, out;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    goto out;
> +    return;
>       ...>
> - out:
> -    error_propagate(errp, local_err);
>   }
> 
> // Convert most of local_err related stuff.
> //
> // Note, that we update everything related to matched by rule1
> // function name and local_err name. We may match something not
> // related to the pattern matched by rule1. For example, local_err may
> // be defined with the same name in different blocks inside one
> // function, and in one block follow the propagation pattern and in
> // other block doesn't. Or we may have several functions with the same
> // name (for different configurations).
> //
> // Note also that errp-cleaning functions
> //   error_free_errp
> //   error_report_errp
> //   error_reportf_errp
> //   warn_report_errp
> //   warn_reportf_errp
> // are not yet implemented. They must call corresponding Error* -
> // freeing function and then set *errp to NULL, to avoid further
> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
> // For example, error_free_errp may look like this:
> //
> //    void error_free_errp(Error **errp)
> //    {
> //        error_free(*errp);
> //        *errp = NULL;
> //    }
> @ disable optional_qualifier exists@
> identifier fn, rule1.local_err;
> expression list args;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> (
> -    Error *local_err = NULL;
> |
> 
> // Convert error clearing functions
> (
> -    error_free(local_err);
> +    error_free_errp(errp);
> |
> -    error_report_err(local_err);
> +    error_report_errp(errp);
> |
> -    error_reportf_err(local_err, args);
> +    error_reportf_errp(errp, args);
> |
> -    warn_report_err(local_err);
> +    warn_report_errp(errp);
> |
> -    warn_reportf_err(local_err, args);
> +    warn_reportf_errp(errp, args);
> )
> ?-    local_err = NULL;
> 
> |
> -    error_propagate_prepend(errp, local_err, args);
> +    error_prepend(errp, args);
> |
> -    error_propagate(errp, local_err);
> |
> -    &local_err
> +    errp
> )
>       ...>
>   }
> 
> // Convert remaining local_err usage. For example, different kinds of
> // error checking in if conditionals. We can't merge this into
> // previous hunk, as this conflicts with other substitutions in it (at
> // least with "- local_err = NULL").
> @ disable optional_qualifier@
> identifier fn, rule1.local_err;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    local_err
> +    *errp
>       ...>
>   }
> 
> // Always use the same pattern for checking error
> @ disable optional_qualifier@
> identifier fn;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    *errp != NULL
> +    *errp
>       ...>
>   }
> 
> // Revert temporary ___ identifier.
> @ disable optional_qualifier@
> identifier fn;
> @@
> 
>   fn(..., Error **
> -   ____
> +   errp
>      , ...)
>   {
>       ...
>   }
> 


-- 
Best regards,
Vladimir


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-17 13:54               ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-17 13:54 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Laszlo Ersek, Christian Schoenebeck, Michael Roth, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

14.03.2020 0:54, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> 13.03.2020 18:42, Markus Armbruster wrote:
>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>
>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>> out now as is.
>>>>>
>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>
>>>>>> Script adds ERRP_AUTO_PROPAGATE macro invocation where appropriate and
>>>>>> does corresponding changes in code (look for details in
>>>>>> include/qapi/error.h)
>>>>>>
>>>>>> Usage example:
>>>>>> spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>>     --macro-file scripts/cocci-macro-file.h --in-place --no-show-diff \
>>>>>>     --max-width 80 FILES...
>>>>>>
>>>>>> Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
>>>>>> ---
>>>>>>
>>>>>> Cc: Eric Blake <eblake@redhat.com>
>>>>>> Cc: Kevin Wolf <kwolf@redhat.com>
>>>>>> Cc: Max Reitz <mreitz@redhat.com>
>>>>>> Cc: Greg Kurz <groug@kaod.org>
>>>>>> Cc: Christian Schoenebeck <qemu_oss@crudebyte.com>
>>>>>> Cc: Stefano Stabellini <sstabellini@kernel.org>
>>>>>> Cc: Anthony Perard <anthony.perard@citrix.com>
>>>>>> Cc: Paul Durrant <paul@xen.org>
>>>>>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>>>>>> Cc: "Philippe Mathieu-Daudé" <philmd@redhat.com>
>>>>>> Cc: Laszlo Ersek <lersek@redhat.com>
>>>>>> Cc: Gerd Hoffmann <kraxel@redhat.com>
>>>>>> Cc: Stefan Berger <stefanb@linux.ibm.com>
>>>>>> Cc: Markus Armbruster <armbru@redhat.com>
>>>>>> Cc: Michael Roth <mdroth@linux.vnet.ibm.com>
>>>>>> Cc: qemu-devel@nongnu.org
>>>>>> Cc: qemu-block@nongnu.org
>>>>>> Cc: xen-devel@lists.xenproject.org
>>>>>>
>>>>>>     scripts/coccinelle/auto-propagated-errp.cocci | 327 ++++++++++++++++++
>>>>>>     include/qapi/error.h                          |   3 +
>>>>>>     MAINTAINERS                                   |   1 +
>>>>>>     3 files changed, 331 insertions(+)
>>>>>>     create mode 100644 scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>
>>>>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>> new file mode 100644
>>>>>> index 0000000000..7dac2dcfa4
>>>>>> --- /dev/null
>>>>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>>>>> @@ -0,0 +1,327 @@
>>>>>> +// Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
>>>>>> +//
>>>>>> +// Copyright (c) 2020 Virtuozzo International GmbH.
>>>>>> +//
>>>>>> +// This program is free software; you can redistribute it and/or
>>>>>> +// modify it under the terms of the GNU General Public License as
>>>>>> +// published by the Free Software Foundation; either version 2 of the
>>>>>> +// License, or (at your option) any later version.
>>>>>> +//
>>>>>> +// This program is distributed in the hope that it will be useful,
>>>>>> +// but WITHOUT ANY WARRANTY; without even the implied warranty of
>>>>>> +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>>>>> +// GNU General Public License for more details.
>>>>>> +//
>>>>>> +// You should have received a copy of the GNU General Public License
>>>>>> +// along with this program.  If not, see
>>>>>> +// <http://www.gnu.org/licenses/>.
>>>>>> +//
>>>>>> +// Usage example:
>>>>>> +// spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
>>>>>> +//  --macro-file scripts/cocci-macro-file.h --in-place \
>>>>>> +//  --no-show-diff --max-width 80 FILES...
>>>>>> +//
>>>>>> +// Note: --max-width 80 is needed because coccinelle default is less
>>>>>> +// than 80, and without this parameter coccinelle may reindent some
>>>>>> +// lines which fit into 80 characters but not to coccinelle default,
>>>>>> +// which in turn produces extra patch hunks for no reason.
>>>>>
>>>>> This is about unwanted reformatting of parameter lists due to the ___
>>>>> chaining hack.  --max-width 80 makes that less likely, but not
>>>>> impossible.
>>>>>
>>>>> We can search for unwanted reformatting of parameter lists.  I think
>>>>> grepping diffs for '^\+.*Error \*\*' should do the trick.  For the whole
>>>>> tree, I get one false positive (not a parameter list), and one hit:
>>>>>
>>>>>        @@ -388,8 +388,10 @@ static void object_post_init_with_type(O
>>>>>             }
>>>>>         }
>>>>>
>>>>>        -void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp)
>>>>>        +void object_apply_global_props(Object *obj, const GPtrArray *props,
>>>>>        +                               Error **errp)
>>>>>         {
>>>>>        +    ERRP_AUTO_PROPAGATE();
>>>>>             int i;
>>>>>
>>>>>             if (!props) {
>>>>>
>>>>> Reformatting, but not unwanted.
>>>>
>>>> Yes, I saw it. This line is 81 character length, so it's OK to fix it in one hunk with
>>>> ERRP_AUTO_PROPAGATE addition even for non-automatic patch.
>>>
>>> Agree.
>>>
>>>>>
>>>>> The --max-width 80 hack is good enough for me.
>>>>>
>>>>> It does result in slightly long transformed lines, e.g. this one in
>>>>> replication.c:
>>>>>
>>>>>        @@ -113,7 +113,7 @@ static int replication_open(BlockDriverS
>>>>>                 s->mode = REPLICATION_MODE_PRIMARY;
>>>>>                 top_id = qemu_opt_get(opts, REPLICATION_TOP_ID);
>>>>>                 if (top_id) {
>>>>>        -            error_setg(&local_err, "The primary side does not support option top-id");
>>>>>        +            error_setg(errp, "The primary side does not support option top-id");
>>>>>                     goto fail;
>>>>>                 }
>>>>>             } else if (!strcmp(mode, "secondary")) {
>>>>>
>>>>> v8 did break this line (that's how I found it).  However, v9 still
>>>>> shortens the line, just not below the target.  All your + lines look
>>>>> quite unlikely to lengthen lines.  Let's not worry about this.
>>>>>
>>>>>> +// Switch unusual Error ** parameter names to errp
>>>>>> +// (this is necessary to use ERRP_AUTO_PROPAGATE).
>>>>>> +//
>>>>>> +// Disable optional_qualifier to skip functions with
>>>>>> +// "Error *const *errp" parameter.
>>>>>> +//
>>>>>> +// Skip functions with "assert(_errp && *_errp)" statement, because
>>>>>> +// that signals unusual semantics, and the parameter name may well
>>>>>> +// serve a purpose. (like nbd_iter_channel_error()).
>>>>>> +//
>>>>>> +// Skip util/error.c to not touch, for example, error_propagate() and
>>>>>> +// error_propagate_prepend().
>>>>>> +@ depends on !(file in "util/error.c") disable optional_qualifier@
>>>>>> +identifier fn;
>>>>>> +identifier _errp != errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(...,
>>>>>> +-   Error **_errp
>>>>>> ++   Error **errp
>>>>>> +    ,...)
>>>>>> + {
>>>>>> +(
>>>>>> +     ... when != assert(_errp && *_errp)
>>>>>> +&
>>>>>> +     <...
>>>>>> +-    _errp
>>>>>> ++    errp
>>>>>> +     ...>
>>>>>> +)
>>>>>> + }
>>>>>> +
>>>>>> +// Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
>>>>>> +// necessary
>>>>>> +//
>>>>>> +// Note, that without "when any" the final "..." does not mach
>>>>>> +// something matched by previous pattern, i.e. the rule will not match
>>>>>> +// double error_prepend in control flow like in
>>>>>> +// vfio_set_irq_signaling().
>>>>>> +//
>>>>>> +// Note, "exists" says that we want apply rule even if it matches not
>>>>>> +// on all possible control flows (otherwise, it will not match
>>>>>> +// standard pattern when error_propagate() call is in if branch).
>>>>>> +@ disable optional_qualifier exists@
>>>>>> +identifier fn, local_err;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error **errp, ...)
>>>>>> + {
>>>>>> ++   ERRP_AUTO_PROPAGATE();
>>>>>> +    ...  when != ERRP_AUTO_PROPAGATE();
>>>>>> +(
>>>>>> +(
>>>>>> +    error_append_hint(errp, ...);
>>>>>> +|
>>>>>> +    error_prepend(errp, ...);
>>>>>> +|
>>>>>> +    error_vprepend(errp, ...);
>>>>>> +)
>>>>>> +    ... when any
>>>>>> +|
>>>>>> +    Error *local_err = NULL;
>>>>>> +    ...
>>>>>> +(
>>>>>> +    error_propagate_prepend(errp, local_err, ...);
>>>>>> +|
>>>>>> +    error_propagate(errp, local_err);
>>>>>> +)
>>>>>> +    ...
>>>>>> +)
>>>>>> + }
>>>>>> +
>>>>>> +
>>>>>> +// Match functions with propagation of local error to errp.
>>>>>> +// We want to refer these functions in several following rules, but I
>>>>>> +// don't know a proper way to inherit a function, not just its name
>>>>>> +// (to not match another functions with same name in following rules).
>>>>>> +// Not-proper way is as follows: rename errp parameter in functions
>>>>>> +// header and match it in following rules. Rename it back after all
>>>>>> +// transformations.
>>>>>> +//
>>>>>> +// The simplest case of propagation scheme is single definition of
>>>>>> +// local_err with at most one error_propagate_prepend or
>>>>>> +// error_propagate on each control-flow. Still, we want to match more
>>>>>> +// complex schemes too. We'll warn them with help of further rules.
>>>>>
>>>>> I think what we actually want is to examine instances of this pattern to
>>>>> figure out whether and how we want to transform them.  Perhaps:
>>>>>
>>>>>        // The common case is a single definition of local_err with at most one
>>>>>        // error_propagate_prepend() or error_propagate() on each control-flow
>>>>>        // path. Instances of this case we convert with this script. Functions
>>>>
>>>> For me, sounds a bit like "other things we don't convert".
>>>> Actually we convert other things too.
>>>
>>> What other patterns of error propagation do we convert?
>>
>> Something like in xen_block_device_destroy, why not? Otherwise, it's better to avoid
>> matching things like xen_block_device_destroy, not just warn them.
>> But I'd prefer to proceed now as is to fit into 5.0.. Too much time already
>> spent on this. So, I'm OK with your wording too.
> 
> Let's scratch "Instances of this case we convert with this script."
> 
>>>>>        // with multiple definitions or propagates we want to examine
>>>>>        // manually. Later rules emit warnings to guide us to them.
>>>>>
>>>>>> +@rule1 disable optional_qualifier exists@
>>>>>> +identifier fn, local_err;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error **
>>>>>> +-    errp
>>>>>> ++    ____
>>>>>> +    , ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> +     Error *local_err = NULL;
>>>>>> +     ...
>>>>>> +(
>>>>>> +     error_propagate_prepend(errp, local_err, ...);
>>>>>> +|
>>>>>> +     error_propagate(errp, local_err);
>>>>>> +)
>>>>>> +     ...
>>>>>> + }
>>>>>> +
>>>>>> +
>>>>>> +// Warn several Error * definitions.
>>>>>> +@check1 disable optional_qualifier exists@
>>>>>> +identifier fn = rule1.fn, local_err, local_err2;
>>>>>
>>>>> Elsewhere, you use just rule.fn instead of fn = rule1.fn.  Any
>>>>> particular reason for the difference?
>>>>
>>>> I didn't find other way to ref check1.fn in next python rule. It just don't
>>>> work if I write here just rule1.fn.
>>>>
>>>>>
>>>>> With the ___ chaining hack, I doubt we still need "= rule1.fn" or
>>>>> "rule1.fn".  If I replace "fn = rule1.fn" and "rule.fn" by just "fn"
>>>>> everywhere, then apply the script to the complete tree, I get the same
>>>>> result.
>>>>
>>>> I think, it's more efficient to reuse names from previous rules. I think it should
>>>> work faster (more information, less extra matching).
>>>
>>> Nope.  With my hacked up script (patch appended) Coccinelle is actually
>>> *faster* for the .[ch] touched by this series: with your unmodified
>>> script, it takes a bit over 12s on my box, with mine around 7s.  Output
>>> is identical.
>>>
>>> Never guess performance, always measure it :)
>>
>> Hmm, whole tree results would be better proof
>>
>>>
>>> Two notes on my script:
>>>
>>> * Unlike yours, it recognizes double-propagation in my test case.
>>>     Discussed below.
>>>
>>> * Its "several definitions of" warning includes positions.  That turned
>>>     out to be useless, but I've been too lazy to take that out again.
>>>
>>>>>
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> +     Error *local_err = NULL;
>>>>>> +     ... when any
>>>>>> +     Error *local_err2 = NULL;
>>>>>> +     ... when any
>>>>>> + }
> 
> This flags functions that have more than one declaration along any
> control flow path.  It doesn't flag this one:
> 
>      void gnat(bool b, Error **errp)
>      {
>          if (b) {
>              Error *local_err = NULL;
>              foo(arg, &local_err);
>              error_propagate(errp, local_err);
>          } else {
>              Error *local_err = NULL;
>              bar(arg, &local_err);
>              error_propagate(errp, local_err);
>          }
>      }
> 
> The Coccinelle script does the right thing for this one regardless.
> 
> I'd prefer to have such functions flagged, too.  But spending time on
> convincing Coccinelle to do it for me is not worthwhile; I can simply
> search the diff produced by Coccinelle for deletions of declarations
> that are not indented exactly four spaces.
> 
> But if we keep this rule, we should adjust its comment
> 
>      // Warn several Error * definitions.
> 
> because it sure suggests it also catches functions like the one I gave
> above.
> 
>>>>>> +
>>>>>> +@ script:python @
>>>>>> +fn << check1.fn;
>>>>>> +@@
>>>>>> +
>>>>>> +print('Warning: function {} has several definitions of '
>>>>>> +      'Error * local variable'.format(fn))
>>>>>> +
>>>>>> +// Warn several propagations in control flow.
>>>>>> +@check2 disable optional_qualifier exists@
>>>>>> +identifier fn = rule1.fn;
>>>>>> +symbol errp;
>>>>>> +position p1, p2;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> +(
>>>>>> +     error_propagate_prepend(errp, ...);@p1
>>>>>> +|
>>>>>> +     error_propagate(errp, ...);@p1
>>>>>> +)
>>>>>> +     ...
>>>>>> +(
>>>>>> +     error_propagate_prepend(errp, ...);@p2
>>>>>> +|
>>>>>> +     error_propagate(errp, ...);@p2
>>>>>> +)
>>>>>> +     ... when any
>>>>>> + }
>>>>>> +
>>>>>
>>>>> Hmm, we don't catch the example I used in review of v8:
>>>>>
>>>>>        extern foo(int, Error **);
>>>>>        extern bar(int, Error **);
>>>>>
>>>>>        void frob(Error **errp)
>>>>>        {
>>>>>            Error *local_err = NULL;
>>>>>            int arg;
>>>>>
>>>>>            foo(arg, errp);
>>>>>            bar(arg, &local_err);
>>>>>            error_propagate(errp, local_err);
>>>>>            bar(arg + 1, &local_err);
>>>>>            error_propagate(errp, local_err);
>>>>>        }
>>>>>
>>>>> I believe this is because rule1 does not match here.
>>>>
>>>> Yes, rule1 wants at least one code flow with non-doubled propagation.
>>>>
>>>>>
>>>>> If I change the rule as follows, it catches the example:
>>>>>
>>>>>        @@ -157,24 +157,23 @@ print('Warning: function {} has several definitions of '
>>>>>
>>>>>         // Warn several propagations in control flow.
>>>>>         @check2 disable optional_qualifier exists@
>>>>>        -identifier fn = rule1.fn;
>>>>>        -symbol errp;
>>>>>        +identifier fn, _errp;
>>>>>         position p1, p2;
>>>>>         @@
>>>>>
>>>>>        - fn(..., Error ** ____, ...)
>>>>>        + fn(..., Error **_errp, ...)
>>>>>          {
>>>>>              ...
>>>>>         (
>>>>>        -     error_propagate_prepend(errp, ...);@p1
>>>>>        +     error_propagate_prepend(_errp, ...);@p1
>>>>>         |
>>>>>        -     error_propagate(errp, ...);@p1
>>>>>        +     error_propagate(_errp, ...);@p1
>>>>>         )
>>>>>              ...
>>>>>         (
>>>>>        -     error_propagate_prepend(errp, ...);@p2
>>>>>        +     error_propagate_prepend(_errp, ...);@p2
>>>>>         |
>>>>>        -     error_propagate(errp, ...);@p2
>>>>>        +     error_propagate(_errp, ...);@p2
>>>>>         )
>>>>>              ... when any
>>>>>          }
>>>>>
>>>>> To my mild surprise, it still doesn't find anything in our tree.
>>>>>
>>>>> Should we decouple the previous rule from rule1, too?  I tested the
>>>>> following on the whole tree:
>>>>
>>>> I don't think so. Why to check what we are not going to convert? If we want
>>>> to check side things, it's better to do it in other coccinelle script..
>>>
>>> Misunderstanding?  The rules are still chained together via the ___
>>> hack, just not via function name, because that's unreliable and
>>> redundant.
>>
>> Strange.. Then, how can it match something not matched by rule1?
> 
> I think I got confused when I wrote the "Misunderstanding?" paragraph.
> 
> Let me try again.
> 
> First rule check2.
> 
> The common case is a at most one propagation to @errp along any control
> flow path.  We trust your Coccinelle script to convert that alright.
> 
> Any other propagation to @errp I want to review.  Whether the script
> attempts a conversion or not is unimportant, as long as it points me to
> the function to review.
> 
> Rule rule1 matches functions that propagate to @errp once along at least
> one control flow path.
> 
> Unchained from rule rule1, rule check2 flags any function that
> propagates to @errp multiple times along any control flow path.
> 
> Chained to rule1, it flags only functions that also have a path with
> single propagation.
> 
> In other words, the unchained rule flags *all* multi-propagations to
> @errp, while the chained rule flags only the ones the script attempts to
> convert.  The former is much more useful to me.
> 
> Now rule check1.  It flags functions with multiple declarations along
> any control flow path.  Again, chaining it to rule1 restricts it to the
> functions we attempt to convert.  Makes it less useful to me.  However,
> because my desire to review multiple declarations in function we don't
> attempt to convert is lower than my desire to review multiple
> propagations to @errp in such functions, chaining check1 is tolerable
> for me.  But why chain check1 if we don't chain check2?
> 
>>
>>>
>>>>>
>>>>>        @@ -136,10 +136,10 @@ symbol errp;
>>>>>
>>>>>         // Warn several Error * definitions.
>>>>>         @check1 disable optional_qualifier exists@
>>>>>        -identifier fn = rule1.fn, local_err, local_err2;
>>>>>        +identifier fn, _errp, local_err, local_err2;
>>>>>         @@
>>>>>
>>>>>        - fn(..., Error ** ____, ...)
>>>>>        + fn(..., Error **_errp, ...)
>>>>>          {
>>>>>              ...
>>>>>              Error *local_err = NULL;
>>>>>
>>>>> Warnings remain unchanged.
>>>>>
>>>>>> +@ script:python @
>>>>>> +fn << check2.fn;
>>>>>> +p1 << check2.p1;
>>>>>> +p2 << check2.p2;
>>>>>> +@@
>>>>>> +
>>>>>> +print('Warning: function {} propagates to errp several times in '
>>>>>> +      'one control flow: at {}:{} and then at {}:{}'.format(
>>>>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>>>> +
>>>>>> +// Convert special case with goto separately.
>>>>>> +// I tried merging this into the following rule the obvious way, but
>>>>>> +// it made Coccinelle hang on block.c
>>>>>> +//
>>>>>> +// Note interesting thing: if we don't do it here, and try to fixup
>>>>>> +// "out: }" things later after all transformations (the rule will be
>>>>>> +// the same, just without error_propagate() call), coccinelle fails to
>>>>>> +// match this "out: }".
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn, rule1.local_err, out;
>>>>>
>>>>> As explained above, I doubt the need for rule1.fn.  We do need
>>>>> rule1.local_err to avoid unwanted transformations.  More of the same
>>>>> below.
>>>>
>>>> Logically, I want to inherit from rule1. So why not to stress it by inheriting
>>>> fn variable? It's just a correct thing to do.
>>>> And I hope it helps coccinelle to work more efficiently.
>>>>
>>>>>
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +-    goto out;
>>>>>> ++    return;
>>>>>> +     ...>
>>>>>> +- out:
>>>>>> +-    error_propagate(errp, local_err);
>>>>>> + }
>>>>>> +
>>>>>> +// Convert most of local_err related stuff.
>>>>>> +//
>>>>>> +// Note, that we update everything related to matched by rule1
>>>>>> +// function name and local_err name. We may match something not
>>>>>> +// related to the pattern matched by rule1. For example, local_err may
>>>>>> +// be defined with the same name in different blocks inside one
>>>>>> +// function, and in one block follow the propagation pattern and in
>>>>>> +// other block doesn't. Or we may have several functions with the same
>>>>>> +// name (for different configurations).
>>>>>> +//
>>>>>> +// Note also that errp-cleaning functions
>>>>>> +//   error_free_errp
>>>>>> +//   error_report_errp
>>>>>> +//   error_reportf_errp
>>>>>> +//   warn_report_errp
>>>>>> +//   warn_reportf_errp
>>>>>> +// are not yet implemented. They must call corresponding Error* -
>>>>>> +// freeing function and then set *errp to NULL, to avoid further
>>>>>> +// propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
>>>>>> +// For example, error_free_errp may look like this:
>>>>>> +//
>>>>>> +//    void error_free_errp(Error **errp)
>>>>>> +//    {
>>>>>> +//        error_free(*errp);
>>>>>> +//        *errp = NULL;
>>>>>> +//    }
>>>>>> +@ disable optional_qualifier exists@
>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>> +expression list args;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +(
>>>>>> +-    Error *local_err = NULL;
>>>>>> +|
>>>>>> +
>>>>>> +// Convert error clearing functions
>>>>>> +(
>>>>>> +-    error_free(local_err);
>>>>>> ++    error_free_errp(errp);
>>>>>> +|
>>>>>> +-    error_report_err(local_err);
>>>>>> ++    error_report_errp(errp);
>>>>>> +|
>>>>>> +-    error_reportf_err(local_err, args);
>>>>>> ++    error_reportf_errp(errp, args);
>>>>>> +|
>>>>>> +-    warn_report_err(local_err);
>>>>>> ++    warn_report_errp(errp);
>>>>>> +|
>>>>>> +-    warn_reportf_err(local_err, args);
>>>>>> ++    warn_reportf_errp(errp, args);
>>>>>> +)
>>>>>> +?-    local_err = NULL;
>>>>>> +
>>>>>> +|
>>>>>> +-    error_propagate_prepend(errp, local_err, args);
>>>>>> ++    error_prepend(errp, args);
>>>>>> +|
>>>>>> +-    error_propagate(errp, local_err);
>>>>>> +|
>>>>>> +-    &local_err
>>>>>> ++    errp
>>>>>> +)
>>>>>> +     ...>
>>>>>> + }
>>>>>> +
>>>>>> +// Convert remaining local_err usage. For example, different kinds of
>>>>>> +// error checking in if conditionals. We can't merge this into
>>>>>> +// previous hunk, as this conflicts with other substitutions in it (at
>>>>>> +// least with "- local_err = NULL").
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn, rule1.local_err;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +-    local_err
>>>>>> ++    *errp
>>>>>> +     ...>
>>>>>> + }
>>>>>> +
>>>>>> +// Always use the same pattern for checking error
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn;
>>>>>> +symbol errp;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error ** ____, ...)
>>>>>> + {
>>>>>> +     <...
>>>>>> +-    *errp != NULL
>>>>>> ++    *errp
>>>>>> +     ...>
>>>>>> + }
>>>>>> +
>>>>>> +// Revert temporary ___ identifier.
>>>>>> +@ disable optional_qualifier@
>>>>>> +identifier rule1.fn;
>>>>>> +@@
>>>>>> +
>>>>>> + fn(..., Error **
>>>>>> +-   ____
>>>>>> ++   errp
>>>>>> +    , ...)
>>>>>> + {
>>>>>> +     ...
>>>>>> + }
>>>>>> diff --git a/include/qapi/error.h b/include/qapi/error.h
>>>>>> index 30140d9bfe..56c133520d 100644
>>>>>> --- a/include/qapi/error.h
>>>>>> +++ b/include/qapi/error.h
>>>>>> @@ -214,6 +214,9 @@
>>>>>>      *         }
>>>>>>      *         ...
>>>>>>      *     }
>>>>>> + *
>>>>>> + * For mass-conversion use script
>>>>>> + *   scripts/coccinelle/auto-propagated-errp.cocci
>>>>>>      */
>>>>>>       #ifndef ERROR_H
>>>>>> diff --git a/MAINTAINERS b/MAINTAINERS
>>>>>> index 857f969aa1..047f1b9714 100644
>>>>>> --- a/MAINTAINERS
>>>>>> +++ b/MAINTAINERS
>>>>>> @@ -1998,6 +1998,7 @@ F: include/qemu/error-report.h
>>>>>>     F: qapi/error.json
>>>>>>     F: util/error.c
>>>>>>     F: util/qemu-error.c
>>>>>> +F: scripts/coccinelle/*err*.cocci
>>>>>>       GDB stub
>>>>>>     M: Alex Bennée <alex.bennee@linaro.org>
>>>>>
>>>
>>>
>>>   From 42a08c529024337d1b859839c9ce7f797f784555 Mon Sep 17 00:00:00 2001
>>> From: Markus Armbruster <armbru@redhat.com>
>>> Date: Fri, 13 Mar 2020 14:27:57 +0100
>>> Subject: [PATCH] fixup! scripts: Coccinelle script to use
>>>    ERRP_AUTO_PROPAGATE()
>>>
>>> ---
>>>    scripts/coccinelle/auto-propagated-errp.cocci | 37 ++++++++++---------
>>>    1 file changed, 20 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/scripts/coccinelle/auto-propagated-errp.cocci b/scripts/coccinelle/auto-propagated-errp.cocci
>>> index 7dac2dcfa4..43b0b0e63b 100644
>>> --- a/scripts/coccinelle/auto-propagated-errp.cocci
>>> +++ b/scripts/coccinelle/auto-propagated-errp.cocci
>>> @@ -136,45 +136,48 @@ symbol errp;
>>>      // Warn several Error * definitions.
>>>    @check1 disable optional_qualifier exists@
>>> -identifier fn = rule1.fn, local_err, local_err2;
>>> +identifier fn, _errp, local_err, local_err2;
>>> +position p1, p2;
>>
>>
>> Hmm, seems like I forget to define ____ as symbol in my patch
> 
> Coccinelle defaults to symbol.
> 
>>>    @@
>>>    - fn(..., Error ** ____, ...)
>>> + fn(..., Error **_errp, ...)
>>
>> Ahmm.. it will break compilation?
>>
>> Or, how will it work when _errp defined as meta variable is only in "+..." line? Should it be symbol instead, or just not defined?
> 
> Misunderstanding?  It's a diff between your .cocci and mine.  My version
> is
> 
>      // Warn several Error * definitions.
>      @check1 disable optional_qualifier exists@
>      identifier fn, _errp, local_err, local_err2;
>      position p1, p2;
>      @@
> 
>       fn(..., Error **_errp, ...)
>       {
>           ...
>           Error *local_err = NULL;@p1
>           ... when any
>           Error *local_err2 = NULL;@p2
>           ... when any
>       }
> 
>      @ script:python @
>      fn << check1.fn;
>      p1 << check1.p1;
>      p2 << check1.p2;
>      @@
> 
>>>     {
>>>         ...
>>> -     Error *local_err = NULL;
>>> +     Error *local_err = NULL;@p1
>>
>> Why to do -/+ here? Nothing changed..
>>
>>>         ... when any
>>> -     Error *local_err2 = NULL;
>>> +     Error *local_err2 = NULL;@p2
>>>         ... when any
>>>     }
>>>      @ script:python @
>>>    fn << check1.fn;
>>> +p1 << check1.p1;
>>> +p2 << check1.p2;
>>>    @@
>>>      print('Warning: function {} has several definitions of '
>>> -      'Error * local variable'.format(fn))
>>> +      'Error * local variable: at {}:{} and then at {}:{}'.format(
>>> +          fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>>      // Warn several propagations in control flow.
>>>    @check2 disable optional_qualifier exists@
>>> -identifier fn = rule1.fn;
>>> -symbol errp;
>>> +identifier fn, _errp;
>>>    position p1, p2;
>>>    @@
>>>    - fn(..., Error ** ____, ...)
>>> + fn(..., Error **_errp, ...)
>>>     {
>>>         ...
>>>    (
>>> -     error_propagate_prepend(errp, ...);@p1
>>> +     error_propagate_prepend(_errp, ...);@p1
>>>    |
>>> -     error_propagate(errp, ...);@p1
>>> +     error_propagate(_errp, ...);@p1
>>>    )
>>>         ...
>>>    (
>>> -     error_propagate_prepend(errp, ...);@p2
>>> +     error_propagate_prepend(_errp, ...);@p2
>>>    |
>>> -     error_propagate(errp, ...);@p2
>>> +     error_propagate(_errp, ...);@p2
>>>    )
>>
>> You change some occurrences of errp to _errp, but not all. It breaks compilation.
>>
>>>         ... when any
>>>     }
>>> @@ -198,7 +201,7 @@ print('Warning: function {} propagates to errp several times in '
>>>    // the same, just without error_propagate() call), coccinelle fails to
>>>    // match this "out: }".
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn, rule1.local_err, out;
>>> +identifier fn, rule1.local_err, out;
>>
>> Hmm. If it improves performance it is strange.. But I can live with this change.
>>
>>>    symbol errp;
>>>    @@
>>>    @@ -239,7 +242,7 @@ symbol errp;
>>>    //        *errp = NULL;
>>>    //    }
>>>    @ disable optional_qualifier exists@
>>> -identifier rule1.fn, rule1.local_err;
>>> +identifier fn, rule1.local_err;
>>>    expression list args;
>>>    symbol errp;
>>>    @@
>>> @@ -287,7 +290,7 @@ symbol errp;
>>>    // previous hunk, as this conflicts with other substitutions in it (at
>>>    // least with "- local_err = NULL").
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn, rule1.local_err;
>>> +identifier fn, rule1.local_err;
>>>    symbol errp;
>>>    @@
>>>    @@ -301,7 +304,7 @@ symbol errp;
>>>      // Always use the same pattern for checking error
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn;
>>> +identifier fn;
>>>    symbol errp;
>>>    @@
>>>    @@ -315,7 +318,7 @@ symbol errp;
>>>      // Revert temporary ___ identifier.
>>>    @ disable optional_qualifier@
>>> -identifier rule1.fn;
>>> +identifier fn;
>>>    @@
>>>       fn(..., Error **
>>>
> 
> I append my hacked up version of auto-propagated-errp.cocci.  It
> produces the same patch as yours for the complete tree.
> 
> 
> 
> // Use ERRP_AUTO_PROPAGATE (see include/qapi/error.h)
> //
> // Copyright (c) 2020 Virtuozzo International GmbH.
> //
> // This program is free software; you can redistribute it and/or
> // modify it under the terms of the GNU General Public License as
> // published by the Free Software Foundation; either version 2 of the
> // License, or (at your option) any later version.
> //
> // This program is distributed in the hope that it will be useful,
> // but WITHOUT ANY WARRANTY; without even the implied warranty of
> // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> // GNU General Public License for more details.
> //
> // You should have received a copy of the GNU General Public License
> // along with this program.  If not, see
> // <http://www.gnu.org/licenses/>.
> //
> // Usage example:
> // spatch --sp-file scripts/coccinelle/auto-propagated-errp.cocci \
> //  --macro-file scripts/cocci-macro-file.h --in-place \
> //  --no-show-diff --max-width 80 FILES...
> //
> // Note: --max-width 80 is needed because coccinelle default is less
> // than 80, and without this parameter coccinelle may reindent some
> // lines which fit into 80 characters but not to coccinelle default,
> // which in turn produces extra patch hunks for no reason.
> 
> // Switch unusual Error ** parameter names to errp
> // (this is necessary to use ERRP_AUTO_PROPAGATE).
> //
> // Disable optional_qualifier to skip functions with
> // "Error *const *errp" parameter.
> //
> // Skip functions with "assert(_errp && *_errp)" statement, because
> // that signals unusual semantics, and the parameter name may well
> // serve a purpose. (like nbd_iter_channel_error()).
> //
> // Skip util/error.c to not touch, for example, error_propagate() and
> // error_propagate_prepend().
> @ depends on !(file in "util/error.c") disable optional_qualifier@
> identifier fn;
> identifier _errp != errp;
> @@
> 
>   fn(...,
> -   Error **_errp
> +   Error **errp
>      ,...)
>   {
> (
>       ... when != assert(_errp && *_errp)
> &
>       <...
> -    _errp
> +    errp
>       ...>
> )
>   }
> 
> // Add invocation of ERRP_AUTO_PROPAGATE to errp-functions where
> // necessary
> //
> // Note, that without "when any" the final "..." does not mach
> // something matched by previous pattern, i.e. the rule will not match
> // double error_prepend in control flow like in
> // vfio_set_irq_signaling().
> //
> // Note, "exists" says that we want apply rule even if it matches not
> // on all possible control flows (otherwise, it will not match
> // standard pattern when error_propagate() call is in if branch).
> @ disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
> 
>   fn(..., Error **errp, ...)
>   {
> +   ERRP_AUTO_PROPAGATE();
>      ...  when != ERRP_AUTO_PROPAGATE();
> (
> (
>      error_append_hint(errp, ...);
> |
>      error_prepend(errp, ...);
> |
>      error_vprepend(errp, ...);
> )
>      ... when any
> |
>      Error *local_err = NULL;
>      ...
> (
>      error_propagate_prepend(errp, local_err, ...);
> |
>      error_propagate(errp, local_err);
> )
>      ...
> )
>   }
> 
> 
> // Match functions with propagation of local error to errp.
> // We want to refer these functions in several following rules, but I
> // don't know a proper way to inherit a function, not just its name
> // (to not match another functions with same name in following rules).
> // Not-proper way is as follows: rename errp parameter in functions
> // header and match it in following rules. Rename it back after all
> // transformations.
> //
> // The simplest case of propagation scheme is single definition of
> // local_err with at most one error_propagate_prepend or
> // error_propagate on each control-flow. Still, we want to match more
> // complex schemes too. We'll warn them with help of further rules.
> @rule1 disable optional_qualifier exists@
> identifier fn, local_err;
> symbol errp;
> @@
> 
>   fn(..., Error **
> -    errp
> +    ____
>      , ...)
>   {
>       ...
>       Error *local_err = NULL;
>       ...
> (
>       error_propagate_prepend(errp, local_err, ...);
> |
>       error_propagate(errp, local_err);
> )
>       ...
>   }
> 
> 
> // Warn several Error * definitions.
> @check1 disable optional_qualifier exists@
> identifier fn, _errp, local_err, local_err2;
> position p1, p2;
> @@
> 
>   fn(..., Error **_errp, ...)
>   {
>       ...
>       Error *local_err = NULL;@p1
>       ... when any
>       Error *local_err2 = NULL;@p2
>       ... when any
>   }
> 
> @ script:python @
> fn << check1.fn;
> p1 << check1.p1;
> p2 << check1.p2;
> @@
> 
> print('Warning: function {} has several definitions of '
>        'Error * local variable: at {}:{} and then at {}:{}'.format(
>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> 
> // Warn several propagations in control flow.
> @check2 disable optional_qualifier exists@
> identifier fn, _errp;
> position p1, p2;
> @@
> 
>   fn(..., Error **_errp, ...)

Hmm, for this to work, we should move the rule above rule1, because now paramter
definition is different from it usage in the function body.

>   {
>       ...
> (
>       error_propagate_prepend(_errp, ...);@p1
> |
>       error_propagate(_errp, ...);@p1
> )
>       ...
> (
>       error_propagate_prepend(_errp, ...);@p2
> |
>       error_propagate(_errp, ...);@p2
> )
>       ... when any
>   }
> 
> @ script:python @
> fn << check2.fn;
> p1 << check2.p1;
> p2 << check2.p2;
> @@
> 
> print('Warning: function {} propagates to errp several times in '
>        'one control flow: at {}:{} and then at {}:{}'.format(
>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
> 
> // Convert special case with goto separately.
> // I tried merging this into the following rule the obvious way, but
> // it made Coccinelle hang on block.c
> //
> // Note interesting thing: if we don't do it here, and try to fixup
> // "out: }" things later after all transformations (the rule will be
> // the same, just without error_propagate() call), coccinelle fails to
> // match this "out: }".
> @ disable optional_qualifier@
> identifier fn, rule1.local_err, out;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    goto out;
> +    return;
>       ...>
> - out:
> -    error_propagate(errp, local_err);
>   }
> 
> // Convert most of local_err related stuff.
> //
> // Note, that we update everything related to matched by rule1
> // function name and local_err name. We may match something not
> // related to the pattern matched by rule1. For example, local_err may
> // be defined with the same name in different blocks inside one
> // function, and in one block follow the propagation pattern and in
> // other block doesn't. Or we may have several functions with the same
> // name (for different configurations).
> //
> // Note also that errp-cleaning functions
> //   error_free_errp
> //   error_report_errp
> //   error_reportf_errp
> //   warn_report_errp
> //   warn_reportf_errp
> // are not yet implemented. They must call corresponding Error* -
> // freeing function and then set *errp to NULL, to avoid further
> // propagation to original errp (consider ERRP_AUTO_PROPAGATE in use).
> // For example, error_free_errp may look like this:
> //
> //    void error_free_errp(Error **errp)
> //    {
> //        error_free(*errp);
> //        *errp = NULL;
> //    }
> @ disable optional_qualifier exists@
> identifier fn, rule1.local_err;
> expression list args;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> (
> -    Error *local_err = NULL;
> |
> 
> // Convert error clearing functions
> (
> -    error_free(local_err);
> +    error_free_errp(errp);
> |
> -    error_report_err(local_err);
> +    error_report_errp(errp);
> |
> -    error_reportf_err(local_err, args);
> +    error_reportf_errp(errp, args);
> |
> -    warn_report_err(local_err);
> +    warn_report_errp(errp);
> |
> -    warn_reportf_err(local_err, args);
> +    warn_reportf_errp(errp, args);
> )
> ?-    local_err = NULL;
> 
> |
> -    error_propagate_prepend(errp, local_err, args);
> +    error_prepend(errp, args);
> |
> -    error_propagate(errp, local_err);
> |
> -    &local_err
> +    errp
> )
>       ...>
>   }
> 
> // Convert remaining local_err usage. For example, different kinds of
> // error checking in if conditionals. We can't merge this into
> // previous hunk, as this conflicts with other substitutions in it (at
> // least with "- local_err = NULL").
> @ disable optional_qualifier@
> identifier fn, rule1.local_err;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    local_err
> +    *errp
>       ...>
>   }
> 
> // Always use the same pattern for checking error
> @ disable optional_qualifier@
> identifier fn;
> symbol errp;
> @@
> 
>   fn(..., Error ** ____, ...)
>   {
>       <...
> -    *errp != NULL
> +    *errp
>       ...>
>   }
> 
> // Revert temporary ___ identifier.
> @ disable optional_qualifier@
> identifier fn;
> @@
> 
>   fn(..., Error **
> -   ____
> +   errp
>      , ...)
>   {
>       ...
>   }
> 


-- 
Best regards,
Vladimir

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-17 13:54               ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-19  8:31                 ` Markus Armbruster
  -1 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-19  8:31 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 14.03.2020 0:54, Markus Armbruster wrote:
[...]
>> // Match functions with propagation of local error to errp.
>> // We want to refer these functions in several following rules, but I
>> // don't know a proper way to inherit a function, not just its name
>> // (to not match another functions with same name in following rules).
>> // Not-proper way is as follows: rename errp parameter in functions
>> // header and match it in following rules. Rename it back after all
>> // transformations.
>> //
>> // The simplest case of propagation scheme is single definition of
>> // local_err with at most one error_propagate_prepend or
>> // error_propagate on each control-flow. Still, we want to match more
>> // complex schemes too. We'll warn them with help of further rules.
>> @rule1 disable optional_qualifier exists@
>> identifier fn, local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error **
>> -    errp
>> +    ____
>>      , ...)
>>   {
>>       ...
>>       Error *local_err = NULL;
>>       ...
>> (
>>       error_propagate_prepend(errp, local_err, ...);
>> |
>>       error_propagate(errp, local_err);
>> )
>>       ...
>>   }
>>
>>
>> // Warn several Error * definitions.
>> @check1 disable optional_qualifier exists@
>> identifier fn, _errp, local_err, local_err2;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>>   {
>>       ...
>>       Error *local_err = NULL;@p1
>>       ... when any
>>       Error *local_err2 = NULL;@p2
>>       ... when any
>>   }
>>
>> @ script:python @
>> fn << check1.fn;
>> p1 << check1.p1;
>> p2 << check1.p2;
>> @@
>>
>> print('Warning: function {} has several definitions of '
>>        'Error * local variable: at {}:{} and then at {}:{}'.format(
>>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>
>> // Warn several propagations in control flow.
>> @check2 disable optional_qualifier exists@
>> identifier fn, _errp;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>
> Hmm, for this to work, we should move the rule above rule1, because now paramter
> definition is different from it usage in the function body.

I think you're right.

[...]



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-19  8:31                 ` Markus Armbruster
  0 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-19  8:31 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 14.03.2020 0:54, Markus Armbruster wrote:
[...]
>> // Match functions with propagation of local error to errp.
>> // We want to refer these functions in several following rules, but I
>> // don't know a proper way to inherit a function, not just its name
>> // (to not match another functions with same name in following rules).
>> // Not-proper way is as follows: rename errp parameter in functions
>> // header and match it in following rules. Rename it back after all
>> // transformations.
>> //
>> // The simplest case of propagation scheme is single definition of
>> // local_err with at most one error_propagate_prepend or
>> // error_propagate on each control-flow. Still, we want to match more
>> // complex schemes too. We'll warn them with help of further rules.
>> @rule1 disable optional_qualifier exists@
>> identifier fn, local_err;
>> symbol errp;
>> @@
>>
>>   fn(..., Error **
>> -    errp
>> +    ____
>>      , ...)
>>   {
>>       ...
>>       Error *local_err = NULL;
>>       ...
>> (
>>       error_propagate_prepend(errp, local_err, ...);
>> |
>>       error_propagate(errp, local_err);
>> )
>>       ...
>>   }
>>
>>
>> // Warn several Error * definitions.
>> @check1 disable optional_qualifier exists@
>> identifier fn, _errp, local_err, local_err2;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>>   {
>>       ...
>>       Error *local_err = NULL;@p1
>>       ... when any
>>       Error *local_err2 = NULL;@p2
>>       ... when any
>>   }
>>
>> @ script:python @
>> fn << check1.fn;
>> p1 << check1.p1;
>> p2 << check1.p2;
>> @@
>>
>> print('Warning: function {} has several definitions of '
>>        'Error * local variable: at {}:{} and then at {}:{}'.format(
>>            fn, p1[0].file, p1[0].line, p2[0].file, p2[0].line))
>>
>> // Warn several propagations in control flow.
>> @check2 disable optional_qualifier exists@
>> identifier fn, _errp;
>> position p1, p2;
>> @@
>>
>>   fn(..., Error **_errp, ...)
>
> Hmm, for this to work, we should move the rule above rule1, because now paramter
> definition is different from it usage in the function body.

I think you're right.

[...]


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-17 11:35                       ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-19 10:45                         ` Markus Armbruster
  -1 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-19 10:45 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 17.03.2020 13:39, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>
>>> 16.03.2020 11:21, Markus Armbruster wrote:
>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>
>>>>> On 14.03.2020 00:54, Markus Armbruster wrote:
>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>
>>>>>>> 13.03.2020 18:42, Markus Armbruster wrote:
>>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>>>
>>>>>>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>>>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>>>>>>> out now as is.
>>>>>>>>>>
>>>>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>> [...]
>>>>>>>>>>> +@@
>>>>>>>>>>> +
>>>>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>>>>> + {
>>>>>>>>>>> +     ...
>>>>>>>>>>> +     Error *local_err = NULL;
>>>>>>>>>>> +     ... when any
>>>>>>>>>>> +     Error *local_err2 = NULL;
>>>>>>>>>>> +     ... when any
>>>>>>>>>>> + }
>>>>>>
>>>>>> This flags functions that have more than one declaration along any
>>>>>> control flow path.  It doesn't flag this one:
>>>>>>
>>>>>>        void gnat(bool b, Error **errp)
>>>>>>        {
>>>>>>            if (b) {
>>>>>>                Error *local_err = NULL;
>>>>>>                foo(arg, &local_err);
>>>>>>                error_propagate(errp, local_err);
>>>>>>            } else {
>>>>>>                Error *local_err = NULL;
>>>>>>                bar(arg, &local_err);
>>>>>>                error_propagate(errp, local_err);
>>>>>>            }
>>>>>>        }
>>>>>>
>>>>>> The Coccinelle script does the right thing for this one regardless.
>>>>>>
>>>>>> I'd prefer to have such functions flagged, too.  But spending time on
>>>>>> convincing Coccinelle to do it for me is not worthwhile; I can simply
>>>>>> search the diff produced by Coccinelle for deletions of declarations
>>>>>> that are not indented exactly four spaces.
>>>>>>
>>>>>> But if we keep this rule, we should adjust its comment
>>>>>>
>>>>>>        // Warn several Error * definitions.
>>>>>>
>>>>>> because it sure suggests it also catches functions like the one I gave
>>>>>> above.
>>>>>
>>>>> Hmm, yes.. We can write "Warn several Error * definitions in _one_
>>>>> control flow (it's not so trivial to match _any_ case with several
>>>>> definitions with coccinelle)" or something like this.
>>>>
>>>> Ha, "trivial" reminds me of a story.  The math professor, after having
>>>> spent a good chunk of his lecture developing a proof on the blackboad
>>>> turns to the audience to explain why this little part doesn't require
>>>> proof with the words familiar to any math student "and this is trivial."
>>>> Pause, puzzled look...  "Is it trivial?"  Pause, storms out of the
>>>> lecture hall.  A minute or three pass.  Professor comes back beaming,
>>>> "it is trivial!", and proceeds with the proof.
>>>>
>>>> My point is: it might be trivial with Coccinelle once you know how to do
>>>> it.  We don't.
>>>>
>>>> Suggest "(can't figure out how to match several definitions regardless
>>>> of control flow)".
>>>
>>> Wrong too, because I can:) for example, chaining two rules, catching the
>>> positions of definition and check that they are different.. Or, some
>>> cheating with python script.. That's why I wrote "not trivial",
>>>
>>> So, most correct would be "(can't figure out how to simply match several definitions regardless
>>>> of control flow)".
>>
>> Works for me.
>>
>>> But again, coccinelle is for matching control flows, so its probably impossible to match such thing..
>> [...]
>>>>> OK, I almost OK with it, the only thing I doubt a bit is the following:
>>>>>
>>>>> We want to keep rule1.local_err inheritance to keep connection with
>>>>> local_err definition.
>>>>
>>>> Yes.
>>>>
>>>>> Interesting, when we have both rule1.fn and rule1.local_err inherited,
>>>>> do we inherit them in separate (i.e. all possible combinations of fn
>>>>> and local_err symbols from rule1) or do we inherit a pair, i.e. only
>>>>> fn/local_err pairs, found by rule1? If the latter is correct, that
>>>>> with your script we loss this pair inheritance, and go to all possible
>>>>> combinations of fn and local_err from rule1, possibly adding some wrong
>>>>> conversion (OK, you've checked that no such cases in current code tree).
>>>>
>>>> The chaining "identifier rule1.FOO" is by name.  It's reliable only as
>>>> long as there is exactly one instance of the name.
>>>>
>>>> We already discussed the case of the function name: if there are two
>>>> instances of foo(), and rule1 matches only one of them, then we
>>>> nevertheless apply the rules chained to rule1 to both.  Because that can
>>>> be wrong, you came up with the ___ trick, which chains reliably.
>>>>
>>>> The same issue exists with the variable name: if there are two instances
>>>> of @local_err, and rule1 matches only one of them, then we nevertheless
>>>> apply the rules chained to rule1 to both.  Can also be wrong.
>>>>
>>>> What are the conditions for "wrong"?
>>>>
>>>> Because the ___ chaining is reliable, we know rule1 matched the
>>>> function, i.e. it has a parameter Error **errp, and it has a automatic
>>>> variable Error *local_err = NULL.
>>>>
>>>> We're good as long as *all* identifiers @local_err in this function are
>>>> declared that way.  This seems quite likely.  It's not certain, though.
>>>>
>>>> Since nested declarations of Error ** variables are rare, we can rely on
>>>> review to ensure we transform these functions correctly.
>>>>
>>>>> So, dropping inheritance in check-rules makes sence, as it may match
>>>>> (and warn) more interesting cases.
>>>>>
>>>>> But for other rules, I'd prefere to be safer, and explictly inherit all
>>>>> actually inherited identifiers..
>>>>
>>>> I still can't see what chaining by function name in addition to the ___
>>>> chaining buys us.
>>>
>>> I'll check this thing soon. And resend today.
>
> Checked.
>
> Yes, it inherits pair of fn and local_err, and it definitely makes sense. It more stable.
>
> Consider the following example:
>
> # cat a.c
> int f1(Error **errp)
> {
>     Error *err1 = NULL;
>     int err2 = 0;
>
>     error_propagate(errp, err1);
>
>     return err2;
> }
>
> int f2(Error **errp)
> {
>     Error *err2 = NULL;
>     int err1 = 0;
>
>     error_propagate(errp, err2);
>
>     return err1;
> }
>
>
> My script works correct and produces this change:
> --- a.c
> +++ /tmp/cocci-output-1753-10842a-a.c
> @@ -1,19 +1,15 @@
>  int f1(Error **errp)
>  {
> -    Error *err1 = NULL;
> +    ERRP_AUTO_PROPAGATE();
>      int err2 = 0;
>
> -    error_propagate(errp, err1);
> -
>      return err2;
>  }
>
>  int f2(Error **errp)
>  {
> -    Error *err2 = NULL;
> +    ERRP_AUTO_PROPAGATE();
>      int err1 = 0;
>
> -    error_propagate(errp, err2);
> -
>      return err1;
>  }
>
>
> But yours script is caught:
> --- a.c
> +++ /tmp/cocci-output-1814-b9b681-a.c
> @@ -1,19 +1,15 @@
>  int f1(Error **errp)
>  {
> -    Error *err1 = NULL;
> +    ERRP_AUTO_PROPAGATE();
>      int err2 = 0;
>
> -    error_propagate(errp, err1);
> -
> -    return err2;
> +    return *errp;
>  }
>
>  int f2(Error **errp)
>  {
> -    Error *err2 = NULL;
> +    ERRP_AUTO_PROPAGATE();
>      int err1 = 0;
>
> -    error_propagate(errp, err2);
> -
> -    return err1;
> +    return *errp;
>  }
>
>
> - see, it touches err1, which is unrelated to Error in f2. Hmm,
> interesting that it doesn't want to convert err1 declaration:)
>
> - this is because relation between local_err and fn is lost.

Let me try to think this through.

rule1 matches functions that propagate from a local variable @local_err
to parameter @errp.  It uses the ___ hack to reliably tag the function.
Later rules that should only apply to these functions can match ___.

These later rules each provide a part of the total error propagation
transformation.  They must transform exactly the @local_err and @errp
matched by rule1 in each function.

Your solution is to constrain the identifiers, i.e.

    identifier rule1.fn, rule1.local_err;

If rule1 matches only one function named foo(), and within that foo()
the local variable @local_err rule1 matches actually binds all
occurences of the identifier @local_err, the constraint is reliable.

Else, the constraint may still accept occurences of @local_err not bound
to the variable matched by rule1.

Example 1:

    int bar(Error **errp)
    {
        if (pred()) {
            Error *local_err = NULL;

            error_setg(&local_err, "zzzt");
            error_propagate(errp, local_err);
        } else {
            int local_err = 0;
            return local_err;
        }
        return 0;
    }

rule1 matches the first @local_err variable, and not the second one.  We
must transform occurences of the first one, and not occurences of the
second one.  We do transform all:

     int bar(Error **errp)
     {
    +    ERRP_AUTO_PROPAGATE();
         if (pred()) {
    -        Error *local_err = NULL;
    -
    -        error_setg(&local_err, "zzzt");
    -        error_propagate(errp, local_err);
    +        error_setg(errp, "zzzt");
         } else {
             int local_err = 0;
    -        return local_err;
    +        return *errp;
         }
         return 0;
     }

Example 2:

    int foo(Error **errp)
    {
        Error *local_err = NULL;

        error_setg(&local_err, "zzzt");
        error_propagate(errp, local_err);
        return 0;
    }

    int foo(Error **errp)
    {
        Error *err = NULL;
        int local_err = 0;

        error_setg(&local_err, "zzzt");
        error_propagate(errp, err);
        return local_err;
    }

rule1 matches @local_err in the first foo(), and @err in the second one.
We must transform @local_err in the first one(), and @err in the second
one.  We do transform both in both:

     int foo(Error **errp)
     {
    -    Error *local_err = NULL;
    +    ERRP_AUTO_PROPAGATE();

    -    error_setg(&local_err, "zzzt");
    -    error_propagate(errp, local_err);
    +    error_setg(errp, "zzzt");
         return 0;
     }

     int foo(Error **errp)
     {
    -    Error *err = NULL;
    +    ERRP_AUTO_PROPAGATE();
         int local_err = 0;

    -    error_setg(&local_err, "zzzt");
    -    error_propagate(errp, err);
    -    return local_err;
    +    error_setg(errp, "zzzt");
    +    return *errp;
     }

Constraining only the variable identifier like I proposed is even less
reliable, as you demonstrated: then the issue in example 2 exists even
for differently named functions.

For a reliable solution, we could use perhaps use the ___ hack again:
have rule1 rename @local_err it actually matches.  But to be honest, my
appetite for another round of wrestling with Coccinelle isn't what it
used to be.

I think we can do without as long as we're well aware of the script's
limitations, and we're confident we can detect problematic cases.

Detecting transformation of multiple functions with the same name should
be easy.

Detecting occurences of identifiers not bound by a certain variable
should be feasible: we find and review every transformed function that
doesn't declare the variable in its outermost scope.

Since "well aware" is going to erode with time, we may want to delete
the script when we're done converting.

> So, understanding that there no such cases in the whole tree, and even
> if your patch works faster on the whole tree, I still don't want to
> drop inheritance, because it's just a correct thing to do. Yes, we've
> added ____ helper. It helps to avoid some problems. Pair-inheritance
> helps to avoid another problems. I understand, that there still may
> other, not-covered problems, but better to be as safe as possible. And
> inheritance here is native and correct thing to do, even with our ____
> additional helper. What do you think?

I wouldn't call it correct.  It's still unreliable, but less so than
without the function name constraint.  That makes it less wrong.

100% reliable would be nice, but not at any cost.  Something we're
reasonably confident to get right should be good enough.

To be confident, we need to understand the script's limitations, and how
to compensate for them.  I figure we do now.  You too?

[...]



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-19 10:45                         ` Markus Armbruster
  0 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-19 10:45 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 17.03.2020 13:39, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>
>>> 16.03.2020 11:21, Markus Armbruster wrote:
>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>
>>>>> On 14.03.2020 00:54, Markus Armbruster wrote:
>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>
>>>>>>> 13.03.2020 18:42, Markus Armbruster wrote:
>>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>>>
>>>>>>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>>>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>>>>>>> out now as is.
>>>>>>>>>>
>>>>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>> [...]
>>>>>>>>>>> +@@
>>>>>>>>>>> +
>>>>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>>>>> + {
>>>>>>>>>>> +     ...
>>>>>>>>>>> +     Error *local_err = NULL;
>>>>>>>>>>> +     ... when any
>>>>>>>>>>> +     Error *local_err2 = NULL;
>>>>>>>>>>> +     ... when any
>>>>>>>>>>> + }
>>>>>>
>>>>>> This flags functions that have more than one declaration along any
>>>>>> control flow path.  It doesn't flag this one:
>>>>>>
>>>>>>        void gnat(bool b, Error **errp)
>>>>>>        {
>>>>>>            if (b) {
>>>>>>                Error *local_err = NULL;
>>>>>>                foo(arg, &local_err);
>>>>>>                error_propagate(errp, local_err);
>>>>>>            } else {
>>>>>>                Error *local_err = NULL;
>>>>>>                bar(arg, &local_err);
>>>>>>                error_propagate(errp, local_err);
>>>>>>            }
>>>>>>        }
>>>>>>
>>>>>> The Coccinelle script does the right thing for this one regardless.
>>>>>>
>>>>>> I'd prefer to have such functions flagged, too.  But spending time on
>>>>>> convincing Coccinelle to do it for me is not worthwhile; I can simply
>>>>>> search the diff produced by Coccinelle for deletions of declarations
>>>>>> that are not indented exactly four spaces.
>>>>>>
>>>>>> But if we keep this rule, we should adjust its comment
>>>>>>
>>>>>>        // Warn several Error * definitions.
>>>>>>
>>>>>> because it sure suggests it also catches functions like the one I gave
>>>>>> above.
>>>>>
>>>>> Hmm, yes.. We can write "Warn several Error * definitions in _one_
>>>>> control flow (it's not so trivial to match _any_ case with several
>>>>> definitions with coccinelle)" or something like this.
>>>>
>>>> Ha, "trivial" reminds me of a story.  The math professor, after having
>>>> spent a good chunk of his lecture developing a proof on the blackboad
>>>> turns to the audience to explain why this little part doesn't require
>>>> proof with the words familiar to any math student "and this is trivial."
>>>> Pause, puzzled look...  "Is it trivial?"  Pause, storms out of the
>>>> lecture hall.  A minute or three pass.  Professor comes back beaming,
>>>> "it is trivial!", and proceeds with the proof.
>>>>
>>>> My point is: it might be trivial with Coccinelle once you know how to do
>>>> it.  We don't.
>>>>
>>>> Suggest "(can't figure out how to match several definitions regardless
>>>> of control flow)".
>>>
>>> Wrong too, because I can:) for example, chaining two rules, catching the
>>> positions of definition and check that they are different.. Or, some
>>> cheating with python script.. That's why I wrote "not trivial",
>>>
>>> So, most correct would be "(can't figure out how to simply match several definitions regardless
>>>> of control flow)".
>>
>> Works for me.
>>
>>> But again, coccinelle is for matching control flows, so its probably impossible to match such thing..
>> [...]
>>>>> OK, I almost OK with it, the only thing I doubt a bit is the following:
>>>>>
>>>>> We want to keep rule1.local_err inheritance to keep connection with
>>>>> local_err definition.
>>>>
>>>> Yes.
>>>>
>>>>> Interesting, when we have both rule1.fn and rule1.local_err inherited,
>>>>> do we inherit them in separate (i.e. all possible combinations of fn
>>>>> and local_err symbols from rule1) or do we inherit a pair, i.e. only
>>>>> fn/local_err pairs, found by rule1? If the latter is correct, that
>>>>> with your script we loss this pair inheritance, and go to all possible
>>>>> combinations of fn and local_err from rule1, possibly adding some wrong
>>>>> conversion (OK, you've checked that no such cases in current code tree).
>>>>
>>>> The chaining "identifier rule1.FOO" is by name.  It's reliable only as
>>>> long as there is exactly one instance of the name.
>>>>
>>>> We already discussed the case of the function name: if there are two
>>>> instances of foo(), and rule1 matches only one of them, then we
>>>> nevertheless apply the rules chained to rule1 to both.  Because that can
>>>> be wrong, you came up with the ___ trick, which chains reliably.
>>>>
>>>> The same issue exists with the variable name: if there are two instances
>>>> of @local_err, and rule1 matches only one of them, then we nevertheless
>>>> apply the rules chained to rule1 to both.  Can also be wrong.
>>>>
>>>> What are the conditions for "wrong"?
>>>>
>>>> Because the ___ chaining is reliable, we know rule1 matched the
>>>> function, i.e. it has a parameter Error **errp, and it has a automatic
>>>> variable Error *local_err = NULL.
>>>>
>>>> We're good as long as *all* identifiers @local_err in this function are
>>>> declared that way.  This seems quite likely.  It's not certain, though.
>>>>
>>>> Since nested declarations of Error ** variables are rare, we can rely on
>>>> review to ensure we transform these functions correctly.
>>>>
>>>>> So, dropping inheritance in check-rules makes sence, as it may match
>>>>> (and warn) more interesting cases.
>>>>>
>>>>> But for other rules, I'd prefere to be safer, and explictly inherit all
>>>>> actually inherited identifiers..
>>>>
>>>> I still can't see what chaining by function name in addition to the ___
>>>> chaining buys us.
>>>
>>> I'll check this thing soon. And resend today.
>
> Checked.
>
> Yes, it inherits pair of fn and local_err, and it definitely makes sense. It more stable.
>
> Consider the following example:
>
> # cat a.c
> int f1(Error **errp)
> {
>     Error *err1 = NULL;
>     int err2 = 0;
>
>     error_propagate(errp, err1);
>
>     return err2;
> }
>
> int f2(Error **errp)
> {
>     Error *err2 = NULL;
>     int err1 = 0;
>
>     error_propagate(errp, err2);
>
>     return err1;
> }
>
>
> My script works correct and produces this change:
> --- a.c
> +++ /tmp/cocci-output-1753-10842a-a.c
> @@ -1,19 +1,15 @@
>  int f1(Error **errp)
>  {
> -    Error *err1 = NULL;
> +    ERRP_AUTO_PROPAGATE();
>      int err2 = 0;
>
> -    error_propagate(errp, err1);
> -
>      return err2;
>  }
>
>  int f2(Error **errp)
>  {
> -    Error *err2 = NULL;
> +    ERRP_AUTO_PROPAGATE();
>      int err1 = 0;
>
> -    error_propagate(errp, err2);
> -
>      return err1;
>  }
>
>
> But yours script is caught:
> --- a.c
> +++ /tmp/cocci-output-1814-b9b681-a.c
> @@ -1,19 +1,15 @@
>  int f1(Error **errp)
>  {
> -    Error *err1 = NULL;
> +    ERRP_AUTO_PROPAGATE();
>      int err2 = 0;
>
> -    error_propagate(errp, err1);
> -
> -    return err2;
> +    return *errp;
>  }
>
>  int f2(Error **errp)
>  {
> -    Error *err2 = NULL;
> +    ERRP_AUTO_PROPAGATE();
>      int err1 = 0;
>
> -    error_propagate(errp, err2);
> -
> -    return err1;
> +    return *errp;
>  }
>
>
> - see, it touches err1, which is unrelated to Error in f2. Hmm,
> interesting that it doesn't want to convert err1 declaration:)
>
> - this is because relation between local_err and fn is lost.

Let me try to think this through.

rule1 matches functions that propagate from a local variable @local_err
to parameter @errp.  It uses the ___ hack to reliably tag the function.
Later rules that should only apply to these functions can match ___.

These later rules each provide a part of the total error propagation
transformation.  They must transform exactly the @local_err and @errp
matched by rule1 in each function.

Your solution is to constrain the identifiers, i.e.

    identifier rule1.fn, rule1.local_err;

If rule1 matches only one function named foo(), and within that foo()
the local variable @local_err rule1 matches actually binds all
occurences of the identifier @local_err, the constraint is reliable.

Else, the constraint may still accept occurences of @local_err not bound
to the variable matched by rule1.

Example 1:

    int bar(Error **errp)
    {
        if (pred()) {
            Error *local_err = NULL;

            error_setg(&local_err, "zzzt");
            error_propagate(errp, local_err);
        } else {
            int local_err = 0;
            return local_err;
        }
        return 0;
    }

rule1 matches the first @local_err variable, and not the second one.  We
must transform occurences of the first one, and not occurences of the
second one.  We do transform all:

     int bar(Error **errp)
     {
    +    ERRP_AUTO_PROPAGATE();
         if (pred()) {
    -        Error *local_err = NULL;
    -
    -        error_setg(&local_err, "zzzt");
    -        error_propagate(errp, local_err);
    +        error_setg(errp, "zzzt");
         } else {
             int local_err = 0;
    -        return local_err;
    +        return *errp;
         }
         return 0;
     }

Example 2:

    int foo(Error **errp)
    {
        Error *local_err = NULL;

        error_setg(&local_err, "zzzt");
        error_propagate(errp, local_err);
        return 0;
    }

    int foo(Error **errp)
    {
        Error *err = NULL;
        int local_err = 0;

        error_setg(&local_err, "zzzt");
        error_propagate(errp, err);
        return local_err;
    }

rule1 matches @local_err in the first foo(), and @err in the second one.
We must transform @local_err in the first one(), and @err in the second
one.  We do transform both in both:

     int foo(Error **errp)
     {
    -    Error *local_err = NULL;
    +    ERRP_AUTO_PROPAGATE();

    -    error_setg(&local_err, "zzzt");
    -    error_propagate(errp, local_err);
    +    error_setg(errp, "zzzt");
         return 0;
     }

     int foo(Error **errp)
     {
    -    Error *err = NULL;
    +    ERRP_AUTO_PROPAGATE();
         int local_err = 0;

    -    error_setg(&local_err, "zzzt");
    -    error_propagate(errp, err);
    -    return local_err;
    +    error_setg(errp, "zzzt");
    +    return *errp;
     }

Constraining only the variable identifier like I proposed is even less
reliable, as you demonstrated: then the issue in example 2 exists even
for differently named functions.

For a reliable solution, we could use perhaps use the ___ hack again:
have rule1 rename @local_err it actually matches.  But to be honest, my
appetite for another round of wrestling with Coccinelle isn't what it
used to be.

I think we can do without as long as we're well aware of the script's
limitations, and we're confident we can detect problematic cases.

Detecting transformation of multiple functions with the same name should
be easy.

Detecting occurences of identifiers not bound by a certain variable
should be feasible: we find and review every transformed function that
doesn't declare the variable in its outermost scope.

Since "well aware" is going to erode with time, we may want to delete
the script when we're done converting.

> So, understanding that there no such cases in the whole tree, and even
> if your patch works faster on the whole tree, I still don't want to
> drop inheritance, because it's just a correct thing to do. Yes, we've
> added ____ helper. It helps to avoid some problems. Pair-inheritance
> helps to avoid another problems. I understand, that there still may
> other, not-covered problems, but better to be as safe as possible. And
> inheritance here is native and correct thing to do, even with our ____
> additional helper. What do you think?

I wouldn't call it correct.  It's still unreliable, but less so than
without the function name constraint.  That makes it less wrong.

100% reliable would be nice, but not at any cost.  Something we're
reasonably confident to get right should be good enough.

To be confident, we need to understand the script's limitations, and how
to compensate for them.  I figure we do now.  You too?

[...]


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-19 10:45                         ` [Xen-devel] " Markus Armbruster
@ 2020-03-19 12:12                           ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-19 12:12 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

19.03.2020 13:45, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> 17.03.2020 13:39, Markus Armbruster wrote:
>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>
>>>> 16.03.2020 11:21, Markus Armbruster wrote:
>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>
>>>>>> On 14.03.2020 00:54, Markus Armbruster wrote:
>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>>
>>>>>>>> 13.03.2020 18:42, Markus Armbruster wrote:
>>>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>>>>
>>>>>>>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>>>>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>>>>>>>> out now as is.
>>>>>>>>>>>
>>>>>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>> [...]
>>>>>>>>>>>> +@@
>>>>>>>>>>>> +
>>>>>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>>>>>> + {
>>>>>>>>>>>> +     ...
>>>>>>>>>>>> +     Error *local_err = NULL;
>>>>>>>>>>>> +     ... when any
>>>>>>>>>>>> +     Error *local_err2 = NULL;
>>>>>>>>>>>> +     ... when any
>>>>>>>>>>>> + }
>>>>>>>
>>>>>>> This flags functions that have more than one declaration along any
>>>>>>> control flow path.  It doesn't flag this one:
>>>>>>>
>>>>>>>         void gnat(bool b, Error **errp)
>>>>>>>         {
>>>>>>>             if (b) {
>>>>>>>                 Error *local_err = NULL;
>>>>>>>                 foo(arg, &local_err);
>>>>>>>                 error_propagate(errp, local_err);
>>>>>>>             } else {
>>>>>>>                 Error *local_err = NULL;
>>>>>>>                 bar(arg, &local_err);
>>>>>>>                 error_propagate(errp, local_err);
>>>>>>>             }
>>>>>>>         }
>>>>>>>
>>>>>>> The Coccinelle script does the right thing for this one regardless.
>>>>>>>
>>>>>>> I'd prefer to have such functions flagged, too.  But spending time on
>>>>>>> convincing Coccinelle to do it for me is not worthwhile; I can simply
>>>>>>> search the diff produced by Coccinelle for deletions of declarations
>>>>>>> that are not indented exactly four spaces.
>>>>>>>
>>>>>>> But if we keep this rule, we should adjust its comment
>>>>>>>
>>>>>>>         // Warn several Error * definitions.
>>>>>>>
>>>>>>> because it sure suggests it also catches functions like the one I gave
>>>>>>> above.
>>>>>>
>>>>>> Hmm, yes.. We can write "Warn several Error * definitions in _one_
>>>>>> control flow (it's not so trivial to match _any_ case with several
>>>>>> definitions with coccinelle)" or something like this.
>>>>>
>>>>> Ha, "trivial" reminds me of a story.  The math professor, after having
>>>>> spent a good chunk of his lecture developing a proof on the blackboad
>>>>> turns to the audience to explain why this little part doesn't require
>>>>> proof with the words familiar to any math student "and this is trivial."
>>>>> Pause, puzzled look...  "Is it trivial?"  Pause, storms out of the
>>>>> lecture hall.  A minute or three pass.  Professor comes back beaming,
>>>>> "it is trivial!", and proceeds with the proof.
>>>>>
>>>>> My point is: it might be trivial with Coccinelle once you know how to do
>>>>> it.  We don't.
>>>>>
>>>>> Suggest "(can't figure out how to match several definitions regardless
>>>>> of control flow)".
>>>>
>>>> Wrong too, because I can:) for example, chaining two rules, catching the
>>>> positions of definition and check that they are different.. Or, some
>>>> cheating with python script.. That's why I wrote "not trivial",
>>>>
>>>> So, most correct would be "(can't figure out how to simply match several definitions regardless
>>>>> of control flow)".
>>>
>>> Works for me.
>>>
>>>> But again, coccinelle is for matching control flows, so its probably impossible to match such thing..
>>> [...]
>>>>>> OK, I almost OK with it, the only thing I doubt a bit is the following:
>>>>>>
>>>>>> We want to keep rule1.local_err inheritance to keep connection with
>>>>>> local_err definition.
>>>>>
>>>>> Yes.
>>>>>
>>>>>> Interesting, when we have both rule1.fn and rule1.local_err inherited,
>>>>>> do we inherit them in separate (i.e. all possible combinations of fn
>>>>>> and local_err symbols from rule1) or do we inherit a pair, i.e. only
>>>>>> fn/local_err pairs, found by rule1? If the latter is correct, that
>>>>>> with your script we loss this pair inheritance, and go to all possible
>>>>>> combinations of fn and local_err from rule1, possibly adding some wrong
>>>>>> conversion (OK, you've checked that no such cases in current code tree).
>>>>>
>>>>> The chaining "identifier rule1.FOO" is by name.  It's reliable only as
>>>>> long as there is exactly one instance of the name.
>>>>>
>>>>> We already discussed the case of the function name: if there are two
>>>>> instances of foo(), and rule1 matches only one of them, then we
>>>>> nevertheless apply the rules chained to rule1 to both.  Because that can
>>>>> be wrong, you came up with the ___ trick, which chains reliably.
>>>>>
>>>>> The same issue exists with the variable name: if there are two instances
>>>>> of @local_err, and rule1 matches only one of them, then we nevertheless
>>>>> apply the rules chained to rule1 to both.  Can also be wrong.
>>>>>
>>>>> What are the conditions for "wrong"?
>>>>>
>>>>> Because the ___ chaining is reliable, we know rule1 matched the
>>>>> function, i.e. it has a parameter Error **errp, and it has a automatic
>>>>> variable Error *local_err = NULL.
>>>>>
>>>>> We're good as long as *all* identifiers @local_err in this function are
>>>>> declared that way.  This seems quite likely.  It's not certain, though.
>>>>>
>>>>> Since nested declarations of Error ** variables are rare, we can rely on
>>>>> review to ensure we transform these functions correctly.
>>>>>
>>>>>> So, dropping inheritance in check-rules makes sence, as it may match
>>>>>> (and warn) more interesting cases.
>>>>>>
>>>>>> But for other rules, I'd prefere to be safer, and explictly inherit all
>>>>>> actually inherited identifiers..
>>>>>
>>>>> I still can't see what chaining by function name in addition to the ___
>>>>> chaining buys us.
>>>>
>>>> I'll check this thing soon. And resend today.
>>
>> Checked.
>>
>> Yes, it inherits pair of fn and local_err, and it definitely makes sense. It more stable.
>>
>> Consider the following example:
>>
>> # cat a.c
>> int f1(Error **errp)
>> {
>>      Error *err1 = NULL;
>>      int err2 = 0;
>>
>>      error_propagate(errp, err1);
>>
>>      return err2;
>> }
>>
>> int f2(Error **errp)
>> {
>>      Error *err2 = NULL;
>>      int err1 = 0;
>>
>>      error_propagate(errp, err2);
>>
>>      return err1;
>> }
>>
>>
>> My script works correct and produces this change:
>> --- a.c
>> +++ /tmp/cocci-output-1753-10842a-a.c
>> @@ -1,19 +1,15 @@
>>   int f1(Error **errp)
>>   {
>> -    Error *err1 = NULL;
>> +    ERRP_AUTO_PROPAGATE();
>>       int err2 = 0;
>>
>> -    error_propagate(errp, err1);
>> -
>>       return err2;
>>   }
>>
>>   int f2(Error **errp)
>>   {
>> -    Error *err2 = NULL;
>> +    ERRP_AUTO_PROPAGATE();
>>       int err1 = 0;
>>
>> -    error_propagate(errp, err2);
>> -
>>       return err1;
>>   }
>>
>>
>> But yours script is caught:
>> --- a.c
>> +++ /tmp/cocci-output-1814-b9b681-a.c
>> @@ -1,19 +1,15 @@
>>   int f1(Error **errp)
>>   {
>> -    Error *err1 = NULL;
>> +    ERRP_AUTO_PROPAGATE();
>>       int err2 = 0;
>>
>> -    error_propagate(errp, err1);
>> -
>> -    return err2;
>> +    return *errp;
>>   }
>>
>>   int f2(Error **errp)
>>   {
>> -    Error *err2 = NULL;
>> +    ERRP_AUTO_PROPAGATE();
>>       int err1 = 0;
>>
>> -    error_propagate(errp, err2);
>> -
>> -    return err1;
>> +    return *errp;
>>   }
>>
>>
>> - see, it touches err1, which is unrelated to Error in f2. Hmm,
>> interesting that it doesn't want to convert err1 declaration:)
>>
>> - this is because relation between local_err and fn is lost.
> 
> Let me try to think this through.
> 
> rule1 matches functions that propagate from a local variable @local_err
> to parameter @errp.  It uses the ___ hack to reliably tag the function.
> Later rules that should only apply to these functions can match ___.
> 
> These later rules each provide a part of the total error propagation
> transformation.  They must transform exactly the @local_err and @errp
> matched by rule1 in each function.
> 
> Your solution is to constrain the identifiers, i.e.
> 
>      identifier rule1.fn, rule1.local_err;
> 
> If rule1 matches only one function named foo(), and within that foo()
> the local variable @local_err rule1 matches actually binds all
> occurences of the identifier @local_err, the constraint is reliable.
> 
> Else, the constraint may still accept occurences of @local_err not bound
> to the variable matched by rule1.
> 
> Example 1:
> 
>      int bar(Error **errp)
>      {
>          if (pred()) {
>              Error *local_err = NULL;
> 
>              error_setg(&local_err, "zzzt");
>              error_propagate(errp, local_err);
>          } else {
>              int local_err = 0;
>              return local_err;
>          }
>          return 0;
>      }
> 
> rule1 matches the first @local_err variable, and not the second one.  We
> must transform occurences of the first one, and not occurences of the
> second one.  We do transform all:
> 
>       int bar(Error **errp)
>       {
>      +    ERRP_AUTO_PROPAGATE();
>           if (pred()) {
>      -        Error *local_err = NULL;
>      -
>      -        error_setg(&local_err, "zzzt");
>      -        error_propagate(errp, local_err);
>      +        error_setg(errp, "zzzt");
>           } else {
>               int local_err = 0;
>      -        return local_err;
>      +        return *errp;
>           }
>           return 0;
>       }
> 

Aha, good example. And we even do not warn it.

> Example 2:
> 
>      int foo(Error **errp)
>      {
>          Error *local_err = NULL;
> 
>          error_setg(&local_err, "zzzt");
>          error_propagate(errp, local_err);
>          return 0;
>      }
> 
>      int foo(Error **errp)
>      {
>          Error *err = NULL;
>          int local_err = 0;
> 
>          error_setg(&local_err, "zzzt");
>          error_propagate(errp, err);
>          return local_err;
>      }
> 
> rule1 matches @local_err in the first foo(), and @err in the second one.
> We must transform @local_err in the first one(), and @err in the second
> one.  We do transform both in both:
> 
>       int foo(Error **errp)
>       {
>      -    Error *local_err = NULL;
>      +    ERRP_AUTO_PROPAGATE();
> 
>      -    error_setg(&local_err, "zzzt");
>      -    error_propagate(errp, local_err);
>      +    error_setg(errp, "zzzt");
>           return 0;
>       }
> 
>       int foo(Error **errp)
>       {
>      -    Error *err = NULL;
>      +    ERRP_AUTO_PROPAGATE();
>           int local_err = 0;
> 
>      -    error_setg(&local_err, "zzzt");
>      -    error_propagate(errp, err);
>      -    return local_err;
>      +    error_setg(errp, "zzzt");
>      +    return *errp;
>       }
> 
> Constraining only the variable identifier like I proposed is even less
> reliable, as you demonstrated: then the issue in example 2 exists even
> for differently named functions.
> 
> For a reliable solution, we could use perhaps use the ___ hack again:
> have rule1 rename @local_err it actually matches. But to be honest, my
> appetite for another round of wrestling with Coccinelle isn't what it
> used to be. >
> I think we can do without as long as we're well aware of the script's
> limitations, and we're confident we can detect problematic cases.
> 
> Detecting transformation of multiple functions with the same name should
> be easy.
> 
> Detecting occurences of identifiers not bound by a certain variable
> should be feasible: we find and review every transformed function that
> doesn't declare the variable in its outermost scope.
> 
> Since "well aware" is going to erode with time, we may want to delete
> the script when we're done converting.
> 
>> So, understanding that there no such cases in the whole tree, and even
>> if your patch works faster on the whole tree, I still don't want to
>> drop inheritance, because it's just a correct thing to do. Yes, we've
>> added ____ helper. It helps to avoid some problems. Pair-inheritance
>> helps to avoid another problems. I understand, that there still may
>> other, not-covered problems, but better to be as safe as possible. And
>> inheritance here is native and correct thing to do, even with our ____
>> additional helper. What do you think?
> 
> I wouldn't call it correct.  It's still unreliable, but less so than
> without the function name constraint.  That makes it less wrong.

Agree.

> 
> 100% reliable would be nice, but not at any cost.  Something we're
> reasonably confident to get right should be good enough.
> 
> To be confident, we need to understand the script's limitations, and how
> to compensate for them.  I figure we do now.  You too?
> 

I will not be surprised, if we missed some more interesting cases :)
But we should proceed. What is our plan? Will you queue v10 for 5.1?

-- 
Best regards,
Vladimir


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-19 12:12                           ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-19 12:12 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

19.03.2020 13:45, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> 17.03.2020 13:39, Markus Armbruster wrote:
>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>
>>>> 16.03.2020 11:21, Markus Armbruster wrote:
>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>
>>>>>> On 14.03.2020 00:54, Markus Armbruster wrote:
>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>>
>>>>>>>> 13.03.2020 18:42, Markus Armbruster wrote:
>>>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>>>>>>>>
>>>>>>>>>> 12.03.2020 19:36, Markus Armbruster wrote:
>>>>>>>>>>> I may have a second look tomorrow with fresher eyes, but let's get this
>>>>>>>>>>> out now as is.
>>>>>>>>>>>
>>>>>>>>>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
>>> [...]
>>>>>>>>>>>> +@@
>>>>>>>>>>>> +
>>>>>>>>>>>> + fn(..., Error ** ____, ...)
>>>>>>>>>>>> + {
>>>>>>>>>>>> +     ...
>>>>>>>>>>>> +     Error *local_err = NULL;
>>>>>>>>>>>> +     ... when any
>>>>>>>>>>>> +     Error *local_err2 = NULL;
>>>>>>>>>>>> +     ... when any
>>>>>>>>>>>> + }
>>>>>>>
>>>>>>> This flags functions that have more than one declaration along any
>>>>>>> control flow path.  It doesn't flag this one:
>>>>>>>
>>>>>>>         void gnat(bool b, Error **errp)
>>>>>>>         {
>>>>>>>             if (b) {
>>>>>>>                 Error *local_err = NULL;
>>>>>>>                 foo(arg, &local_err);
>>>>>>>                 error_propagate(errp, local_err);
>>>>>>>             } else {
>>>>>>>                 Error *local_err = NULL;
>>>>>>>                 bar(arg, &local_err);
>>>>>>>                 error_propagate(errp, local_err);
>>>>>>>             }
>>>>>>>         }
>>>>>>>
>>>>>>> The Coccinelle script does the right thing for this one regardless.
>>>>>>>
>>>>>>> I'd prefer to have such functions flagged, too.  But spending time on
>>>>>>> convincing Coccinelle to do it for me is not worthwhile; I can simply
>>>>>>> search the diff produced by Coccinelle for deletions of declarations
>>>>>>> that are not indented exactly four spaces.
>>>>>>>
>>>>>>> But if we keep this rule, we should adjust its comment
>>>>>>>
>>>>>>>         // Warn several Error * definitions.
>>>>>>>
>>>>>>> because it sure suggests it also catches functions like the one I gave
>>>>>>> above.
>>>>>>
>>>>>> Hmm, yes.. We can write "Warn several Error * definitions in _one_
>>>>>> control flow (it's not so trivial to match _any_ case with several
>>>>>> definitions with coccinelle)" or something like this.
>>>>>
>>>>> Ha, "trivial" reminds me of a story.  The math professor, after having
>>>>> spent a good chunk of his lecture developing a proof on the blackboad
>>>>> turns to the audience to explain why this little part doesn't require
>>>>> proof with the words familiar to any math student "and this is trivial."
>>>>> Pause, puzzled look...  "Is it trivial?"  Pause, storms out of the
>>>>> lecture hall.  A minute or three pass.  Professor comes back beaming,
>>>>> "it is trivial!", and proceeds with the proof.
>>>>>
>>>>> My point is: it might be trivial with Coccinelle once you know how to do
>>>>> it.  We don't.
>>>>>
>>>>> Suggest "(can't figure out how to match several definitions regardless
>>>>> of control flow)".
>>>>
>>>> Wrong too, because I can:) for example, chaining two rules, catching the
>>>> positions of definition and check that they are different.. Or, some
>>>> cheating with python script.. That's why I wrote "not trivial",
>>>>
>>>> So, most correct would be "(can't figure out how to simply match several definitions regardless
>>>>> of control flow)".
>>>
>>> Works for me.
>>>
>>>> But again, coccinelle is for matching control flows, so its probably impossible to match such thing..
>>> [...]
>>>>>> OK, I almost OK with it, the only thing I doubt a bit is the following:
>>>>>>
>>>>>> We want to keep rule1.local_err inheritance to keep connection with
>>>>>> local_err definition.
>>>>>
>>>>> Yes.
>>>>>
>>>>>> Interesting, when we have both rule1.fn and rule1.local_err inherited,
>>>>>> do we inherit them in separate (i.e. all possible combinations of fn
>>>>>> and local_err symbols from rule1) or do we inherit a pair, i.e. only
>>>>>> fn/local_err pairs, found by rule1? If the latter is correct, that
>>>>>> with your script we loss this pair inheritance, and go to all possible
>>>>>> combinations of fn and local_err from rule1, possibly adding some wrong
>>>>>> conversion (OK, you've checked that no such cases in current code tree).
>>>>>
>>>>> The chaining "identifier rule1.FOO" is by name.  It's reliable only as
>>>>> long as there is exactly one instance of the name.
>>>>>
>>>>> We already discussed the case of the function name: if there are two
>>>>> instances of foo(), and rule1 matches only one of them, then we
>>>>> nevertheless apply the rules chained to rule1 to both.  Because that can
>>>>> be wrong, you came up with the ___ trick, which chains reliably.
>>>>>
>>>>> The same issue exists with the variable name: if there are two instances
>>>>> of @local_err, and rule1 matches only one of them, then we nevertheless
>>>>> apply the rules chained to rule1 to both.  Can also be wrong.
>>>>>
>>>>> What are the conditions for "wrong"?
>>>>>
>>>>> Because the ___ chaining is reliable, we know rule1 matched the
>>>>> function, i.e. it has a parameter Error **errp, and it has a automatic
>>>>> variable Error *local_err = NULL.
>>>>>
>>>>> We're good as long as *all* identifiers @local_err in this function are
>>>>> declared that way.  This seems quite likely.  It's not certain, though.
>>>>>
>>>>> Since nested declarations of Error ** variables are rare, we can rely on
>>>>> review to ensure we transform these functions correctly.
>>>>>
>>>>>> So, dropping inheritance in check-rules makes sence, as it may match
>>>>>> (and warn) more interesting cases.
>>>>>>
>>>>>> But for other rules, I'd prefere to be safer, and explictly inherit all
>>>>>> actually inherited identifiers..
>>>>>
>>>>> I still can't see what chaining by function name in addition to the ___
>>>>> chaining buys us.
>>>>
>>>> I'll check this thing soon. And resend today.
>>
>> Checked.
>>
>> Yes, it inherits pair of fn and local_err, and it definitely makes sense. It more stable.
>>
>> Consider the following example:
>>
>> # cat a.c
>> int f1(Error **errp)
>> {
>>      Error *err1 = NULL;
>>      int err2 = 0;
>>
>>      error_propagate(errp, err1);
>>
>>      return err2;
>> }
>>
>> int f2(Error **errp)
>> {
>>      Error *err2 = NULL;
>>      int err1 = 0;
>>
>>      error_propagate(errp, err2);
>>
>>      return err1;
>> }
>>
>>
>> My script works correct and produces this change:
>> --- a.c
>> +++ /tmp/cocci-output-1753-10842a-a.c
>> @@ -1,19 +1,15 @@
>>   int f1(Error **errp)
>>   {
>> -    Error *err1 = NULL;
>> +    ERRP_AUTO_PROPAGATE();
>>       int err2 = 0;
>>
>> -    error_propagate(errp, err1);
>> -
>>       return err2;
>>   }
>>
>>   int f2(Error **errp)
>>   {
>> -    Error *err2 = NULL;
>> +    ERRP_AUTO_PROPAGATE();
>>       int err1 = 0;
>>
>> -    error_propagate(errp, err2);
>> -
>>       return err1;
>>   }
>>
>>
>> But yours script is caught:
>> --- a.c
>> +++ /tmp/cocci-output-1814-b9b681-a.c
>> @@ -1,19 +1,15 @@
>>   int f1(Error **errp)
>>   {
>> -    Error *err1 = NULL;
>> +    ERRP_AUTO_PROPAGATE();
>>       int err2 = 0;
>>
>> -    error_propagate(errp, err1);
>> -
>> -    return err2;
>> +    return *errp;
>>   }
>>
>>   int f2(Error **errp)
>>   {
>> -    Error *err2 = NULL;
>> +    ERRP_AUTO_PROPAGATE();
>>       int err1 = 0;
>>
>> -    error_propagate(errp, err2);
>> -
>> -    return err1;
>> +    return *errp;
>>   }
>>
>>
>> - see, it touches err1, which is unrelated to Error in f2. Hmm,
>> interesting that it doesn't want to convert err1 declaration:)
>>
>> - this is because relation between local_err and fn is lost.
> 
> Let me try to think this through.
> 
> rule1 matches functions that propagate from a local variable @local_err
> to parameter @errp.  It uses the ___ hack to reliably tag the function.
> Later rules that should only apply to these functions can match ___.
> 
> These later rules each provide a part of the total error propagation
> transformation.  They must transform exactly the @local_err and @errp
> matched by rule1 in each function.
> 
> Your solution is to constrain the identifiers, i.e.
> 
>      identifier rule1.fn, rule1.local_err;
> 
> If rule1 matches only one function named foo(), and within that foo()
> the local variable @local_err rule1 matches actually binds all
> occurences of the identifier @local_err, the constraint is reliable.
> 
> Else, the constraint may still accept occurences of @local_err not bound
> to the variable matched by rule1.
> 
> Example 1:
> 
>      int bar(Error **errp)
>      {
>          if (pred()) {
>              Error *local_err = NULL;
> 
>              error_setg(&local_err, "zzzt");
>              error_propagate(errp, local_err);
>          } else {
>              int local_err = 0;
>              return local_err;
>          }
>          return 0;
>      }
> 
> rule1 matches the first @local_err variable, and not the second one.  We
> must transform occurences of the first one, and not occurences of the
> second one.  We do transform all:
> 
>       int bar(Error **errp)
>       {
>      +    ERRP_AUTO_PROPAGATE();
>           if (pred()) {
>      -        Error *local_err = NULL;
>      -
>      -        error_setg(&local_err, "zzzt");
>      -        error_propagate(errp, local_err);
>      +        error_setg(errp, "zzzt");
>           } else {
>               int local_err = 0;
>      -        return local_err;
>      +        return *errp;
>           }
>           return 0;
>       }
> 

Aha, good example. And we even do not warn it.

> Example 2:
> 
>      int foo(Error **errp)
>      {
>          Error *local_err = NULL;
> 
>          error_setg(&local_err, "zzzt");
>          error_propagate(errp, local_err);
>          return 0;
>      }
> 
>      int foo(Error **errp)
>      {
>          Error *err = NULL;
>          int local_err = 0;
> 
>          error_setg(&local_err, "zzzt");
>          error_propagate(errp, err);
>          return local_err;
>      }
> 
> rule1 matches @local_err in the first foo(), and @err in the second one.
> We must transform @local_err in the first one(), and @err in the second
> one.  We do transform both in both:
> 
>       int foo(Error **errp)
>       {
>      -    Error *local_err = NULL;
>      +    ERRP_AUTO_PROPAGATE();
> 
>      -    error_setg(&local_err, "zzzt");
>      -    error_propagate(errp, local_err);
>      +    error_setg(errp, "zzzt");
>           return 0;
>       }
> 
>       int foo(Error **errp)
>       {
>      -    Error *err = NULL;
>      +    ERRP_AUTO_PROPAGATE();
>           int local_err = 0;
> 
>      -    error_setg(&local_err, "zzzt");
>      -    error_propagate(errp, err);
>      -    return local_err;
>      +    error_setg(errp, "zzzt");
>      +    return *errp;
>       }
> 
> Constraining only the variable identifier like I proposed is even less
> reliable, as you demonstrated: then the issue in example 2 exists even
> for differently named functions.
> 
> For a reliable solution, we could use perhaps use the ___ hack again:
> have rule1 rename @local_err it actually matches. But to be honest, my
> appetite for another round of wrestling with Coccinelle isn't what it
> used to be. >
> I think we can do without as long as we're well aware of the script's
> limitations, and we're confident we can detect problematic cases.
> 
> Detecting transformation of multiple functions with the same name should
> be easy.
> 
> Detecting occurences of identifiers not bound by a certain variable
> should be feasible: we find and review every transformed function that
> doesn't declare the variable in its outermost scope.
> 
> Since "well aware" is going to erode with time, we may want to delete
> the script when we're done converting.
> 
>> So, understanding that there no such cases in the whole tree, and even
>> if your patch works faster on the whole tree, I still don't want to
>> drop inheritance, because it's just a correct thing to do. Yes, we've
>> added ____ helper. It helps to avoid some problems. Pair-inheritance
>> helps to avoid another problems. I understand, that there still may
>> other, not-covered problems, but better to be as safe as possible. And
>> inheritance here is native and correct thing to do, even with our ____
>> additional helper. What do you think?
> 
> I wouldn't call it correct.  It's still unreliable, but less so than
> without the function name constraint.  That makes it less wrong.

Agree.

> 
> 100% reliable would be nice, but not at any cost.  Something we're
> reasonably confident to get right should be good enough.
> 
> To be confident, we need to understand the script's limitations, and how
> to compensate for them.  I figure we do now.  You too?
> 

I will not be surprised, if we missed some more interesting cases :)
But we should proceed. What is our plan? Will you queue v10 for 5.1?

-- 
Best regards,
Vladimir

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-19 12:12                           ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-20 13:58                             ` Markus Armbruster
  -1 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-20 13:58 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Laszlo Ersek, Christian Schoenebeck, Michael Roth, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 19.03.2020 13:45, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
[...]
>>> So, understanding that there no such cases in the whole tree, and even
>>> if your patch works faster on the whole tree, I still don't want to
>>> drop inheritance, because it's just a correct thing to do. Yes, we've
>>> added ____ helper. It helps to avoid some problems. Pair-inheritance
>>> helps to avoid another problems. I understand, that there still may
>>> other, not-covered problems, but better to be as safe as possible. And
>>> inheritance here is native and correct thing to do, even with our ____
>>> additional helper. What do you think?
>>
>> I wouldn't call it correct.  It's still unreliable, but less so than
>> without the function name constraint.  That makes it less wrong.
>
> Agree.
>
>>
>> 100% reliable would be nice, but not at any cost.  Something we're
>> reasonably confident to get right should be good enough.
>>
>> To be confident, we need to understand the script's limitations, and how
>> to compensate for them.  I figure we do now.  You too?
>>
>
> I will not be surprised, if we missed some more interesting cases :)
> But we should proceed. What is our plan? Will you queue v10 for 5.1?

v10's PATCH 1+2 look ready.  The error.h comment update could perhaps
use some polish; I've focused my attention elsewhere.

PATCH 8-9 are generated.  They should never be rebased, always be
regenerated.  We compare regenerated patches to posted ones to make sure
they are still sane, and the R-bys are still valid.  I can take care of
the comparing.

I'd like to have a pull request ready when the tree reopens for general
development.  Let's use the time until then to get more generated
patches out for review.

If I queue up patches in my tree, we shift the responsibility for
regenerating patches from you to me, and create a coordination issue:
you'll want to base patch submissions on the branch I use to queue this
work, and that's going to be awkward when I rebase / regenerate that
branch.  I think it's simpler to queue up in your tree until we're ready
for a pull request.

When you post more patches, use

    Based-on: <20200317151625.20797-1-vsementsov@virtuozzo.com>

so that Patchew applies them on top of this series.  Hmm, probably won't
do, as PATCH 9 already conflicts.

You could instead repost PATCH 1+2 with each batch.  I hope that's not
too confusing.

I trust you'll keep providing a tag reviewers can pull.

I suggest to ask maintainers to leave merging these patches to me, in
cover letters.

Makes sense?



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-20 13:58                             ` Markus Armbruster
  0 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-20 13:58 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Laszlo Ersek, Christian Schoenebeck, Michael Roth, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 19.03.2020 13:45, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
[...]
>>> So, understanding that there no such cases in the whole tree, and even
>>> if your patch works faster on the whole tree, I still don't want to
>>> drop inheritance, because it's just a correct thing to do. Yes, we've
>>> added ____ helper. It helps to avoid some problems. Pair-inheritance
>>> helps to avoid another problems. I understand, that there still may
>>> other, not-covered problems, but better to be as safe as possible. And
>>> inheritance here is native and correct thing to do, even with our ____
>>> additional helper. What do you think?
>>
>> I wouldn't call it correct.  It's still unreliable, but less so than
>> without the function name constraint.  That makes it less wrong.
>
> Agree.
>
>>
>> 100% reliable would be nice, but not at any cost.  Something we're
>> reasonably confident to get right should be good enough.
>>
>> To be confident, we need to understand the script's limitations, and how
>> to compensate for them.  I figure we do now.  You too?
>>
>
> I will not be surprised, if we missed some more interesting cases :)
> But we should proceed. What is our plan? Will you queue v10 for 5.1?

v10's PATCH 1+2 look ready.  The error.h comment update could perhaps
use some polish; I've focused my attention elsewhere.

PATCH 8-9 are generated.  They should never be rebased, always be
regenerated.  We compare regenerated patches to posted ones to make sure
they are still sane, and the R-bys are still valid.  I can take care of
the comparing.

I'd like to have a pull request ready when the tree reopens for general
development.  Let's use the time until then to get more generated
patches out for review.

If I queue up patches in my tree, we shift the responsibility for
regenerating patches from you to me, and create a coordination issue:
you'll want to base patch submissions on the branch I use to queue this
work, and that's going to be awkward when I rebase / regenerate that
branch.  I think it's simpler to queue up in your tree until we're ready
for a pull request.

When you post more patches, use

    Based-on: <20200317151625.20797-1-vsementsov@virtuozzo.com>

so that Patchew applies them on top of this series.  Hmm, probably won't
do, as PATCH 9 already conflicts.

You could instead repost PATCH 1+2 with each batch.  I hope that's not
too confusing.

I trust you'll keep providing a tag reviewers can pull.

I suggest to ask maintainers to leave merging these patches to me, in
cover letters.

Makes sense?


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-20 13:58                             ` [Xen-devel] " Markus Armbruster
@ 2020-03-20 14:36                               ` Vladimir Sementsov-Ogievskiy
  -1 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-20 14:36 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Laszlo Ersek, Christian Schoenebeck, Michael Roth, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

20.03.2020 16:58, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> 19.03.2020 13:45, Markus Armbruster wrote:
>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> [...]
>>>> So, understanding that there no such cases in the whole tree, and even
>>>> if your patch works faster on the whole tree, I still don't want to
>>>> drop inheritance, because it's just a correct thing to do. Yes, we've
>>>> added ____ helper. It helps to avoid some problems. Pair-inheritance
>>>> helps to avoid another problems. I understand, that there still may
>>>> other, not-covered problems, but better to be as safe as possible. And
>>>> inheritance here is native and correct thing to do, even with our ____
>>>> additional helper. What do you think?
>>>
>>> I wouldn't call it correct.  It's still unreliable, but less so than
>>> without the function name constraint.  That makes it less wrong.
>>
>> Agree.
>>
>>>
>>> 100% reliable would be nice, but not at any cost.  Something we're
>>> reasonably confident to get right should be good enough.
>>>
>>> To be confident, we need to understand the script's limitations, and how
>>> to compensate for them.  I figure we do now.  You too?
>>>
>>
>> I will not be surprised, if we missed some more interesting cases :)
>> But we should proceed. What is our plan? Will you queue v10 for 5.1?
> 
> v10's PATCH 1+2 look ready.  The error.h comment update could perhaps
> use some polish; I've focused my attention elsewhere.
> 
> PATCH 8-9 are generated.  They should never be rebased, always be
> regenerated.  We compare regenerated patches to posted ones to make sure
> they are still sane, and the R-bys are still valid.  I can take care of
> the comparing.
> 
> I'd like to have a pull request ready when the tree reopens for general
> development.  Let's use the time until then to get more generated
> patches out for review.
> 
> If I queue up patches in my tree, we shift the responsibility for
> regenerating patches from you to me, and create a coordination issue:
> you'll want to base patch submissions on the branch I use to queue this
> work, and that's going to be awkward when I rebase / regenerate that
> branch.  I think it's simpler to queue up in your tree until we're ready
> for a pull request.
> 
> When you post more patches, use
> 
>      Based-on: <20200317151625.20797-1-vsementsov@virtuozzo.com>
> 
> so that Patchew applies them on top of this series.  Hmm, probably won't
> do, as PATCH 9 already conflicts.
> 
> You could instead repost PATCH 1+2 with each batch.  I hope that's not
> too confusing.
> 
> I trust you'll keep providing a tag reviewers can pull.
> 
> I suggest to ask maintainers to leave merging these patches to me, in
> cover letters.
> 
> Makes sense?
> 

Hmm.

I remember what Kevin said about freeze period: maintainers will queue
a lot of patches in their "next" branches, and send pull requests at start
of next developing period. This highly possible will drop r-bs I can get now.
And reviewers will have to review twice.

And for the same reason, it's bad idea to queue in your branch a lot of patches
from different subsystems during freeze.

So, just postpone this all up to next development phase?


-- 
Best regards,
Vladimir


^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-20 14:36                               ` Vladimir Sementsov-Ogievskiy
  0 siblings, 0 replies; 67+ messages in thread
From: Vladimir Sementsov-Ogievskiy @ 2020-03-20 14:36 UTC (permalink / raw)
  To: Markus Armbruster
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Laszlo Ersek, Christian Schoenebeck, Michael Roth, qemu-devel,
	Greg Kurz, Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard,
	xen-devel, Max Reitz, Philippe Mathieu-Daudé,
	Stefan Berger

20.03.2020 16:58, Markus Armbruster wrote:
> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> 
>> 19.03.2020 13:45, Markus Armbruster wrote:
>>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
> [...]
>>>> So, understanding that there no such cases in the whole tree, and even
>>>> if your patch works faster on the whole tree, I still don't want to
>>>> drop inheritance, because it's just a correct thing to do. Yes, we've
>>>> added ____ helper. It helps to avoid some problems. Pair-inheritance
>>>> helps to avoid another problems. I understand, that there still may
>>>> other, not-covered problems, but better to be as safe as possible. And
>>>> inheritance here is native and correct thing to do, even with our ____
>>>> additional helper. What do you think?
>>>
>>> I wouldn't call it correct.  It's still unreliable, but less so than
>>> without the function name constraint.  That makes it less wrong.
>>
>> Agree.
>>
>>>
>>> 100% reliable would be nice, but not at any cost.  Something we're
>>> reasonably confident to get right should be good enough.
>>>
>>> To be confident, we need to understand the script's limitations, and how
>>> to compensate for them.  I figure we do now.  You too?
>>>
>>
>> I will not be surprised, if we missed some more interesting cases :)
>> But we should proceed. What is our plan? Will you queue v10 for 5.1?
> 
> v10's PATCH 1+2 look ready.  The error.h comment update could perhaps
> use some polish; I've focused my attention elsewhere.
> 
> PATCH 8-9 are generated.  They should never be rebased, always be
> regenerated.  We compare regenerated patches to posted ones to make sure
> they are still sane, and the R-bys are still valid.  I can take care of
> the comparing.
> 
> I'd like to have a pull request ready when the tree reopens for general
> development.  Let's use the time until then to get more generated
> patches out for review.
> 
> If I queue up patches in my tree, we shift the responsibility for
> regenerating patches from you to me, and create a coordination issue:
> you'll want to base patch submissions on the branch I use to queue this
> work, and that's going to be awkward when I rebase / regenerate that
> branch.  I think it's simpler to queue up in your tree until we're ready
> for a pull request.
> 
> When you post more patches, use
> 
>      Based-on: <20200317151625.20797-1-vsementsov@virtuozzo.com>
> 
> so that Patchew applies them on top of this series.  Hmm, probably won't
> do, as PATCH 9 already conflicts.
> 
> You could instead repost PATCH 1+2 with each batch.  I hope that's not
> too confusing.
> 
> I trust you'll keep providing a tag reviewers can pull.
> 
> I suggest to ask maintainers to leave merging these patches to me, in
> cover letters.
> 
> Makes sense?
> 

Hmm.

I remember what Kevin said about freeze period: maintainers will queue
a lot of patches in their "next" branches, and send pull requests at start
of next developing period. This highly possible will drop r-bs I can get now.
And reviewers will have to review twice.

And for the same reason, it's bad idea to queue in your branch a lot of patches
from different subsystems during freeze.

So, just postpone this all up to next development phase?


-- 
Best regards,
Vladimir

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
  2020-03-20 14:36                               ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
@ 2020-03-20 16:23                                 ` Markus Armbruster
  -1 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-20 16:23 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 20.03.2020 16:58, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
[...]
>>> I will not be surprised, if we missed some more interesting cases :)
>>> But we should proceed. What is our plan? Will you queue v10 for 5.1?
>>
>> v10's PATCH 1+2 look ready.  The error.h comment update could perhaps
>> use some polish; I've focused my attention elsewhere.
>>
>> PATCH 8-9 are generated.  They should never be rebased, always be
>> regenerated.  We compare regenerated patches to posted ones to make sure
>> they are still sane, and the R-bys are still valid.  I can take care of
>> the comparing.
>>
>> I'd like to have a pull request ready when the tree reopens for general
>> development.  Let's use the time until then to get more generated
>> patches out for review.
>>
>> If I queue up patches in my tree, we shift the responsibility for
>> regenerating patches from you to me, and create a coordination issue:
>> you'll want to base patch submissions on the branch I use to queue this
>> work, and that's going to be awkward when I rebase / regenerate that
>> branch.  I think it's simpler to queue up in your tree until we're ready
>> for a pull request.
>>
>> When you post more patches, use
>>
>>      Based-on: <20200317151625.20797-1-vsementsov@virtuozzo.com>
>>
>> so that Patchew applies them on top of this series.  Hmm, probably won't
>> do, as PATCH 9 already conflicts.
>>
>> You could instead repost PATCH 1+2 with each batch.  I hope that's not
>> too confusing.
>>
>> I trust you'll keep providing a tag reviewers can pull.
>>
>> I suggest to ask maintainers to leave merging these patches to me, in
>> cover letters.
>>
>> Makes sense?
>>
>
> Hmm.
>
> I remember what Kevin said about freeze period: maintainers will queue
> a lot of patches in their "next" branches, and send pull requests at start
> of next developing period. This highly possible will drop r-bs I can get now.
> And reviewers will have to review twice.
>
> And for the same reason, it's bad idea to queue in your branch a lot of patches
> from different subsystems during freeze.
>
> So, just postpone this all up to next development phase?

Okay.  I hope we can process generated patches at a brisk pace then.



^ permalink raw reply	[flat|nested] 67+ messages in thread

* Re: [Xen-devel] [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE()
@ 2020-03-20 16:23                                 ` Markus Armbruster
  0 siblings, 0 replies; 67+ messages in thread
From: Markus Armbruster @ 2020-03-20 16:23 UTC (permalink / raw)
  To: Vladimir Sementsov-Ogievskiy
  Cc: Kevin Wolf, Stefano Stabellini, qemu-block, Paul Durrant,
	Philippe Mathieu-Daudé,
	Christian Schoenebeck, Michael Roth, qemu-devel, Greg Kurz,
	Gerd Hoffmann, Stefan Hajnoczi, Anthony Perard, xen-devel,
	Max Reitz, Laszlo Ersek, Stefan Berger

Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:

> 20.03.2020 16:58, Markus Armbruster wrote:
>> Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> writes:
[...]
>>> I will not be surprised, if we missed some more interesting cases :)
>>> But we should proceed. What is our plan? Will you queue v10 for 5.1?
>>
>> v10's PATCH 1+2 look ready.  The error.h comment update could perhaps
>> use some polish; I've focused my attention elsewhere.
>>
>> PATCH 8-9 are generated.  They should never be rebased, always be
>> regenerated.  We compare regenerated patches to posted ones to make sure
>> they are still sane, and the R-bys are still valid.  I can take care of
>> the comparing.
>>
>> I'd like to have a pull request ready when the tree reopens for general
>> development.  Let's use the time until then to get more generated
>> patches out for review.
>>
>> If I queue up patches in my tree, we shift the responsibility for
>> regenerating patches from you to me, and create a coordination issue:
>> you'll want to base patch submissions on the branch I use to queue this
>> work, and that's going to be awkward when I rebase / regenerate that
>> branch.  I think it's simpler to queue up in your tree until we're ready
>> for a pull request.
>>
>> When you post more patches, use
>>
>>      Based-on: <20200317151625.20797-1-vsementsov@virtuozzo.com>
>>
>> so that Patchew applies them on top of this series.  Hmm, probably won't
>> do, as PATCH 9 already conflicts.
>>
>> You could instead repost PATCH 1+2 with each batch.  I hope that's not
>> too confusing.
>>
>> I trust you'll keep providing a tag reviewers can pull.
>>
>> I suggest to ask maintainers to leave merging these patches to me, in
>> cover letters.
>>
>> Makes sense?
>>
>
> Hmm.
>
> I remember what Kevin said about freeze period: maintainers will queue
> a lot of patches in their "next" branches, and send pull requests at start
> of next developing period. This highly possible will drop r-bs I can get now.
> And reviewers will have to review twice.
>
> And for the same reason, it's bad idea to queue in your branch a lot of patches
> from different subsystems during freeze.
>
> So, just postpone this all up to next development phase?

Okay.  I hope we can process generated patches at a brisk pace then.


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

^ permalink raw reply	[flat|nested] 67+ messages in thread

end of thread, other threads:[~2020-03-20 16:24 UTC | newest]

Thread overview: 67+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-12  8:59 [PATCH v9 00/10] error: auto propagated local_err part I Vladimir Sementsov-Ogievskiy
2020-03-12  8:59 ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
2020-03-12  8:59 ` [PATCH v9 01/10] error: auto propagated local_err Vladimir Sementsov-Ogievskiy
2020-03-12  8:59   ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
2020-03-12  8:59 ` [PATCH v9 02/10] scripts: Coccinelle script to use ERRP_AUTO_PROPAGATE() Vladimir Sementsov-Ogievskiy
2020-03-12  8:59   ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
2020-03-12 16:36   ` Markus Armbruster
2020-03-12 16:36     ` [Xen-devel] " Markus Armbruster
2020-03-13  6:38     ` Vladimir Sementsov-Ogievskiy
2020-03-13  6:38       ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
2020-03-13 15:42       ` Markus Armbruster
2020-03-13 15:42         ` [Xen-devel] " Markus Armbruster
2020-03-13 16:12         ` Vladimir Sementsov-Ogievskiy
2020-03-13 16:12           ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
2020-03-13 21:54           ` Markus Armbruster
2020-03-13 21:54             ` [Xen-devel] " Markus Armbruster
2020-03-13 22:12             ` Eric Blake
2020-03-13 22:12               ` [Xen-devel] " Eric Blake
2020-03-15 16:38               ` Markus Armbruster
2020-03-15 16:38                 ` [Xen-devel] " Markus Armbruster
2020-03-16  7:12             ` Vladimir Sementsov-Ogievskiy
2020-03-16  7:12               ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
2020-03-16  8:21               ` Markus Armbruster
2020-03-16  8:21                 ` [Xen-devel] " Markus Armbruster
2020-03-17  9:29                 ` Vladimir Sementsov-Ogievskiy
2020-03-17  9:29                   ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
2020-03-17 10:39                   ` Markus Armbruster
2020-03-17 10:39                     ` [Xen-devel] " Markus Armbruster
2020-03-17 11:35                     ` Vladimir Sementsov-Ogievskiy
2020-03-17 11:35                       ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
2020-03-19 10:45                       ` Markus Armbruster
2020-03-19 10:45                         ` [Xen-devel] " Markus Armbruster
2020-03-19 12:12                         ` Vladimir Sementsov-Ogievskiy
2020-03-19 12:12                           ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
2020-03-20 13:58                           ` Markus Armbruster
2020-03-20 13:58                             ` [Xen-devel] " Markus Armbruster
2020-03-20 14:36                             ` Vladimir Sementsov-Ogievskiy
2020-03-20 14:36                               ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
2020-03-20 16:23                               ` Markus Armbruster
2020-03-20 16:23                                 ` [Xen-devel] " Markus Armbruster
2020-03-17 13:54             ` Vladimir Sementsov-Ogievskiy
2020-03-17 13:54               ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
2020-03-19  8:31               ` Markus Armbruster
2020-03-19  8:31                 ` [Xen-devel] " Markus Armbruster
2020-03-13  7:50   ` Markus Armbruster
2020-03-13  7:50     ` [Xen-devel] " Markus Armbruster
2020-03-13  8:06     ` Vladimir Sementsov-Ogievskiy
2020-03-13  8:06       ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
2020-03-13 15:34       ` Markus Armbruster
2020-03-13 15:34         ` [Xen-devel] " Markus Armbruster
2020-03-13 14:58   ` Markus Armbruster
2020-03-13 14:58     ` [Xen-devel] " Markus Armbruster
2020-03-13 15:22     ` Vladimir Sementsov-Ogievskiy
2020-03-13 15:22       ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
2020-03-12  8:59 ` [PATCH v9 03/10] hw/sd/ssi-sd: fix error handling in ssi_sd_realize Vladimir Sementsov-Ogievskiy
2020-03-12  8:59 ` [PATCH v9 04/10] SD (Secure Card): introduce ERRP_AUTO_PROPAGATE Vladimir Sementsov-Ogievskiy
2020-03-12  8:59 ` [PATCH v9 05/10] pflash: " Vladimir Sementsov-Ogievskiy
2020-03-12  8:59 ` [PATCH v9 06/10] fw_cfg: " Vladimir Sementsov-Ogievskiy
2020-03-12  8:59 ` [PATCH v9 07/10] virtio-9p: " Vladimir Sementsov-Ogievskiy
2020-03-12  8:59 ` [PATCH v9 08/10] TPM: " Vladimir Sementsov-Ogievskiy
2020-03-12  8:59 ` [PATCH v9 09/10] nbd: " Vladimir Sementsov-Ogievskiy
2020-03-12  8:59 ` [PATCH v9 10/10] xen: " Vladimir Sementsov-Ogievskiy
2020-03-12  8:59   ` [Xen-devel] " Vladimir Sementsov-Ogievskiy
2020-03-12 14:24 ` [PATCH v9 00/10] error: auto propagated local_err part I Markus Armbruster
2020-03-12 14:24   ` [Xen-devel] " Markus Armbruster
2020-03-13  6:40   ` Vladimir Sementsov-Ogievskiy
2020-03-13  6:40     ` [Xen-devel] " Vladimir Sementsov-Ogievskiy

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.