首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Visual锁定SAL

用Visual锁定SAL
EN

Stack Overflow用户
提问于 2022-02-08 00:48:35
回答 1查看 189关注 0票数 0

我正在尝试添加锁定SAL语句,以在我的应用程序中查找/防止不正确的锁定。比如缺少锁定呼叫和不匹配的锁定呼叫。我收到了我不明白的警告。我把它们作为注释放在下面的例子中。我打开了代码分析并设置了Microsoft的所有规则。我正在使用Visual 2019 16.11.9。我还试用了Visual 2022 17.0.5并获得了相同的结果。

我已经用_Success_代替_When_了。我尝试返回bool,而不是BOOL和_Success_(返回)和_Success_(返回!= 0)。

我读过的一些研究:

https://learn.microsoft.com/en-us/cpp/code-quality/c26135?view=msvc-170

代码语言:javascript
复制
_When_(return != 0, _Acquires_lock_(p->cs))
int TryEnter(DATA* p)
{
    if (p->state != 0)
    {
        EnterCriticalSection(&p->cs);
        return p->state;
    }
    return 0;
}

前一篇文章是从2021年开始的,因此可能比后一篇Visual 2015的文章更新得更多。VS2015示例不起作用;似乎_Success_注释已经更改,因为它不再接受两个参数。

https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2015/code-quality/best-practices-and-examples-sal?view=vs-2015

代码语言:javascript
复制
// Incorrect  
_Success_(return == TRUE, _Acquires_lock_(*lpCriticalSection))  
BOOL WINAPI TryEnterCriticalSection(  
  _Inout_ LPCRITICAL_SECTION lpCriticalSection  
);  
  
// Correct  
_Success_(return != 0, _Acquires_lock_(*lpCriticalSection))  
BOOL WINAPI TryEnterCriticalSection(  
  _Inout_ LPCRITICAL_SECTION lpCriticalSection  
);  

我的测试代码:

代码语言:javascript
复制
#define _WIN32_WINNT _WIN32_WINNT_WIN7

#include <windows.h>
#include <tchar.h>

// https://learn.microsoft.com/en-us/cpp/code-quality/c26135?view=msvc-170

class CLock {
public:

    CLock() noexcept : m_hMutex(CreateMutex(nullptr,FALSE,nullptr)){
    }

    ~CLock(){

        CloseHandle(m_hMutex);

        m_hMutex = nullptr;

    }

    _When_(return != 0, _Acquires_lock_(this->m_hMutex)) BOOL Lock() noexcept {

        // warning C26135: Missing annotation _Acquires_lock_(this->m_hMutex) at function 'CLock::Lock'.
        // I don't understand this warning, I have the annotation?
        return (WaitForSingleObject(m_hMutex,INFINITE) == WAIT_OBJECT_0);

    }

    _When_(return != 0, _Releases_lock_(this->m_hMutex)) BOOL Unlock() noexcept {

        // warning C26135 : Missing annotation _Releases_lock_(this->m_hMutex) at function 'CLock::Unlock'.
        // I don't understand this warning, I have the annotation?
        return ReleaseMutex(m_hMutex);

    }

private:

    // Ensure no copies can be made
    CLock(const CLock &lCopy) = delete;
    CLock(const CLock &&lMove) = delete;
    const CLock &operator=(const CLock &lCopy) = delete;
    const CLock &&operator=(const CLock &&lMove) = delete;

    _Has_lock_kind_(_Lock_kind_mutex_) HANDLE m_hMutex;

};

class ThreadedThingy {
public:

    ThreadedThingy() noexcept : m_iThingy(0){
    }

    VOID TestBadNotLocked() noexcept {

        // warning C26130: Missing annotation _Requires_lock_held_(this->m_lLock) or _No_competing_thread_
        //                 at function 'ThreadedThingy::TestBadNotLocked'. Otherwise it could be a race
        //                 condition. Variable 'this->m_iThingy' should be protected by lock 'this->m_lLock'.
        // This should be a warning since the lock isn't held
        m_iThingy = 10;

    }

    VOID TestBadNotUnlocked() noexcept {

        if (m_lLock.Lock()){

            // warning C26165: Possibly failing to release lock '(&this->m_lLock)->m_hMutex' in function
            //                'ThreadedThingy::TestBadNotUnlocked'.
            // This should be a warning since lock isn't unlocked

            // warning C26130: Missing annotation _Requires_lock_held_(this->m_lLock) or _No_competing_thread_
            //                 at function 'ThreadedThingy::TestBadNotUnlocked'. Otherwise it could be a race
            //                 condition. Variable 'this->m_iThingy' should be protected by lock 'this->m_lLock'.
            // I don't understand this warning, the lock is held
            m_iThingy = 20;

        }

    }

    VOID TestGood() noexcept {

        if (m_lLock.Lock()){

            // warning C26130: Missing annotation _Requires_lock_held_(this->m_lLock) or _No_competing_thread_ at
            //                 function 'ThreadedThingy::TestGood'. Otherwise it could be a race condition.
            //                 Variable 'this->m_iThingy' should be protected by lock 'this->m_lLock'.
            // I don't understand this warning, the lock is held
            m_iThingy = 20;

            // warning C26165: Possibly failing to release lock '(&this->m_lLock)->m_hMutex' in function
            //                 'ThreadedThingy::TestGood'.
            // I kind of understand this warning because Unlock can't gaurentee the lock is released
            m_lLock.Unlock();

        }

    }

private:

    _Has_lock_kind_(_Lock_kind_mutex_) CLock m_lLock;

    _Guarded_by_(this->m_lLock) INT m_iThingy;

};

INT _tmain() noexcept {

    ThreadedThingy ttTest;

    ttTest.TestBadNotLocked();

    ttTest.TestBadNotUnlocked();

    ttTest.TestGood();

    return 0;

}

谢谢!

-Daniel

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-11 06:39:23

我和微软开了一张罚单,想得到一个答案。我学到了三件事。首先,当WaitForSingleObject返回WAIT_ABANDONED时,它意味着锁现在是拥有的,类似于它返回WAIT_OBJECT_0但没有发出信号的时候。因此,您必须检查这两个返回值,否则它会说您没有正确的注释。其次,静态代码分析工具假设ReleaseMutex总是释放锁。因此,解锁()上的_When_注释是不必要的/错误的。最后,还需要另一个注释将互斥锁链接到CLock对象。这个注释是_Post_same_lock_。Google并没有太多的注释,只是头文件。工作守则:

代码语言:javascript
复制
#define _WIN32_WINNT _WIN32_WINNT_WIN7

#include <windows.h>
#include <tchar.h>

class CLock {
public:

    CLock() noexcept : m_hMutex(CreateMutex(nullptr,FALSE,nullptr)){
    }

    ~CLock(){

        CloseHandle(m_hMutex);

        m_hMutex = nullptr;

    }

    _When_(return != 0, _Acquires_lock_(this->m_hMutex) _Post_same_lock_(*this, this->m_hMutex)) BOOL Lock() noexcept {

        const DWORD dwWait = WaitForSingleObject(m_hMutex, INFINITE);

        // You have to do more than this to handle WAIT_ABANDONED_0
        // This example is only about SAL, not how to corretly handle WAIT_ABANDONED_0

        return ((dwWait == WAIT_OBJECT_0) || (dwWait == WAIT_ABANDONED_0));

    }

    _Releases_lock_(this->m_hMutex) VOID Unlock() noexcept {

        ReleaseMutex(m_hMutex);

    }

private:

    // Ensure no copies can be made
    CLock(const CLock &lCopy) = delete;
    CLock(const CLock &&lMove) = delete;
    const CLock &operator=(const CLock &lCopy) = delete;
    const CLock &&operator=(const CLock &&lMove) = delete;

    _Has_lock_kind_(_Lock_kind_mutex_) HANDLE m_hMutex;

};

class ThreadedThingy {
public:

    ThreadedThingy() noexcept : m_iThingy(0){
    }

    VOID TestBadNotLocked() noexcept {

        // warning C26130: Missing annotation _Requires_lock_held_(this->m_lLock) or _No_competing_thread_
        //                 at function 'ThreadedThingy::TestBadNotLocked'. Otherwise it could be a race
        //                 condition. Variable 'this->m_iThingy' should be protected by lock 'this->m_lLock'.
        // This should be a warning since the lock isn't held
        m_iThingy = 10;

    }

    VOID TestBadNotUnlocked() noexcept {

        if (m_lLock.Lock()){

            // warning C26165: Possibly failing to release lock '(&this->m_lLock)->m_hMutex' in function
            //                'ThreadedThingy::TestBadNotUnlocked'.
            // This should be a warning since lock isn't unlocked

            m_iThingy = 20;

        }

    }

    VOID TestGood() noexcept {

        if (m_lLock.Lock()){

            m_iThingy = 20;

            m_lLock.Unlock();

        }

    }

private:

    CLock m_lLock;

    _Guarded_by_(this->m_lLock) INT m_iThingy;

};

INT _tmain() noexcept {

    ThreadedThingy ttTest;

    ttTest.TestBadNotLocked();

    ttTest.TestBadNotUnlocked();

    ttTest.TestGood();

    return 0;

}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71027258

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档