On Sun, Jun 13, 2010 at 09:43:42PM +0200, Julia Lawall wrote:
> On Sun, 13 Jun 2010, Josh Triplett wrote:
> > I've just started trying to use Coccinelle to rewrite code written for
> > Xlib to use our replacement library XCB instead.
> >
> > In trying some simple test patches and learning Coccinelle, I
> > encountered this error:
> >
> > """
> > HANDLING: /tmp/bug.c
> >
> > previous modification:
> > MINUS
> > >>> xcb_disconnect(conn);
> >
> > According to environment 0:
> >
> >
> > current modification:
> > MINUS
> > According to environment 0:
> >
> >
> > Fatal error: exception Failure("rule starting on line 1: already tagged
> > token:
> > C code context
> > File "/tmp/bug.c", line 5, column 1, charpos = 45
> > around = 'XCloseDisplay', whole content = XCloseDisplay (dpy);")
> > """
>
> In general, what the error means is that it found two different things to
> do for a token in the source program; once to remove it and add something
> and another time just to remove it.
>
> > I reduced the semantic patch and the source file to minimal test cases.
> > The semantic patch:
> >
> > @@
> > identifier dpy;
> > @@
> > (
> > -if (dpy) { XCloseDisplay(dpy); }
> > +xcb_disconnect(conn);
> > |
> > -XCloseDisplay(dpy);
> > +xcb_disconnect(conn);
> > )
>
> First point: if (dpy) { XCloseDisplay(dpy); } is also considered to match
> if (dpy) XCloseDisplay(dpy); by an isomorphism.
Hmmm. Does the reverse hold true as well? If I write "if (dpy)
XCloseDisplay(dpy);" it doesn't seem to match "if (dpy) {
XCloseDisplay(dpy); }".
> Then, the basic idea of ( | ) is that it works from top to bottom; if the
> first branch matches the second one should not be applied. But the more
> precise semantics is that this is what happens at the node level. If you
> look at the control-flow graph for your source program, which you can see
> with the option -control_flow and just the name of the C file, you will
> see that the header of an if statement and the branch are different nodes.
>
> Since the root node matched by the if (dpy) XCloseDisplay(dpy); pattern is
> different fro the root node matched by the XCloseDisplay(dpy); pattern,
> they are just considered to be disjoint matches, and the top to bottom
> semantics of ( | ) doesn't help. Thus there are two possible and
> conflicting matches.
Ah, I see! That explains it.
> The solution is to separate the semantic patch into two rules, with the
> first rule taking care of the if case and the second rule taking care of
> any calls to XCloseDisplay(dpy); that are left over.
I'll remember that for the next time I encounter this situation.
As it turned out, I couldn't eliminate the if as I thought I could, so I
ended up with this rule, which worked:
@@
Display *dpy;
@@
(
-if (dpy) { XCloseDisplay(dpy); }
+if (conn) xcb_disconnect(conn);
|
if (
- !dpy
+ xcb_connection_has_error(conn)
) { ... }
)
As mentioned above, it seems that I have to write this rule with the
braces around XCloseDisplay, or it won't match when the if has braces.
The isomorphism does work in the other direction, though; this rule
matches cases *without* braces.
Thanks for the quick response! I've had good luck with automated
translation of Xlib code to XCB code so far. I'll write back if I run
into anything else I can't seem to express as a semantic patch, since I
strongly suspect it would indicate a limitation of my understanding
rather than of Coccinelle's functionality. :)
- Josh Triplett
_______________________________________________
Cocci mailing list
[email protected]
http://lists.diku.dk/mailman/listinfo/cocci
(Web access from inside DIKUs LAN only)