[clang] [clang] WIP: Warn on mismatched RequiresCapability attributes (PR #67520)

2024-07-26 Thread Kevin Wolf via cfe-commits

kevmw wrote:

I'm the person who asked @tbaederr last year if this could be added for the 
benefit of QEMU, and as I'm looking at it again now, I thought maybe I should 
leave a comment here.

In QEMU, we currently handle the problem with a coding convention (public 
functions get TSA attributes _only_ in the header) and rely on manual code 
review that the convention is actually obeyed. Obviously, having something 
automatable like this handled by the compiler would be much nicer and less 
error prone, so we would still like to see this implemented eventually in some 
form.

> I could imagine this being useful for RequiresCapability in cases where you 
> only want to require the capability internally as an implementation detail, 
> but not make it part of the public interface of the function.

Not sure what scenario you have in mind there. How is requiring a capability 
ever something internal? Aren't required capabilities by definition part of the 
contract of a function?

For example, if a function uses RequiresCapability to specify that it must be 
called with some lock held and you call it without that lock, that is a bug. If 
the function takes a lock only internally, then it wouldn't specify that in a 
TSA attribute because these attributes are only about the interface of the 
function.

I would actually compare this to function declarations with conflicting calling 
conventions. This is always a hard compiler error – calling the function with a 
different calling convention would be a bug, just like calling a function 
without the right capabilities. (Though admittedly, differing calling 
conventions would typically result in more obvious bugs if the compiler didn't 
catch them...)

Am I missing some legitimate scenario in which your code snippet shouldn't 
cause a warning here because I'm primarily thinking of capabilities as used 
with locks?

> Yeah, it's a tricky question. On one hand there have been previous issues 
> like #42194 (which this would basically address), and it would definitely 
> improve consistency and prevent beginner's mistakes. On the other hand it 
> seems useful to allow adding attributes e.g. to third-party libraries where 
> you don't control the headers.

I'm not sure that this mistake is one that only beginners would make.

But I agree that adding attributes to functions from third-party libraries is 
important. I think this is why I first suggested the following in the 
[downstream tracker](https://issues.redhat.com/browse/RHEL-7269): "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."

But come to think of it, I'm not sure any more if this really makes a 
difference – typically, you don't even have a definition for functions from 
third-party libraries that could trigger the warning, only declarations. The 
exception are inline functions in headers, but even then, what you get is a 
declaration with the attribute and a definition without it, which still 
wouldn't trigger the warning. So do we actually have a problem here?

https://github.com/llvm/llvm-project/pull/67520
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] WIP: Warn on mismatched RequiresCapability attributes (PR #67520)

2024-08-30 Thread Kevin Wolf via cfe-commits

kevmw wrote:

> But as a rule of thumb, static analysis attributes always belong on the 
> publicly visible declaration. Otherwise, the caller can't see them.

Yes, the theory is obvious and easy to understand, at least once you think of 
it. Applying it in practice is where I made the experience that mistakes happen 
a bit too easily.

When you have a mix of static and public functions (so sometimes the 
annotations are on the definition and sometimes in the header), you're bound to 
miss a missing "static" sooner or later even if you know the theory. Being 
careful only gets you so far, so it would be really nice to get that support 
from the compiler. (And after all, TSA is all about getting support from the 
compiler instead of trying to be careful yourself.)

Another way to deal with the mistakes would be just outright forbidding most 
TSA attributes on definitions for public functions, though that's even more 
restrictive ("TSA attributes on the definition have to be empty" vs. "TSA 
attributes on the definition have to be a subset of the attributes on 
declarations").

What I think would make me prefer having the annotations in both places is that 
when editing a source file, it is slightly inconvenient to have to look at the 
header to know which assumptions it can make, and it's also slightly 
inconvenient to update a function in both places if you can't just copy the 
line, but they have to be different. But that's merely a question of 
convenience, so if forbidding works better for you, I could live with that, too.

> Ok, that's an interesting twist. I could live with that, but I'm not sure if 
> we handle any other atttributes this way.

Yeah, I'm not sure if there are any that work the exact same way (though I also 
didn't actively look for one). But as @AaronBallman said above, the attributes 
are additive, so comparing the definition with the final set of TSA annotations 
of all declarations combined – which is the same as checking for "at least one" 
– would seem to make a lot of sense to me.

But as I concluded, checking all previous declarations for function definitions 
(and only for definitions) should actually work fine in practice, too, unless 
you're doing crazy things like writing your own implementation with TSA 
annotations while using a third-party header file for it that doesn't have 
them. In which case you should probably just copy that header file instead, or 
locally turn off the warning for that function.

I also compared TSA annotations to calling conventions. There it's possible to 
have the attribute only on the first declaration and leave it out on later ones 
(but not the other way around, and obviously also not specifying two different 
calling conventions). Modelling it after that should work, too, though I'm not 
sure if the consistency with another attribute is worth the additional 
limitation.

So there are options and the exact mode is for you guys to decide, I don't mind 
too much either way.

> What I was thinking about was warning on any redeclaration that's adding 
> attributes. Sure, if you only do this on definitions, adding attributes to 
> third-party library wouldn't be an issue.

Ah, I see. Maybe I misunderstood the code of this PR, but I thought it only 
checks definitions. And that's honestly all I think we need. It will always be 
possible to fool TSA with declarations that one file sees and another doesn't, 
but if we can warn in the common case of a function with one declaration in a 
header and a definition in a specific source file, it would probably catch 99% 
of cases in practice.

https://github.com/llvm/llvm-project/pull/67520
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang] WIP: Warn on mismatched RequiresCapability attributes (PR #67520)

2024-10-02 Thread Kevin Wolf via cfe-commits
Timm =?utf-8?q?Bäder?= ,
Timm =?utf-8?q?Bäder?= ,
Timm =?utf-8?q?Bäder?= ,
Timm =?utf-8?q?Bäder?= ,
Timm =?utf-8?q?Bäder?= 
Message-ID:
In-Reply-To: 


kevmw wrote:

> This example from the failing test should warn I think
> [...]
> Since the definition of foo2 specifies attributes that aren't present in the 
> previous declaration.

Yes, this looks exactly like the thing we want to protect against to me 
(because chances are that the declaration is actually in a header file and 
other source files will check their calls only against this declaration, so 
real bugs can be expected to result from this).

https://github.com/llvm/llvm-project/pull/67520
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits