Hello,
I am trying to write coccinelle patches for ocaml bindings API to
automatically detect and fix
common error cases.
I have the following questions so far :
1)
What is the best way to handle name #define's, i.e. caml/compatibility.h
defines a bunch of names
of the form :
#define alloc_small caml_alloc_small
and I want to use single name in cocci files, not both, for matching (any name
can be present in .c files).
Ideally I would like to reuse this compatibility.h without copying the
definitions, but apparently this doesn't work, not
even copying the definitions into local include or pasting directly into C
source.
$ cat test.cocci
@@ expression SIZE, TAG; @@
* caml_alloc_small(SIZE,TAG)
$ cat test.h
#define alloc_small caml_alloc_small
$ cat test.c
#include "test.h"
void test()
{
value v = caml_alloc_small(3,0);
value v2 = alloc_small(3,0);
}
Running spatch -all_includes -macro_file test.h -sp_file test.cocci test.c
matches only one line, not both.
IIUC this is because macro defines are used only for the .c code, but not for
the code in the
patches itself - correct? I figured out I can use isomorphisms to achieve this
goal :
$ cat caml.iso
Expression
@@ @@
alloc_small <=> caml_alloc_small
and @ using "caml.iso" @ in test.cocci does the trick, but I guess it is not
quite the intended usage and
I do not like to rewrite all #define's as isomorphisms..
2)
First patch is to check assignments to allocated blocks. Blocks can be
allocated as "structured" or "raw".
This is detected by the tag paramater passed to caml_alloc. Ideally I would
like to "evaluate" tag parameter
(taking into consideration ocaml #define's) to a constant and compare it to
maximum "structured" tag = No_scan_tag = 251,
but this is not possible I guess? After some trial and error I came up with the
following patch :
$ cat caml.cocci
@raw_block@
local idexpression v;
expression SIZE;
identifier C ~=
"^\(No_scan_tag\|Abstract_tag\|String_tag\|Double_tag\|Double_array_tag\|Custom_tag\)$"
;
@@
v = caml_alloc(SIZE,C)
@@
expression FIELD, VAL;
local idexpression raw_block.v;
@@
- Store_field(v,FIELD,VAL)
+ Field(v,FIELD) = VAL
@struct_block@
local idexpression v;
expression SIZE;
identifier C !~=
"^\(No_scan_tag\|Abstract_tag\|String_tag\|Double_tag\|Double_array_tag\|Custom_tag\)$"
;
constant TAG;
@@
v = caml_alloc(SIZE,\(C\|TAG\))
@@
expression FIELD, VAL;
local idexpression struct_block.v;
@@
- Field(v,FIELD) = VAL
+ Store_field(v,FIELD,VAL)
$ cat caml.h
#define CAMLprim
#define CAMLextern
#define CAMLunused
#define CAMLlocal1(x) value x
and it correctly detects all /* FIX */ lines in the following code :
$ cat test.c
void q()
{
value exceptionData;
exceptionData = caml_alloc(3, 0);
Field(exceptionData, 0) = Val_int(code); /* FIX */
Field(exceptionData, 1) = Val_int(code); /* FIX */
Field(exceptionData, 2) = copy_string(errorString); /* FIX */
}
void q()
{
// value exceptionData = caml_alloc(2,1);
Field(exceptionData, 0) = Val_int(code); /* OK */
value x = caml_alloc(3,No_scan_tag);
Field(x,0) = 2; /* OK */
Store_field(x,0,2); /* FIX */
}
It was not obvious what kinds of metavariables to use - i.e. what is the exact
meaning of
constant vs identifier vs local idexpression, etc? Is is ok to match e.g.
No_scan_tag as identifier
while it is really a #define? Any hints to improve this patch?
3)
Do you think overall coccinelle is a correct tool for such a task?
Thanks for your time.
--
ygrek
http://ygrek.org.ua/
_______________________________________________
Cocci mailing list
[email protected]
http://lists.diku.dk/mailman/listinfo/cocci
(Web access from inside DIKUs LAN only)