-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Add SAL annotations to shared_mutex. #3536
Conversation
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
…ck`'s move assign. (Still not perfect.)
Ok, I've pushed changes to address the issues I previously found, and I believe (based on command-line testing) that they improve things. However, there are some warnings being emitted in the implementation, and I haven't figured out how to avoid them yet (without blunt suppression, instead of targeted assume directives):
#include <chrono>
#include <shared_mutex>
#include <utility>
using namespace std;
using namespace std::chrono;
void test_shared_mutex() {
shared_mutex sm;
sm.lock();
sm.unlock();
if (sm.try_lock()) {
sm.unlock();
}
sm.lock_shared();
sm.unlock_shared();
if (sm.try_lock_shared()) {
sm.unlock_shared();
}
}
void test_shared_timed_mutex() {
shared_timed_mutex stm;
const duration dur = 100ms;
const time_point tp = steady_clock::now() + dur;
stm.lock();
stm.unlock();
if (stm.try_lock()) {
stm.unlock();
}
if (stm.try_lock_for(dur)) {
stm.unlock();
}
if (stm.try_lock_until(tp)) {
stm.unlock();
}
stm.lock_shared();
stm.unlock_shared();
if (stm.try_lock_shared()) {
stm.unlock_shared();
}
if (stm.try_lock_shared_for(dur)) {
stm.unlock_shared();
}
if (stm.try_lock_shared_until(tp)) {
stm.unlock_shared();
}
}
void test_shared_lock() {
using STM = shared_timed_mutex;
using SL = shared_lock<STM>;
const duration dur = 100ms;
const time_point tp = steady_clock::now() + dur;
SL default_constructed;
{
STM stm;
SL sl_mutex{stm};
}
{
STM stm;
SL sl_deferred{stm, defer_lock};
sl_deferred.lock();
sl_deferred.unlock();
if (sl_deferred.try_lock()) {
sl_deferred.unlock();
}
if (sl_deferred.try_lock_for(dur)) {
sl_deferred.unlock();
}
if (sl_deferred.try_lock_until(tp)) {
sl_deferred.unlock();
}
[[maybe_unused]] bool b1 = sl_deferred.owns_lock();
[[maybe_unused]] bool b2 = !!sl_deferred;
}
{
STM stm;
SL sl_try{stm, try_to_lock};
}
{
STM stm;
stm.lock_shared();
SL sl_adopt{stm, adopt_lock};
}
{
STM stm;
SL sl_try_for{stm, dur};
}
{
STM stm;
SL sl_try_until{stm, tp};
}
{
STM stm;
SL sl1{stm};
SL sl2{static_cast<SL&&>(sl1)};
}
{
STM cat;
STM dog;
SL sl1{cat};
SL sl2{dog};
sl1 = static_cast<SL&&>(sl2);
}
{
STM cat;
STM dog;
SL sl1{cat};
SL sl2{dog};
sl1.swap(sl2);
}
{
STM stm;
SL sl{stm};
STM* raw_ptr = sl.release();
raw_ptr->unlock_shared();
}
}
Any ideas what I'm missing here? |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
…lock_held_`. Also give it objects, not pointers.
I believe I found how to suppress the spurious warnings - my test case now compiles cleanly, while your original examples all appear to emit intended warnings. (Probably need more manual testing.) Unfortunately, I wasn't able to add the test case to the test harness for the most frustrating reason - the path to the ruleset contains spaces, which our Edit: I realized that we should be able to add a "custombuild" script (at least for the GitHub side, not MSVC-internal) to form an arbitrary command line, as we do in the Header Units and Modules tests. I can look into that later. |
Thanks again (so much) for putting extensive effort into developing this PR and responding to our feedback. We talked about this at the weekly maintainer meeting, after having contacted the compiler's static analysis team with questions about the annotations. Unfortunately, we've learned that the concurrency SAL annotations were never designed with C++ lock types in mind, and we have significant concerns about the compiler's ability to handle them robustly. (Internally, there's a concerningly small amount of test coverage for them, and none with actual C++ types with member functions like If and when the static analyzer is enhanced, we can look into resuming this work. We regret having to close your first submitted PR to the microsoft/STL repo (so sorry! 😿) but it's not your fault at all, it's ours. |
Thanks for the effort, the engagement with this PR was not expected at all. The simple cases of lock annotations in class work pretty well, I use them in other classes. |
You're welcome! I hope the compiler team can make some significant improvements here too. Thanks for reporting issues, having them tracked in DevCom helps the compiler team a lot. |
Annotate shared_mutex.
Next part can be mutex annotations #3163.
This allows compiler to catch the following mistakes: