On Sat, Nov 02, 2013 at 04:02:28PM +0100, Julia Lawall wrote:
> On Sat, 2 Nov 2013, Josh Triplett wrote:
> > On Sat, Nov 02, 2013 at 03:27:35PM +0100, Julia Lawall wrote:
> > > On Sat, 2 Nov 2013, Josh Triplett wrote:
> > > > I wanted to write a semantic patch that matched (and removed) "return;"
> > > > at the end of a void function.  I've attached the full .cocci file
> > > > written for coccicheck, but the key bit looks like this:
> > > >
> > > > @@
> > > > identifier fn;
> > > > @@
> > > > void fn ( ... )
> > > > {
> > > > ...
> > > > - return;
> > > > }
> > > >
> > > > However, that patch also produces results like this:
> > > >
> > > > --- a/drivers/scsi/aacraid/dpcsup.c
> > > > +++ b/drivers/scsi/aacraid/dpcsup.c
> > > > @@ -255,7 +255,6 @@ static void aac_aif_callback(void *conte
> > > >             cpu_to_le32(NoMoreAifDataAvailable)) {
> > > >                 aac_fib_complete(fibptr);
> > > >                 aac_fib_free(fibptr);
> > > > -               return;
> > > >         }
> > > >
> > > >         aac_intr_normal(dev, 0, 1, 0, fibptr->hw_fib_va);
> > > >
> > > > I'm guessing that either coccinelle didn't pair the braces (so that the
> > > > '}' matches close braces other than the one matching fn's opening brace)
> > > > or coccinelle allowed extra statements before the logical end of the
> > > > function despite the lack of '...'.
> > >
> > > The problem is that Coccinlle works on control-flow paths, and a return is
> > > always at the end of a control-flow path...
> >
> > Not sure I fully understand what you mean.  I do understand why
> > coccinelle works on control-flow paths rather than literal code, and
> > that makes it much more powerful, but I'm still not sure how coccinelle
> > manages to match the patch above to the code above.  Do the braces in
> > the semantic patch above not pair with each other?  If not, why not?  If
> > so, how does "return; }" match something between the "return;" and the
> > "}"?
> 
> The return is followed by all of the nested }s to get it out of the
> function.  I think that there is something special for these }s to skip
> over them, so that the return always seems to be next to the final }.

Huh.  Odd.

> > > Try the following:
> > >
> > > @start@
> > > identifier f;
> > > position p;
> > > @@
> > > f(...) {@p ... }
> > >
> > > @bad@
> > > position p, s != start.p;
> > > @@
> > >
> > > {@s <... return;@p ...> }
> > >
> > > @ef@
> > > position p;
> > > statement S;
> > > @@
> > >
> > > (
> > > while (...) return;@p
> > > |
> > > if (...) return;@p else S
> > > )
> > >
> > > @@
> > > position p != {bad.p,ef.p};
> > > @@
> > >
> > > - return;@p
> >
> > Interesting; I didn't know about the ability to exclude specific
> > positions that way.  However, that doesn't quite work, since it still
> > matches code like this:
> 
> OK, good point.  I will try to find something else.
> 
> return;
> S
> 
> doesn't work, because no statement follows a return.  A return is just
> followed by a sequence of closing braces.

In the control-flow sense, sure.  However, in addition to making this
particular case difficult, that also makes it difficult to use
coccinelle to detect dead code after a return.

> You can try this:
> 
> @@
> @@
> 
> - return;
> + RETURN;
> 
> @r exists@
> identifier f;
> position p;
> @@
> 
> f(...) {
>   ...
>   RETURN@p;
> }
> 
> @@
> position r.p;
> @@
> 
> - RETURN@p;
> 
> @@
> @@
> 
> - RETURN;
> + return;

Cute.  I'm not sure why you need the two separate rules with matching
positions; consolidating the two middle rules into one seems to work as
well.  I did have to add a rule for when the return immediately followed
a label, to make sure there was a statement to target.

However, this seems to have two issues.  First, to some extent I
*wanted* the control-flow matching, to handle cases like this without
having to do so explicitly:

void f(void)
{
        if (...) {
                foo();
-               return;
        }
}

Second, this seems to lead to many formatting issues:

--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -895,7 +895,7 @@ static void print_other_cpu_stall(struct
 
        rcu_print_detail_task_stall(rsp);
 
-       force_quiescent_state(rsp);  /* Kick them all. */
+       force_quiescent_state(rsp);
 }
 
 static void print_cpu_stall(struct rcu_state *rsp)

No idea why coccinelle touched this comment.  Do functions have an
implicit "return;" at the end that got patched here?

--- a/lib/xz/xz_crc32.c
+++ b/lib/xz/xz_crc32.c
@@ -43,7 +43,7 @@ XZ_EXTERN void xz_crc32_init(void)
                xz_crc32_table[i] = r;
        }
 
-       return;
+       RETURN;
 }
 
 XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)

No idea what happened here to prevent the RETURN; from getting
substituted back.


Also, I noticed some cases where the return; in question immediately
followed a label, so removing it would give that label no statement to
jump to.  I tried handling that explicitly:

@r1 depends on patch exists@
identifier f, l;
statement S;
position p;
@@
void f(...)
{
...
(
l:
- RETURN;@p
  S
|
l:
- RETURN@p
  ;
|
- RETURN;@p
)
}

However, while this did produce the desired result when the return
immeidately followed the label, it produced odd results in other cases:

--- a/crypto/seqiv.c
+++ b/crypto/seqiv.c
@@ -45,6 +45,7 @@ static void seqiv_complete2(struct skcip
 
 out:
        kfree(subreq->info);
+       return;
 }
 
 static void seqiv_complete(struct crypto_async_request *base, int err)

Many instances like this where coccinelle added "return;" where none
existed before.

- Josh Triplett
_______________________________________________
Cocci mailing list
[email protected]
https://systeme.lip6.fr/mailman/listinfo/cocci

Reply via email to