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)

Reply via email to