TSA attributes for functions are valid and get used as soon as they are given on one declaration of the function, even if other declarations exist and don't contain the attribute.
This sets up a trap for the user: It is possible to have a "require_capabilities" attribute set on the function definition in a source file, but not on the corresponding prototype in a header file. The function itself can do anything that you can do while you hold the lock because the compiler will see the attribute. But other source files will include the header without the attribute and can call the function without actually holding the lock.
A minimal reproducer looks like this:
$ cat > common.h typedef int __attribute__((capability("mutex"))) my_mutex; extern my_mutex mutex; void foo(void);
$ cat > foo.c #include "common.h" void foo(void) __attribute__((requires_capability(mutex))) { /* Could do things that require holding the mutex here */ }
$ cat > main.c #include "common.h" int main(void) { foo(); return 0; }
$ clang -Wthread-safety main.c foo.c
This compiles without a warning and the specified requirement doesn't actually take effect.
I propose that clang should warn if a function definition has TSA attributes, a previous declaration of the same function exists and the attribute isn't present on at least one of the previous declarations.
For the time being, QEMU uses a convention of annotating public functions only in the header file, but not in the source file, to manually catch this kind of problems in review more easily. This is one of the reasons why I'm not suggesting to require that the attributes are identical in all places. Another reason is that adding annotations to function from a library whose header files don't support TSA might be a valid use case.
However, if the decision is that TSA attributes should be identical in all declarations, this is fine, too. QEMU can adapt to this without major problems after the new warning is implemented.
- is related to
-
RHEL-8519 Make use of new clang TSA extensions
- In Progress