diff mbox series

[PATCH-for-5.0,01/12] scripts/coccinelle: Add script to catch missing error_propagate() calls

Message ID 20200325191830.16553-2-f4bug@amsat.org
State New
Headers show
Series hw: Add missing error-propagation code | expand

Commit Message

Philippe Mathieu-Daudé March 25, 2020, 7:18 p.m. UTC
In some places in we put an error into a local Error*, but forget
to check for failure and pass it back to the caller.
Add a Coccinelle patch to catch automatically add the missing code.

Inspired-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
---
 ...ect_property_missing_error_propagate.cocci | 58 +++++++++++++++++++
 1 file changed, 58 insertions(+)
 create mode 100644 scripts/coccinelle/object_property_missing_error_propagate.cocci

Comments

Peter Maydell March 26, 2020, 9:32 p.m. UTC | #1
On Wed, 25 Mar 2020 at 19:18, Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> In some places in we put an error into a local Error*, but forget
> to check for failure and pass it back to the caller.
> Add a Coccinelle patch to catch automatically add the missing code.
>
> Inspired-by: Peter Maydell <peter.maydell@linaro.org>
> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---

This coccinelle script is impressively deep magic...
My general rule with cocci scripts is that if they serve
the purpose they're written for then that's sufficient
and they're not worth trying to polish further, but just
for my own education I have some questions below about how
this one works.

> +@match exists@
> +typedef Error;
> +Error *err;

I didn't realize you could do this kind of "this thing
must be this type" stuff in the metavariable declaration
section...

> +identifier func, errp;
> +identifier object_property_set_type1 =~ "^object_property_set_.*";
> +identifier object_property_set_type2 =~ "^object_property_set_.*";

If we relax this so that we just look for "anything that takes
an &err as its final argument" do we hit way too many false
positives ?

> +expression obj;
> +@@
> +void func(..., Error **errp)
> +{
> + <+...
> + object_property_set_type1(obj, ..., &err);
> + ... when != err

This 'when' clause means "match only when the code doesn't
touch 'err' anywhere between the two calls", right?

> + object_property_set_type2(obj, ..., &err);
> + ...+>
> +}
> +
> +@@
> +Error *match.err;
> +identifier match.errp;
> +identifier match.object_property_set_type1;
> +expression match.obj;
> +@@
> + object_property_set_type1(obj, ..., &err);
> ++if (err) {
> ++    error_propagate(errp, err);
> ++    return;
> ++}

Is there a reason we can't do the substitution
in the same rule we were using to find the match,
or was it just easier this way/done this way in
some other example you were following ?

> +
> +@manual depends on never match@
> +Error *err;
> +identifier object_property_set_type1 =~ "^object_property_set_.*";
> +identifier object_property_set_type2 =~ "^object_property_set_.*";
> +position p;
> +@@
> + object_property_set_type1@p(..., &err);
> + ... when != err
> + object_property_set_type2(..., &err);
> +
> +@script:python@
> +f << manual.object_property_set_type1;
> +p << manual.p;
> +@@
> +print("[[manual check required: "
> +      "error_propagate() might be missing in {}() {}:{}:{}]]".format(
> +            f, p[0].file, p[0].line, p[0].column))

Nice to have an example of how to do a "find these things
and print a diagnostic". This 'manual' match is handling
the cases where we got two consecutive uses of &err but
not in a function that took "Error *errp", yes?

thanks
-- PMM
diff mbox series

Patch

diff --git a/scripts/coccinelle/object_property_missing_error_propagate.cocci b/scripts/coccinelle/object_property_missing_error_propagate.cocci
new file mode 100644
index 0000000000..104e345273
--- /dev/null
+++ b/scripts/coccinelle/object_property_missing_error_propagate.cocci
@@ -0,0 +1,58 @@ 
+// Add missing error-propagation code
+//
+// Copyright: (C) 2020 Philippe Mathieu-Daudé.
+// This work is licensed under the terms of the GNU GPLv2 or later.
+//
+// spatch \
+//  --macro-file scripts/cocci-macro-file.h --include-headers \
+//  --sp-file scripts/coccinelle/object_property_missing_error_propagate.cocci \
+//  --keep-comments --smpl-spacing --in-place --dir hw
+//
+// Inspired by https://www.mail-archive.com/qemu-devel@nongnu.org/msg691638.html
+
+@match exists@
+typedef Error;
+Error *err;
+identifier func, errp;
+identifier object_property_set_type1 =~ "^object_property_set_.*";
+identifier object_property_set_type2 =~ "^object_property_set_.*";
+expression obj;
+@@
+void func(..., Error **errp)
+{
+ <+...
+ object_property_set_type1(obj, ..., &err);
+ ... when != err
+ object_property_set_type2(obj, ..., &err);
+ ...+>
+}
+
+@@
+Error *match.err;
+identifier match.errp;
+identifier match.object_property_set_type1;
+expression match.obj;
+@@
+ object_property_set_type1(obj, ..., &err);
++if (err) {
++    error_propagate(errp, err);
++    return;
++}
+
+@manual depends on never match@
+Error *err;
+identifier object_property_set_type1 =~ "^object_property_set_.*";
+identifier object_property_set_type2 =~ "^object_property_set_.*";
+position p;
+@@
+ object_property_set_type1@p(..., &err);
+ ... when != err
+ object_property_set_type2(..., &err);
+
+@script:python@
+f << manual.object_property_set_type1;
+p << manual.p;
+@@
+print("[[manual check required: "
+      "error_propagate() might be missing in {}() {}:{}:{}]]".format(
+            f, p[0].file, p[0].line, p[0].column))