Clang-tidy check for preprocessor marked functions

Hi,

I have started to investigate using clang-tidy for some QEMU checks and modernization, with some success. I started sending patches to the QEMU ML (https://lists.nongnu.org/archive/html/qemu-devel/2017-06/msg05034.html). The QEMU maintainer, Peter, challenged me to see if we could write a check for coroutine usage: check if there are calls to a coroutine-marked function from a non-coroutine (which would be a bug, as coroutine may yield). Coroutine function are marked with a “coroutine_fn” macro, this a simple example:

#define coroutine_fn

void coroutine_fn qemu_coroutine_yield(void);

int main(int argc, char *argv)
{
qemu_coroutine_yield();
return 0;
}

Here, qemu_coroutine_yield() should be an error, because main() is not a coroutine_fn.

Is there a way to write a clang-tidy check, perhaps at PP level, that would mark the function declaration with coroutine type?

What would you suggest instead?

PS: forgive me if this is not the clang-tidy list.

PS2: I opened 2 little bugs on bugzilla, no reply so far https://bugs.llvm.org/show_bug.cgi?id=33440, https://bugs.llvm.org/show_bug.cgi?id=33441

Hi,

I have started to investigate using clang-tidy for some QEMU checks and
modernization, with some success. I started sending patches to the QEMU ML
([Qemu-devel] [PATCH 00/31] Refactoring with clang-tidy).
The QEMU maintainer, Peter, challenged me to see if we could write a check
for coroutine usage: check if there are calls to a coroutine-marked function
from a non-coroutine (which would be a bug, as coroutine may yield).
Coroutine function are marked with a "coroutine_fn" macro, this a simple
example:

#define coroutine_fn

void coroutine_fn qemu_coroutine_yield(void);

int main(int argc, char *argv)
{
    qemu_coroutine_yield();
    return 0;
}

Here, qemu_coroutine_yield() should be an error, because main() is not a
coroutine_fn.

Is there a way to write a clang-tidy check, perhaps at PP level, that would
mark the function declaration with coroutine type?

While not clang-tidy answer, i wonder if this is an appropriate use-case for
https://clang.llvm.org/docs/ThreadSafetyAnalysis.html

(The following is undested, and is pure speculation)

Have some global symbol, like
typedef int __attribute__((capability("role"))) coroutine_role;
coroutine_role _coroutine_fn;

And then defining:
#define coroutine_fn REQUIRES(_coroutine_fn)

And compiling with -Wthread-safety.

What would you suggest instead?

PS: forgive me if this is not the clang-tidy list.
PS2: I opened 2 little bugs on bugzilla, no reply so far
https://bugs.llvm.org/show_bug.cgi?id=33440,
https://bugs.llvm.org/show_bug.cgi?id=33441

--
Marc-André Lureau

Roman.

Hi Roman

Hi,

I have started to investigate using clang-tidy for some QEMU checks and
modernization, with some success. I started sending patches to the QEMU ML
(https://lists.nongnu.org/archive/html/qemu-devel/2017-06/msg05034.html).
The QEMU maintainer, Peter, challenged me to see if we could write a check
for coroutine usage: check if there are calls to a coroutine-marked function
from a non-coroutine (which would be a bug, as coroutine may yield).
Coroutine function are marked with a “coroutine_fn” macro, this a simple
example:

#define coroutine_fn

void coroutine_fn qemu_coroutine_yield(void);

int main(int argc, char *argv)
{
qemu_coroutine_yield();
return 0;
}

Here, qemu_coroutine_yield() should be an error, because main() is not a
coroutine_fn.

Is there a way to write a clang-tidy check, perhaps at PP level, that would
mark the function declaration with coroutine type?
While not clang-tidy answer, i wonder if this is an appropriate use-case for
https://clang.llvm.org/docs/ThreadSafetyAnalysis.html

(The following is undested, and is pure speculation)

Have some global symbol, like
typedef int attribute((capability(“role”))) coroutine_role;
coroutine_role _coroutine_fn;

And then defining:
#define coroutine_fn REQUIRES(_coroutine_fn)

And compiling with -Wthread-safety.

It almost does the job, thanks for the tip. The documentation seems to be scarce though.

The major issue I see right now, is that you can’t annotate function pointers type or fields with requires_capability for instance.

QEMU has typedef void coroutine_fn CoroutineEntry(void *opaque); it would be nice if the analyser could check the function passed has the same annotation.

Secondly, when calling such pointer, use the same analysis as with regular functions annotation.

I suppose this isn’t too hard to add, and I started digging in clang code, but help welcome.

Who should I CC for help? (I added Aaron, since it seems you have done some related work some time ago)

thanks