[Cocci] Extracting types passed to variadic (varargs) functions

David Malcolm dmalcolm at redhat.com
Tue Nov 17 20:21:07 CET 2009

On Mon, 2009-11-16 at 23:14 +0100, Julia Lawall wrote:
> On Mon, 16 Nov 2009, David Malcolm wrote:
> > I'm new to Coccinelle/spatch and have been experimenting with using it
> > upon CPython code [1]
> > 
> > I'm attempting to validate a mini-language used in format strings by a
> > variadic API call.  My code examines the types of the
> > variables passed as varargs, and attempts to check that they are
> > pointers of the correct types, according to a set of rules [2].
> > 
> > Unfortunately, I couldn't see a way to match a variable-length list of
> > expressions, capturing the type of each expression.
> If you really want to analyze all of the arguments at once, I don't see 
> how to do it.  But perhaps the following would be acceptable (not tested):
> @check_PyArg_ParseTuple@
> position pos;
> expression args;
> expresion fmt;
> type t; t e;
> expression list[n] E;
> @@
> PyArg_ParseTuple(args at pos, fmt, E, e, ...)
> @script:python@
> fmt << check_PyArg_ParseTuple.fmt;
> pos << check_PyArg_ParseTuple.pos;
> t << check_PyArg_ParseTuple.t;
> n << check_PyArg_ParseTuple.n;
> @@
> num_errors += validate_types(pos[0], fmt.expr, n, t)
> (I'm not sure that the .expr is needed on fmt; or in any case I don't know 
> what it does).
> Now validate_types takes a position, a format string, the number of 
> arguments between the format string and some argument, and that argument.  
> The python code will be called on each argument individually.

Thanks.  I tried this, but appeared to only match the final argument at
each call site.

However, I reworked it to have an "expression list" both before _and_
after, thus:

@ check_PyArg_ParseTuple @
position pos;
expression args;
expression fmt;
expression list[len_E] E;
expression list[len_F] F;
type t;
t e;

PyArg_ParseTuple at pos(args, fmt, E, e, F)

pos << check_PyArg_ParseTuple.pos;
fmt << check_PyArg_ParseTuple.fmt;
len_E << check_PyArg_ParseTuple.len_E;
len_F << check_PyArg_ParseTuple.len_F;
t << check_PyArg_ParseTuple.t;
num_errors += validate_type(pos[0], 
    int(len_E) + 1 + int(len_F),

...and it's now successfully matching the rule for each argument, and
supplying the index and the total number of arguments together which
each type, which seems to be everything I needed.

Many thanks!

> > Also, I noticed that positions are passed to Python code as a 1-tuple
> > containing a coccilibs.elems.Location, rather than just the Location
> > itself.  Is this deliberate (e.g. to support ranges as well as
> > positions)?
> A single position variable can be bound to more than one position when 
> using a nest (<... ...> for 0 or more occurrences of the contained pattren 
> and <+... ...+> for 1 or more occurrences of the contained pattern).  For 
> example, if f is a one-argument function, then the following will bind p 
> to each occurrence of e in that argument:
> f(<+...e at p...+>)
> Then you can use for to iterate over them.

Thanks for the clarification.

More information about the Cocci mailing list