r182170 - Thread safety analysis: add two new attributes to the thread safety analysis:

Evgeniy Stepanov eugeni.stepanov at gmail.com
Mon May 20 01:23:10 PDT 2013


Hi,

there is a use-after-free in ThreadSafetyAnalyzer::intersectAndWarn.
FSet1.addLock() eventually calls FactManager::Facts.push_back(), which
invalidates all references to Facts elements.
ThreadSafetyAnalyzer::intersectAndWarn keeps one of those references
(LDat2) across the call to FSet1.addLock().

ERROR: AddressSanitizer: heap-use-after-free on address 0x61300000bf60
at pc 0x512e049 bp 0x7fffd977f790 sp 0x7fffd977f788
READ of size 1 at 0x61300000bf60 thread T0
    #0 0x512e048 in (anonymous
namespace)::ThreadSafetyAnalyzer::intersectAndWarn((anonymous
namespace)::FactSet&, (anonymous namespace)::FactSet const&,
clang::SourceLocation, clang::thread_safety::LockErrorKind,
clang::thread_safety::LockErrorKind, bool)
tools/clang/lib/Analysis/ThreadSafety.cpp:2207
    #1 0x5120b99 in intersectAndWarn
tools/clang/lib/Analysis/ThreadSafety.cpp:1471
    #2 0x5120b99 in (anonymous
namespace)::ThreadSafetyAnalyzer::runAnalysis(clang::AnalysisDeclContext&)
tools/clang/lib/Analysis/ThreadSafety.cpp:2443
    #3 0x5115ad6 in
clang::thread_safety::runThreadSafetyAnalysis(clang::AnalysisDeclContext&,
clang::thread_safety::ThreadSafetyHandler&)
tools/clang/lib/Analysis/ThreadSafety.cpp:2587
    #4 0x479b646 in
clang::sema::AnalysisBasedWarnings::IssueWarnings(clang::sema::AnalysisBasedWarnings::Policy,
clang::sema::FunctionScopeInfo*, clang::Decl const*, clang::BlockExpr
const*) tools/clang/lib/Sema/AnalysisBasedWarnings.cpp:1605
    #5 0x3d6414f in
clang::Sema::PopFunctionScopeInfo(clang::sema::AnalysisBasedWarnings::Policy
const*, clang::Decl const*, clang::BlockExpr const*)
tools/clang/lib/Sema/Sema.cpp:1028
    #6 0x3f6d6f0 in clang::Sema::ActOnFinishFunctionBody(clang::Decl*,
clang::Stmt*, bool) tools/clang/lib/Sema/SemaDecl.cpp:9021
    #7 0x369c6c8 in
clang::Parser::ParseFunctionStatementBody(clang::Decl*,
clang::Parser::ParseScope&) tools/clang/lib/Parse/ParseStmt.cpp:2403
    #8 0x3512200 in
clang::Parser::ParseFunctionDefinition(clang::ParsingDeclarator&,
clang::Parser::ParsedTemplateInfo const&,
clang::Parser::LateParsedAttrList*)
tools/clang/lib/Parse/Parser.cpp:1113
    #9 0x354ea70 in
clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec&, unsigned int,
bool, clang::SourceLocation*, clang::Parser::ForRangeInit*)
tools/clang/lib/Parse/ParseDecl.cpp:1621
    #10 0x351027d in
clang::Parser::ParseDeclOrFunctionDefInternal(clang::Parser::ParsedAttributesWithRange&,
clang::ParsingDeclSpec&, clang::AccessSpecifier)
tools/clang/lib/Parse/Parser.cpp:891
    #11 0x350f283 in
clang::Parser::ParseDeclarationOrFunctionDefinition(clang::Parser::ParsedAttributesWithRange&,
clang::ParsingDeclSpec*, clang::AccessSpecifier)
tools/clang/lib/Parse/Parser.cpp:907
    #12 0x350c3f4 in
clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange&,
clang::ParsingDeclSpec*) tools/clang/lib/Parse/Parser.cpp:772
    #13 0x3509f8f in
clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&)
tools/clang/lib/Parse/Parser.cpp:577
    #14 0x34fca0b in clang::ParseAST(clang::Sema&, bool, bool)
tools/clang/lib/Parse/ParseAST.cpp:144
    #15 0x32933d9 in clang::FrontendAction::Execute()
tools/clang/lib/Frontend/FrontendAction.cpp:378
    #16 0x322ec4e in
clang::CompilerInstance::ExecuteAction(clang::FrontendAction&)
tools/clang/lib/Frontend/CompilerInstance.cpp:685
    #17 0x2c8fc56 in
clang::ExecuteCompilerInvocation(clang::CompilerInstance*)
tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:236
    #18 0x6f8f9e in cc1_main(char const**, char const**, char const*,
void*) tools/clang/tools/driver/cc1_main.cpp:99
    #19 0x6ee153 in main tools/clang/tools/driver/driver.cpp:357

0x61300000bf60 is located 96 bytes inside of 384-byte region
[0x61300000bf00,0x61300000c080)
    #0 0x6dc1d5 in operator delete(void*)
projects/compiler-rt/lib/asan/asan_new_delete.cc:83
    #1 0x512c29d in deallocate
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/ext/new_allocator.h:98
    #2 0x512c29d in size
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/stl_vector.h:156
    #3 0x512c29d in FactEntry
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/stl_vector.h:834
    #4 0x512c29d in newLock tools/clang/lib/Analysis/ThreadSafety.cpp:810
    #5 0x512c29d in (anonymous namespace)::FactSet::addLock((anonymous
namespace)::FactManager&, (anonymous namespace)::SExpr const&,
(anonymous namespace)::LockData const&)
tools/clang/lib/Analysis/ThreadSafety.cpp:845
    #6 0x512d4ec in (anonymous
namespace)::ThreadSafetyAnalyzer::intersectAndWarn((anonymous
namespace)::FactSet&, (anonymous namespace)::FactSet const&,
clang::SourceLocation, clang::thread_safety::LockErrorKind,
clang::thread_safety::LockErrorKind, bool)
tools/clang/lib/Analysis/ThreadSafety.cpp:2204
    #7 0x5120b99 in intersectAndWarn
tools/clang/lib/Analysis/ThreadSafety.cpp:1471
    #8 0x5120b99 in (anonymous
namespace)::ThreadSafetyAnalyzer::runAnalysis(clang::AnalysisDeclContext&)
tools/clang/lib/Analysis/ThreadSafety.cpp:2443
    #9 0x5115ad6 in
clang::thread_safety::runThreadSafetyAnalysis(clang::AnalysisDeclContext&,
clang::thread_safety::ThreadSafetyHandler&)
tools/clang/lib/Analysis/ThreadSafety.cpp:2587
    #10 0x479b646 in
clang::sema::AnalysisBasedWarnings::IssueWarnings(clang::sema::AnalysisBasedWarnings::Policy,
clang::sema::FunctionScopeInfo*, clang::Decl const*, clang::BlockExpr
const*) tools/clang/lib/Sema/AnalysisBasedWarnings.cpp:1605
    #11 0x3d6414f in
clang::Sema::PopFunctionScopeInfo(clang::sema::AnalysisBasedWarnings::Policy
const*, clang::Decl const*, clang::BlockExpr const*)
tools/clang/lib/Sema/Sema.cpp:1028
    #12 0x3f6d6f0 in
clang::Sema::ActOnFinishFunctionBody(clang::Decl*, clang::Stmt*, bool)
tools/clang/lib/Sema/SemaDecl.cpp:9021
    #13 0x369c6c8 in
clang::Parser::ParseFunctionStatementBody(clang::Decl*,
clang::Parser::ParseScope&) tools/clang/lib/Parse/ParseStmt.cpp:2403
    #14 0x3512200 in
clang::Parser::ParseFunctionDefinition(clang::ParsingDeclarator&,
clang::Parser::ParsedTemplateInfo const&,
clang::Parser::LateParsedAttrList*)
tools/clang/lib/Parse/Parser.cpp:1113
    #15 0x354ea70 in
clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec&, unsigned int,
bool, clang::SourceLocation*, clang::Parser::ForRangeInit*)
tools/clang/lib/Parse/ParseDecl.cpp:1621
    #16 0x351027d in
clang::Parser::ParseDeclOrFunctionDefInternal(clang::Parser::ParsedAttributesWithRange&,
clang::ParsingDeclSpec&, clang::AccessSpecifier)
tools/clang/lib/Parse/Parser.cpp:891
    #17 0x350f283 in
clang::Parser::ParseDeclarationOrFunctionDefinition(clang::Parser::ParsedAttributesWithRange&,
clang::ParsingDeclSpec*, clang::AccessSpecifier)
tools/clang/lib/Parse/Parser.cpp:907
    #18 0x350c3f4 in
clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange&,
clang::ParsingDeclSpec*) tools/clang/lib/Parse/Parser.cpp:772
    #19 0x3509f8f in
clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&)
tools/clang/lib/Parse/Parser.cpp:577
    #20 0x34fca0b in clang::ParseAST(clang::Sema&, bool, bool)
tools/clang/lib/Parse/ParseAST.cpp:144
    #21 0x32933d9 in clang::FrontendAction::Execute()
tools/clang/lib/Frontend/FrontendAction.cpp:378
    #22 0x322ec4e in
clang::CompilerInstance::ExecuteAction(clang::FrontendAction&)
tools/clang/lib/Frontend/CompilerInstance.cpp:685
    #23 0x2c8fc56 in
clang::ExecuteCompilerInvocation(clang::CompilerInstance*)
tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:236
    #24 0x6f8f9e in cc1_main(char const**, char const**, char const*,
void*) tools/clang/tools/driver/cc1_main.cpp:99
    #25 0x6ee153 in main tools/clang/tools/driver/driver.cpp:357

previously allocated by thread T0 here:
    #0 0x6dbf15 in operator new(unsigned long)
projects/compiler-rt/lib/asan/asan_new_delete.cc:52
    #1 0x512baf0 in allocate
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/ext/new_allocator.h:92
    #2 0x512baf0 in size
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/stl_vector.h:150
    #3 0x512baf0 in FactEntry
/usr/lib/gcc/x86_64-linux-gnu/4.6/../../../../include/c++/4.6/bits/stl_vector.h:834
    #4 0x512baf0 in newLock tools/clang/lib/Analysis/ThreadSafety.cpp:810
    #5 0x512baf0 in (anonymous namespace)::FactSet::addLock((anonymous
namespace)::FactManager&, (anonymous namespace)::SExpr const&,
(anonymous namespace)::LockData const&)
tools/clang/lib/Analysis/ThreadSafety.cpp:845
    #6 0x51254ab in (anonymous
namespace)::ThreadSafetyAnalyzer::addLock((anonymous
namespace)::FactSet&, (anonymous namespace)::SExpr const&, (anonymous
namespace)::LockData const&)
tools/clang/lib/Analysis/ThreadSafety.cpp:1492
    #7 0x5129424 in (anonymous
namespace)::BuildLockset::handleCall(clang::Expr*, clang::NamedDecl
const*, clang::VarDecl*)
tools/clang/lib/Analysis/ThreadSafety.cpp:2020
    #8 0x512137c in Visit
llvm_build_asan/tools/clang/include/clang/AST/StmtNodes.inc:293
    #9 0x512137c in (anonymous
namespace)::ThreadSafetyAnalyzer::runAnalysis(clang::AnalysisDeclContext&)
tools/clang/lib/Analysis/ThreadSafety.cpp:2494
    #10 0x5115ad6 in
clang::thread_safety::runThreadSafetyAnalysis(clang::AnalysisDeclContext&,
clang::thread_safety::ThreadSafetyHandler&)
tools/clang/lib/Analysis/ThreadSafety.cpp:2587
    #11 0x479b646 in
clang::sema::AnalysisBasedWarnings::IssueWarnings(clang::sema::AnalysisBasedWarnings::Policy,
clang::sema::FunctionScopeInfo*, clang::Decl const*, clang::BlockExpr
const*) tools/clang/lib/Sema/AnalysisBasedWarnings.cpp:1605
    #12 0x3d6414f in
clang::Sema::PopFunctionScopeInfo(clang::sema::AnalysisBasedWarnings::Policy
const*, clang::Decl const*, clang::BlockExpr const*)
tools/clang/lib/Sema/Sema.cpp:1028
    #13 0x3f6d6f0 in
clang::Sema::ActOnFinishFunctionBody(clang::Decl*, clang::Stmt*, bool)
tools/clang/lib/Sema/SemaDecl.cpp:9021
    #14 0x369c6c8 in
clang::Parser::ParseFunctionStatementBody(clang::Decl*,
clang::Parser::ParseScope&) tools/clang/lib/Parse/ParseStmt.cpp:2403
    #15 0x3512200 in
clang::Parser::ParseFunctionDefinition(clang::ParsingDeclarator&,
clang::Parser::ParsedTemplateInfo const&,
clang::Parser::LateParsedAttrList*)
tools/clang/lib/Parse/Parser.cpp:1113
    #16 0x354ea70 in
clang::Parser::ParseDeclGroup(clang::ParsingDeclSpec&, unsigned int,
bool, clang::SourceLocation*, clang::Parser::ForRangeInit*)
tools/clang/lib/Parse/ParseDecl.cpp:1621
    #17 0x351027d in
clang::Parser::ParseDeclOrFunctionDefInternal(clang::Parser::ParsedAttributesWithRange&,
clang::ParsingDeclSpec&, clang::AccessSpecifier)
tools/clang/lib/Parse/Parser.cpp:891
    #18 0x350f283 in
clang::Parser::ParseDeclarationOrFunctionDefinition(clang::Parser::ParsedAttributesWithRange&,
clang::ParsingDeclSpec*, clang::AccessSpecifier)
tools/clang/lib/Parse/Parser.cpp:907
    #19 0x350c3f4 in
clang::Parser::ParseExternalDeclaration(clang::Parser::ParsedAttributesWithRange&,
clang::ParsingDeclSpec*) tools/clang/lib/Parse/Parser.cpp:772
    #20 0x3509f8f in
clang::Parser::ParseTopLevelDecl(clang::OpaquePtr<clang::DeclGroupRef>&)
tools/clang/lib/Parse/Parser.cpp:577
    #21 0x34fca0b in clang::ParseAST(clang::Sema&, bool, bool)
tools/clang/lib/Parse/ParseAST.cpp:144
    #22 0x32933d9 in clang::FrontendAction::Execute()
tools/clang/lib/Frontend/FrontendAction.cpp:378
    #23 0x322ec4e in
clang::CompilerInstance::ExecuteAction(clang::FrontendAction&)
tools/clang/lib/Frontend/CompilerInstance.cpp:685
    #24 0x2c8fc56 in
clang::ExecuteCompilerInvocation(clang::CompilerInstance*)
tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:236
    #25 0x6f8f9e in cc1_main(char const**, char const**, char const*,
void*) tools/clang/tools/driver/cc1_main.cpp:99
    #26 0x6ee153 in main tools/clang/tools/driver/driver.cpp:357

On Sat, May 18, 2013 at 1:02 AM, DeLesley Hutchins <delesley at google.com> wrote:
> Author: delesley
> Date: Fri May 17 18:02:59 2013
> New Revision: 182170
>
> URL: http://llvm.org/viewvc/llvm-project?rev=182170&view=rev
> Log:
> Thread safety analysis: add two new attributes to the thread safety analysis:
> assert_exclusive_lock and assert_shared_lock.  These attributes are used to
> mark functions that dynamically check (i.e. assert) that a lock is held.
>
> Modified:
>     cfe/trunk/include/clang/Basic/Attr.td
>     cfe/trunk/lib/Analysis/ThreadSafety.cpp
>     cfe/trunk/lib/Sema/SemaDeclAttr.cpp
>     cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp
>     cfe/trunk/test/SemaCXX/warn-thread-safety-parsing.cpp
>
> Modified: cfe/trunk/include/clang/Basic/Attr.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=182170&r1=182169&r2=182170&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/Attr.td (original)
> +++ cfe/trunk/include/clang/Basic/Attr.td Fri May 17 18:02:59 2013
> @@ -852,6 +852,20 @@ def SharedLockFunction : InheritableAttr
>    let TemplateDependent = 1;
>  }
>
> +def AssertExclusiveLock : InheritableAttr {
> +  let Spellings = [GNU<"assert_exclusive_lock">];
> +  let Args = [VariadicExprArgument<"Args">];
> +  let LateParsed = 1;
> +  let TemplateDependent = 1;
> +}
> +
> +def AssertSharedLock : InheritableAttr {
> +  let Spellings = [GNU<"assert_shared_lock">];
> +  let Args = [VariadicExprArgument<"Args">];
> +  let LateParsed = 1;
> +  let TemplateDependent = 1;
> +}
> +
>  // The first argument is an integer or boolean value specifying the return value
>  // of a successful lock acquisition.
>  def ExclusiveTrylockFunction : InheritableAttr {
>
> Modified: cfe/trunk/lib/Analysis/ThreadSafety.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafety.cpp?rev=182170&r1=182169&r2=182170&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Analysis/ThreadSafety.cpp (original)
> +++ cfe/trunk/lib/Analysis/ThreadSafety.cpp Fri May 17 18:02:59 2013
> @@ -750,16 +750,18 @@ struct LockData {
>    ///
>    /// FIXME: add support for re-entrant locking and lock up/downgrading
>    LockKind LKind;
> +  bool     Asserted;           // for asserted locks
>    bool     Managed;            // for ScopedLockable objects
>    SExpr    UnderlyingMutex;    // for ScopedLockable objects
>
> -  LockData(SourceLocation AcquireLoc, LockKind LKind, bool M = false)
> -    : AcquireLoc(AcquireLoc), LKind(LKind), Managed(M),
> +  LockData(SourceLocation AcquireLoc, LockKind LKind, bool M=false,
> +           bool Asrt=false)
> +    : AcquireLoc(AcquireLoc), LKind(LKind), Asserted(Asrt), Managed(M),
>        UnderlyingMutex(Decl::EmptyShell())
>    {}
>
>    LockData(SourceLocation AcquireLoc, LockKind LKind, const SExpr &Mu)
> -    : AcquireLoc(AcquireLoc), LKind(LKind), Managed(false),
> +    : AcquireLoc(AcquireLoc), LKind(LKind), Asserted(false), Managed(false),
>        UnderlyingMutex(Mu)
>    {}
>
> @@ -1484,7 +1486,8 @@ void ThreadSafetyAnalyzer::addLock(FactS
>      return;
>
>    if (FSet.findLock(FactMan, Mutex)) {
> -    Handler.handleDoubleLock(Mutex.toString(), LDat.AcquireLoc);
> +    if (!LDat.Asserted)
> +      Handler.handleDoubleLock(Mutex.toString(), LDat.AcquireLoc);
>    } else {
>      FSet.addLock(FactMan, Mutex, LDat);
>    }
> @@ -1909,6 +1912,7 @@ void BuildLockset::checkPtAccess(const E
>  /// the same signature as const method calls can be also treated as reads.
>  ///
>  void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) {
> +  SourceLocation Loc = Exp->getExprLoc();
>    const AttrVec &ArgAttrs = D->getAttrs();
>    MutexIDList ExclusiveLocksToAdd;
>    MutexIDList SharedLocksToAdd;
> @@ -1933,6 +1937,32 @@ void BuildLockset::handleCall(Expr *Exp,
>          break;
>        }
>
> +      // An assert will add a lock to the lockset, but will not generate
> +      // a warning if it is already there, and will not generate a warning
> +      // if it is not removed.
> +      case attr::AssertExclusiveLock: {
> +        AssertExclusiveLockAttr *A = cast<AssertExclusiveLockAttr>(At);
> +
> +        MutexIDList AssertLocks;
> +        Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
> +        for (unsigned i=0,n=AssertLocks.size(); i<n; ++i) {
> +          Analyzer->addLock(FSet, AssertLocks[i],
> +                            LockData(Loc, LK_Exclusive, false, true));
> +        }
> +        break;
> +      }
> +      case attr::AssertSharedLock: {
> +        AssertSharedLockAttr *A = cast<AssertSharedLockAttr>(At);
> +
> +        MutexIDList AssertLocks;
> +        Analyzer->getMutexIDs(AssertLocks, A, Exp, D, VD);
> +        for (unsigned i=0,n=AssertLocks.size(); i<n; ++i) {
> +          Analyzer->addLock(FSet, AssertLocks[i],
> +                            LockData(Loc, LK_Shared, false, true));
> +        }
> +        break;
> +      }
> +
>        // When we encounter an unlock function, we need to remove unlocked
>        // mutexes from the lockset, and flag a warning if they are not there.
>        case attr::UnlockFunction: {
> @@ -1986,7 +2016,6 @@ void BuildLockset::handleCall(Expr *Exp,
>    }
>
>    // Add locks.
> -  SourceLocation Loc = Exp->getExprLoc();
>    for (unsigned i=0,n=ExclusiveLocksToAdd.size(); i<n; ++i) {
>      Analyzer->addLock(FSet, ExclusiveLocksToAdd[i],
>                              LockData(Loc, LK_Exclusive, isScopedVar));
> @@ -2165,7 +2194,7 @@ void ThreadSafetyAnalyzer::intersectAndW
>      const SExpr &FSet2Mutex = FactMan[*I].MutID;
>      const LockData &LDat2 = FactMan[*I].LDat;
>
> -    if (const LockData *LDat1 = FSet1.findLock(FactMan, FSet2Mutex)) {
> +    if (LockData *LDat1 = FSet1.findLock(FactMan, FSet2Mutex)) {
>        if (LDat1->LKind != LDat2.LKind) {
>          Handler.handleExclusiveAndShared(FSet2Mutex.toString(),
>                                           LDat2.AcquireLoc,
> @@ -2175,6 +2204,10 @@ void ThreadSafetyAnalyzer::intersectAndW
>            FSet1.addLock(FactMan, FSet2Mutex, LDat2);
>          }
>        }
> +      if (LDat1->Asserted && !LDat2.Asserted) {
> +        // The non-asserted lock is the one we want to track.
> +        *LDat1 = LDat2;
> +      }
>      } else {
>        if (LDat2.UnderlyingMutex.isValid()) {
>          if (FSet2.findLock(FactMan, LDat2.UnderlyingMutex)) {
> @@ -2186,7 +2219,7 @@ void ThreadSafetyAnalyzer::intersectAndW
>                                              JoinLoc, LEK1);
>          }
>        }
> -      else if (!LDat2.Managed && !FSet2Mutex.isUniversal())
> +      else if (!LDat2.Managed && !FSet2Mutex.isUniversal() && !LDat2.Asserted)
>          Handler.handleMutexHeldEndOfScope(FSet2Mutex.toString(),
>                                            LDat2.AcquireLoc,
>                                            JoinLoc, LEK1);
> @@ -2209,7 +2242,7 @@ void ThreadSafetyAnalyzer::intersectAndW
>                                              JoinLoc, LEK1);
>          }
>        }
> -      else if (!LDat1.Managed && !FSet1Mutex.isUniversal())
> +      else if (!LDat1.Managed && !FSet1Mutex.isUniversal() && !LDat1.Asserted)
>          Handler.handleMutexHeldEndOfScope(FSet1Mutex.toString(),
>                                            LDat1.AcquireLoc,
>                                            JoinLoc, LEK2);
>
> Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=182170&r1=182169&r2=182170&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Fri May 17 18:02:59 2013
> @@ -788,6 +788,34 @@ static void handleExclusiveLockFunctionA
>                                         Attr.getAttributeSpellingListIndex()));
>  }
>
> +static void handleAssertSharedLockAttr(Sema &S, Decl *D,
> +                                       const AttributeList &Attr) {
> +  SmallVector<Expr*, 1> Args;
> +  if (!checkLockFunAttrCommon(S, D, Attr, Args))
> +    return;
> +
> +  unsigned Size = Args.size();
> +  Expr **StartArg = Size == 0 ? 0 : &Args[0];
> +  D->addAttr(::new (S.Context)
> +             AssertSharedLockAttr(Attr.getRange(), S.Context, StartArg, Size,
> +                                  Attr.getAttributeSpellingListIndex()));
> +}
> +
> +static void handleAssertExclusiveLockAttr(Sema &S, Decl *D,
> +                                          const AttributeList &Attr) {
> +  SmallVector<Expr*, 1> Args;
> +  if (!checkLockFunAttrCommon(S, D, Attr, Args))
> +    return;
> +
> +  unsigned Size = Args.size();
> +  Expr **StartArg = Size == 0 ? 0 : &Args[0];
> +  D->addAttr(::new (S.Context)
> +             AssertExclusiveLockAttr(Attr.getRange(), S.Context,
> +                                     StartArg, Size,
> +                                     Attr.getAttributeSpellingListIndex()));
> +}
> +
> +
>  static bool checkTryLockFunAttrCommon(Sema &S, Decl *D,
>                                        const AttributeList &Attr,
>                                        SmallVector<Expr*, 2> &Args) {
> @@ -4918,6 +4946,12 @@ static void ProcessInheritableDeclAttr(S
>      break;
>
>    // Thread safety attributes:
> +  case AttributeList::AT_AssertExclusiveLock:
> +    handleAssertExclusiveLockAttr(S, D, Attr);
> +    break;
> +  case AttributeList::AT_AssertSharedLock:
> +    handleAssertSharedLockAttr(S, D, Attr);
> +    break;
>    case AttributeList::AT_GuardedVar:
>      handleGuardedVarAttr(S, D, Attr);
>      break;
>
> Modified: cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp?rev=182170&r1=182169&r2=182170&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp (original)
> +++ cfe/trunk/test/SemaCXX/warn-thread-safety-analysis.cpp Fri May 17 18:02:59 2013
> @@ -11,8 +11,10 @@
>  #define PT_GUARDED_VAR      __attribute__ ((pt_guarded_var))
>  #define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))
>  #define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__)))
> -#define EXCLUSIVE_LOCK_FUNCTION(...)   __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
> -#define SHARED_LOCK_FUNCTION(...)      __attribute__ ((shared_lock_function(__VA_ARGS__)))
> +#define EXCLUSIVE_LOCK_FUNCTION(...)    __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
> +#define SHARED_LOCK_FUNCTION(...)       __attribute__ ((shared_lock_function(__VA_ARGS__)))
> +#define ASSERT_EXCLUSIVE_LOCK(...)      __attribute__ ((assert_exclusive_lock(__VA_ARGS__)))
> +#define ASSERT_SHARED_LOCK(...)         __attribute__ ((assert_shared_lock(__VA_ARGS__)))
>  #define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__ ((exclusive_trylock_function(__VA_ARGS__)))
>  #define SHARED_TRYLOCK_FUNCTION(...)    __attribute__ ((shared_trylock_function(__VA_ARGS__)))
>  #define UNLOCK_FUNCTION(...)            __attribute__ ((unlock_function(__VA_ARGS__)))
> @@ -33,6 +35,9 @@ class  __attribute__((lockable)) Mutex {
>    bool TryLock() __attribute__((exclusive_trylock_function(true)));
>    bool ReaderTryLock() __attribute__((shared_trylock_function(true)));
>    void LockWhen(const int &cond) __attribute__((exclusive_lock_function));
> +
> +  void AssertHeld()       ASSERT_EXCLUSIVE_LOCK();
> +  void AssertReaderHeld() ASSERT_SHARED_LOCK();
>  };
>
>  class __attribute__((scoped_lockable)) MutexLock {
> @@ -3985,3 +3990,105 @@ private:
>
>  }  // end namespace LockUnlockFunctionTest
>
> +
> +namespace AssertHeldTest {
> +
> +class Foo {
> +public:
> +  int c;
> +  int a GUARDED_BY(mu_);
> +  Mutex mu_;
> +
> +  void test1() {
> +    mu_.AssertHeld();
> +    int b = a;
> +    a = 0;
> +  }
> +
> +  void test2() {
> +    mu_.AssertReaderHeld();
> +    int b = a;
> +    a = 0;   // expected-warning {{writing variable 'a' requires locking 'mu_' exclusively}}
> +  }
> +
> +  void test3() {
> +    if (c) {
> +      mu_.AssertHeld();
> +    }
> +    else {
> +      mu_.AssertHeld();
> +    }
> +    int b = a;
> +    a = 0;
> +  }
> +
> +  void test4() EXCLUSIVE_LOCKS_REQUIRED(mu_) {
> +    mu_.AssertHeld();
> +    int b = a;
> +    a = 0;
> +  }
> +
> +  void test5() UNLOCK_FUNCTION(mu_) {
> +    mu_.AssertHeld();
> +    mu_.Unlock();
> +  }
> +
> +  void test6() {
> +    mu_.AssertHeld();
> +    mu_.Unlock();
> +  }  // should this be a warning?
> +
> +  void test7() {
> +    if (c) {
> +      mu_.AssertHeld();
> +    }
> +    else {
> +      mu_.Lock();
> +    }
> +    int b = a;
> +    a = 0;
> +    mu_.Unlock();
> +  }
> +
> +  void test8() {
> +    if (c) {
> +      mu_.Lock();
> +    }
> +    else {
> +      mu_.AssertHeld();
> +    }
> +    int b = a;
> +    a = 0;
> +    mu_.Unlock();
> +  }
> +
> +  void test9() {
> +    if (c) {
> +      mu_.AssertHeld();
> +    }
> +    else {
> +      mu_.Lock();  // expected-note {{mutex acquired here}}
> +    }
> +  }  // expected-warning {{mutex 'mu_' is still locked at the end of function}}
> +
> +  void test10() {
> +    if (c) {
> +      mu_.Lock();  // expected-note {{mutex acquired here}}
> +    }
> +    else {
> +      mu_.AssertHeld();
> +    }
> +  }  // expected-warning {{mutex 'mu_' is still locked at the end of function}}
> +
> +  void assertMu() ASSERT_EXCLUSIVE_LOCK(mu_);
> +
> +  void test11() {
> +    assertMu();
> +    int b = a;
> +    a = 0;
> +  }
> +};
> +
> +}  // end namespace AssertHeldTest
> +
> +
>
> Modified: cfe/trunk/test/SemaCXX/warn-thread-safety-parsing.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/warn-thread-safety-parsing.cpp?rev=182170&r1=182169&r2=182170&view=diff
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/warn-thread-safety-parsing.cpp (original)
> +++ cfe/trunk/test/SemaCXX/warn-thread-safety-parsing.cpp Fri May 17 18:02:59 2013
> @@ -8,8 +8,10 @@
>  #define PT_GUARDED_VAR      __attribute__ ((pt_guarded_var))
>  #define ACQUIRED_AFTER(...) __attribute__ ((acquired_after(__VA_ARGS__)))
>  #define ACQUIRED_BEFORE(...) __attribute__ ((acquired_before(__VA_ARGS__)))
> -#define EXCLUSIVE_LOCK_FUNCTION(...)   __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
> -#define SHARED_LOCK_FUNCTION(...)      __attribute__ ((shared_lock_function(__VA_ARGS__)))
> +#define EXCLUSIVE_LOCK_FUNCTION(...)    __attribute__ ((exclusive_lock_function(__VA_ARGS__)))
> +#define SHARED_LOCK_FUNCTION(...)       __attribute__ ((shared_lock_function(__VA_ARGS__)))
> +#define ASSERT_EXCLUSIVE_LOCK(...)      __attribute__ ((assert_exclusive_lock(__VA_ARGS__)))
> +#define ASSERT_SHARED_LOCK(...)         __attribute__ ((assert_shared_lock(__VA_ARGS__)))
>  #define EXCLUSIVE_TRYLOCK_FUNCTION(...) __attribute__ ((exclusive_trylock_function(__VA_ARGS__)))
>  #define SHARED_TRYLOCK_FUNCTION(...)    __attribute__ ((shared_trylock_function(__VA_ARGS__)))
>  #define UNLOCK_FUNCTION(...)            __attribute__ ((unlock_function(__VA_ARGS__)))
> @@ -24,7 +26,15 @@
>
>  class LOCKABLE Mutex {
>    public:
> -  void Lock();
> +  void Lock()          EXCLUSIVE_LOCK_FUNCTION();
> +  void ReaderLock()    SHARED_LOCK_FUNCTION();
> +  void Unlock()        UNLOCK_FUNCTION();
> +
> +  bool TryLock()       EXCLUSIVE_TRYLOCK_FUNCTION(true);
> +  bool ReaderTryLock() SHARED_TRYLOCK_FUNCTION(true);
> +
> +  void AssertHeld()       ASSERT_EXCLUSIVE_LOCK();
> +  void AssertReaderHeld() ASSERT_SHARED_LOCK();
>  };
>
>  class UnlockableMu{
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list