- Notifications
You must be signed in to change notification settings - Fork 15.3k
[clang][TSA] Make RequiresCapability a DeclOrType attribute #67095
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| @llvm/pr-subscribers-clang ChangesThis was much easier than expected actually. I'm sure I'm missing a lot of changes and test coverage though. @aaronpuchert I'm starting a new review here instead of continuing the one in Phab since this is a completely different attempt. I hope that's ok. Full diff: https://github.com/llvm/llvm-project/pull/67095.diff 2 Files Affected:
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 21a3b5226623cf2..7eab87dac6921f1 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3305,7 +3305,7 @@ def ReleaseCapability : InheritableAttr { let Documentation = [ReleaseCapabilityDocs]; } -def RequiresCapability : InheritableAttr { +def RequiresCapability : DeclOrTypeAttr { let Spellings = [Clang<"requires_capability", 0>, Clang<"exclusive_locks_required", 0>, Clang<"requires_shared_capability", 0>, @@ -3314,8 +3314,8 @@ def RequiresCapability : InheritableAttr { let LateParsed = 1; let TemplateDependent = 1; let ParseArgumentsAsUnevaluated = 1; - let InheritEvenIfAlreadyPresent = 1; - let Subjects = SubjectList<[Function]>; + /*let InheritEvenIfAlreadyPresent = 1;*/ + /*let Subjects = SubjectList<[Function]>;*/ let Accessors = [Accessor<"isShared", [Clang<"requires_shared_capability", 0>, Clang<"shared_locks_required", 0>]>]; let Documentation = [Undocumented]; diff --git a/clang/test/Sema/warn-thread-safety-analysis.c b/clang/test/Sema/warn-thread-safety-analysis.c index 642ea88ec3c96f7..cd852efac21cb81 100644 --- a/clang/test/Sema/warn-thread-safety-analysis.c +++ b/clang/test/Sema/warn-thread-safety-analysis.c @@ -136,6 +136,17 @@ int main(void) { // Cleanup happens automatically -> no warning. } + /// Function pointers + { + int __attribute__((requires_capability(&mu1))) (*function_ptr)(int) = Foo_fun1; + + function_ptr(5); // expected-warning {{calling function 'function_ptr' requires holding mutex 'mu1'}} + + mutex_exclusive_lock(&mu1); + int five = function_ptr(5); + mutex_exclusive_unlock(&mu1); + } + return 0; } |
2d0d268 to 5dd9266 Compare | Ping |
aaronpuchert left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was much easier than expected actually.
Making it a DeclOrType attribute is indeed a nice idea, this would allow existing attributes to stay where they are. Is it still inheritable, i.e. does it also apply to later redeclarations?
Of course I'm also wondering why we don't have to change anything in the analysis, aren't we currently only looking at declaration attributes, and wouldn't consider attributes on the type? Or is there some mechanism that gives us the combined set of declaration and type attributes?
I'm starting a new review here instead of continuing the one in Phab since this is a completely different attempt. I hope that's ok.
Yeah, since it's a completely different approach than https://reviews.llvm.org/D152246 we're not really losing any history.
clang/lib/Sema/SemaDeclAttr.cpp Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like the attribute sits on the Decl and not its type, or am I misunderstanding this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah we attach the attribute to the declaration later in this function:
RequiresCapabilityAttr *RCA = ::new (S.Context) RequiresCapabilityAttr(S.Context, AL, Args.data(), Args.size()); D->addAttr(RCA);and in ThreadSafety.cpp we then check the decl for the attribute in VisitCallExpr():
auto *D = dyn_cast_or_null<NamedDecl>(Exp->getCalleeDecl()); if(!D || !D->hasAttrs()) return;for the function pointer case, D will be the VarDecl, which now has the attribute attached.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once the Subjects list is corrected, I believe this code can be removed.
I haven't tested this explicitly, but
Let me check why this just works. |
AaronBallman left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes also need a release note at some point.
clang/include/clang/Basic/Attr.td Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of removing it, can this be updated to be correct (we have FunctionPointer as a subject)?
clang/lib/Sema/SemaDeclAttr.cpp Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once the Subjects list is corrected, I believe this code can be removed.
| Ping |
Did you see #67095 (comment) ? |
Yes, I added the changes to But the tests fail too, I'll check that locally. |
Nope, this was another lovely case of GitHub hiding details from me. The Files tab wasn't showing me your changes to that file... until I clicked it a second time and then new changes showed up. Sorry for the noise! |
clang/lib/Sema/SemaType.cpp Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, this needs to be done manually because the helper code automatically generated by tablegen isn't yet smart enough to generate logic for type attributes. I think this work should be done as part of this commit instead of left as follow-up work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll also need changes showing that we properly diagnose all the usual stuff from the decl form of the attribute but with the type form instead, plus additional coverage for new diagnostics like conversions between function pointer types with/out the attribute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are no such diagnostics when converting between function pointers. Are there supposed to be any, without adding special handling for this? I quickly checked and noreturn has the same behavior.
| It's pretty easy to get an error like: but as soon as I change |
| case ParsedAttr::AT_RequiresCapability: { | ||
| HandleRequiresCapabilityAttr(state, type, attr); | ||
| attr.setUsedAsTypeAttr(); | ||
| break; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, maybe we do want to do this change separately. I think I was wrong about modeling after this; I think we want it to be done like handleFunctionTypeAttr() and FUNCTION_TYPE_ATTRS_CASELIST so that it becomes part of the FunctionType itself. That's what would get us the diagnostics on type mismatches (we look through AttributedType as sugar:
llvm-project/clang/include/clang/AST/Type.h
Line 4999 in 28b7e28
| bool isSugared() const { return true; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmmm, my intuition is that if we don't do this work now, we'll forever be stuck with the current behavior where we don't diagnose pointer mismatches because someone will rely on that continuing to work. So maybe we do want to do this work now...
CC @erichkeane @aaronpuchert for opinions on whether we think this needs to diagnose mismatches in the initial offering of it as a type attribute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I agree Aaron, if we don't diagnose now, it'll be pretty ugly to do it later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meh, it seems like adding a pointer to FunctionType::ExtInfo would blow it up a lot, and just a bit isn't enough to save the information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There were a few changes there recently... i wonder if it is time to just accept that we're going all-in on trailing-storage for this type. We're now doing it for the ARM SVE types, plus the 'lesser used' structure, so perhaps the 'capability pointer' can end up there too. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AaronBallman Does this sound like the way to go to you as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, we don't want to modify FunctionType::ExtInfo, I think what @erichkeane was talking about is that we added trailing objects to FunctionProtoType that we can squirrel lesser-used data into. That might be reasonable here because I cannot imagine anyone using thread safety attributes with K&R C interfaces, but that would be the downside to putting the data on FunctionProtoType.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would kind of stink to have to do it in 2 places, but it could go in trailing-storage/etc on FunctionProtoType and FunctionNoProtoType, then just disambiguate it with a function. So it doesn't need to end up in FunctionType::ExtInfo or FunctionType itself.
| Ping |
erichkeane left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems you pinged this without the commit to fix the things we've requested?
Right, I was more looking for guidance what to do with |
| One thing I'm unsure about right now: This probably needs more work, especially regarding assigning function pointers, doesn't it? Even in the test case I added right now, |
| Good question. Which AST nodes could we visit here? Let's see some examples of initializing function pointers/references: void f(); void (*fp)() = f; void (*fp2)() = &f; void (*fp3)() = fp; void (&fr)() = f;The (simplified) AST: The third and fourth declarations are tricky. I don't see an AST node that we could attach to for finding this. Perhaps we should adapt Sema to add casts for the attributes? Then we could always attach to the |
This was much easier than expected actually.
I'm sure I'm missing a lot of changes and test coverage though.
@aaronpuchert I'm starting a new review here instead of continuing the one in Phab since this is a completely different attempt. I hope that's ok.