-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Thread Safety Analysis "guarded_by" attribute doesn't work for struct fields in C code #20777
Comments
Looking into this briefly, I'm wondering if some code related to ExprArgument handling (e.g., within the Sema layer) is only considering scoped lookups for CXXRecordDecls, when it should be generalized to handle plain RecordDecls too? |
In C, struct and union member names are simply never in scope; it's not surprising that name lookup doesn't find them here. The name space containing these names is only searched when the name appears on the right hand side of a . or ->. It's not clear to me what, if anything, should be done about this. We probably don't want to introduce an implicit 'this' pointer into C. |
That's fair, though it's unfortunate that it seems to limit the usefulness of Thread Safety Analysis for C code bases that can't be compiled as C++ without a lot of cleanup work first. Is there at least a workaround that could be used here for C code? |
Apologize for the necroing, but this would be a real quality of life improvement. My workaround is to force compilation of all code into C++ with |
While we probably don't want to introduce an implicit 'this' pointer into C, I think we still should consider doing that. We need a solution that works in both C and C++ with the same syntax (because the structure may be in a header file that's included from both .c and .cpp compilands) and this is the most obvious solution for users to reach for. There's no reason why the thread safety analysis framework shouldn't work on this code in C aside from solving "how do you name the structure member" and that's entirely implementation-defined anyway because it's only a question inside the argument list of an attribute. So for the purposes of name lookup within this very specific context, it seems reasonable to support that. Lacking the ability to do this really devalues the otherwise very useful thread safety analyses we do by cutting out a somewhat common use case in C. |
We should consider how to represent the case where a member of a struct is notionally guarded by acquisition of the a lock on the entire struct: struct Lockable {
int internal_mutex;
int value [[clang::guarded_by(*this)]];
};
void lock(Lockable *p) [[clang::exclusive_lock_function(*p)]];
// ... Allowing the attributes to name the struct members isn't enough to model this; we need to allow the attributes to name the struct itself. We could give C++-like semantics in C by injecting into scope an identifier 'this' along with identifiers for all the struct members while parsing a thread safety annotation expression. I'm not sure that's the cleanest way forward, though. Perhaps instead we should provide an alternative attribute syntax that permits the 'this' parameter to be explicitly declared: struct Lockable {
int internal_mutex;
int value [[clang::guarded_by(for Lockable *self: *self)]];
}; and struct guarded_int {
struct mutex mu;
int value __attribute__((guarded_by(for guarded_int *self: self->mu)));
}; (This is placeholder syntax rather than something I'm actually proposing.) |
I think this could be useful, but it seems like a further extension to the minimal support for naming a field, too. I'd be curious if DeLesley thinks this is the correct model though. My understanding of the analysis is that we want to know what the actual lock object is, and a structure cannot act as a lock object by itself (it has to be some member of the structure that is the actual locking mechanism).
Using new syntax is an interesting option. I would be a little bit worried about injecting a 'this' identifier only because I've seen structures in the wild in C that have a 'this' member, and we'd have to figure out how to handle those beasts. |
As mentioned on cfe-dev, we're interested in using ThreadSafetyAnalysis for the Linux kernel. Since this issue has existed for some years, what is required to get this unstuck? Any estimate on the implementation complexity to get this supported? (Unfortunately I'm not at all familiar with frontend internals, so I wouldn't know where to start -- otherwise I would have tried to put together a prototype, as that feels like the best way to discuss further.) |
Best qualified to answer this is probably @AaronBallman, but I'll give my 2 cents.
That's probably the easiest solution, but it's still not easy. C code generally doesn't have any At some point we have to insert the members of the My understanding is that the attributes are parsed in a "complete type" context, i.e. lookup and semantic analysis is deferred until we've seen all members. That's likely the same in C and C++, because why would we maintain two different ways to do it? But I'm just guessing here.
Such self-referential behavior is probably not too common, at least I can't remember seeing a record containing members guarded by the record itself. It seems preferable for numerous reasons to have the mutex/capability a separate member from what it guards. So I agree with @AaronBallman, we can likely go without explicit |
I've looked into this a bit and it's kind of a weird issue where the reason this is broken is super general (there is nothing like a I have locally added something like Would this be an acceptable solution or is that still too general? Edit: Actually, doesn't a new attribute |
Not the only case. The -fbounds-safety proposal also wants to use field names as an attribute argument in C. |
Deferring to others here, but to me it sounds reasonable.
So in the initial example, instead of |
Should be fixed by #94216 |
…s and support late parsing them This fixes llvm#20777. This replaces llvm#94216 which was reverted after being merged. Previously the `guarded_by`, `pt_guarded_by`, `acquired_after`, and `acquired_before` attributes were only supported inside C++ classes or top level C/C++ declaration. This patch allows these attributes to be added to struct members in C. These attributes have also now support experimental late parsing. This is off by default but can be enabled by passing `-fexperimental-late-parse-attributes`. This is useful for referring to a struct member after the annotated member. E.g. ``` struct Example { int a_value_defined_before __attribute__ ((guarded_by(a_mutex))); struct Mutex *a_mutex; }; ```
…s and support late parsing them This fixes llvm#20777. This replaces llvm#94216 which was reverted after being merged. Previously the `guarded_by`, `pt_guarded_by`, `acquired_after`, and `acquired_before` attributes were only supported inside C++ classes or top level C/C++ declaration. This patch allows these attributes to be added to struct members in C. These attributes have also now support experimental late parsing. This is off by default but can be enabled by passing `-fexperimental-late-parse-attributes`. This is useful for referring to a struct member after the annotated member. E.g. ``` struct Example { int a_value_defined_before __attribute__ ((guarded_by(a_mutex))); struct Mutex *a_mutex; }; ```
…s and support late parsing them This fixes llvm#20777. This replaces llvm#94216 which was reverted after being merged. Previously the `guarded_by`, `pt_guarded_by`, `acquired_after`, and `acquired_before` attributes were only supported inside C++ classes or top level C/C++ declaration. This patch allows these attributes to be added to struct members in C. These attributes have also now support experimental late parsing. This is off by default but can be enabled by passing `-fexperimental-late-parse-attributes`. This is useful for referring to a struct member after the annotated member. E.g. ``` struct Example { int a_value_defined_before __attribute__ ((guarded_by(a_mutex))); struct Mutex *a_mutex; }; ```
…s and support late parsing them This fixes llvm#20777. This replaces llvm#94216 which was reverted after being merged. Previously the `guarded_by`, `pt_guarded_by`, `acquired_after`, and `acquired_before` attributes were only supported inside C++ classes or top level C/C++ declaration. This patch allows these attributes to be added to struct members in C. These attributes have also now support experimental late parsing. This is off by default but can be enabled by passing `-fexperimental-late-parse-attributes`. This is useful for referring to a struct member after the annotated member. E.g. ``` struct Example { int a_value_defined_before __attribute__ ((guarded_by(a_mutex))); struct Mutex *a_mutex; }; ```
…s and support late parsing them This fixes llvm#20777. This replaces llvm#94216 which was reverted after being merged. Previously the `guarded_by`, `pt_guarded_by`, `acquired_after`, and `acquired_before` attributes were only supported inside C++ classes or top level C/C++ declaration. This patch allows these attributes to be added to struct members in C. These attributes have also now support experimental late parsing. This is off by default but can be enabled by passing `-fexperimental-late-parse-attributes`. This is useful for referring to a struct member after the annotated member. E.g. ``` struct Example { int a_value_defined_before __attribute__ ((guarded_by(a_mutex))); struct Mutex *a_mutex; }; ```
…s and support late parsing them This fixes llvm#20777. This replaces llvm#94216 which was reverted after being merged. Previously the `guarded_by`, `pt_guarded_by`, `acquired_after`, and `acquired_before` attributes were only supported inside C++ classes or top level C/C++ declaration. This patch allows these attributes to be added to struct members in C. These attributes have also now support experimental late parsing. This is off by default but can be enabled by passing `-fexperimental-late-parse-attributes`. This is useful for referring to a struct member after the annotated member. E.g. ``` struct Example { int a_value_defined_before __attribute__ ((guarded_by(a_mutex))); struct Mutex *a_mutex; }; ```
…s and support late parsing them (#95455) This fixes #20777. This replaces #94216 which was reverted after being merged. Previously the `guarded_by`, `pt_guarded_by`, `acquired_after`, and `acquired_before` attributes were only supported inside C++ classes or top level C/C++ declaration. This patch allows these attributes to be added to struct members in C. These attributes have also now support experimental late parsing. This is off by default but can be enabled by passing `-fexperimental-late-parse-attributes`. This is useful for referring to a struct member after the annotated member. E.g. ``` struct Example { int a_value_defined_before __attribute__ ((guarded_by(a_mutex))); struct Mutex *a_mutex; }; ```
…s and support late parsing them (llvm#95455) This fixes llvm#20777. This replaces llvm#94216 which was reverted after being merged. Previously the `guarded_by`, `pt_guarded_by`, `acquired_after`, and `acquired_before` attributes were only supported inside C++ classes or top level C/C++ declaration. This patch allows these attributes to be added to struct members in C. These attributes have also now support experimental late parsing. This is off by default but can be enabled by passing `-fexperimental-late-parse-attributes`. This is useful for referring to a struct member after the annotated member. E.g. ``` struct Example { int a_value_defined_before __attribute__ ((guarded_by(a_mutex))); struct Mutex *a_mutex; }; ```
Extended Description
Clang compiles the code okay with "-x c++", so it seems to be a bug in how Thread Safety Analysis is wired into the C frontend.
The text was updated successfully, but these errors were encountered: