[cfe-dev] static Matcher generate Use After Free

Maxim Ostapenko via cfe-dev cfe-dev at lists.llvm.org
Thu Jun 8 05:14:19 PDT 2017


CC'ing Samuel, Alexey and Ilya.

On 06/06/17 12:55, Artem Dergachev wrote:
> Dunno. Crashes i've seen were random, so i'm not sure if being static 
> is the only requirement.

Yeah, you are right, this is not enough. E.g. when I tried to make 
several checkers static in NumberObjectConversionChecker.cpp nothing 
changed (everything works fine).
However, when I've added following checker into 
NumberObjectConversionChecker.cpp:

   static auto varD =
       expr(
         hasDescendant(
           declRefExpr(
             hasDeclaration(
               varDecl().bind("var")))));

I've actually got a use after free bug (ASan log is below). I'm not sure 
how to fix this, but this is non-obvious even for experienced developers 
that in some (non-obvious) cases static matchers don't work. IMHO this 
is a bug that needs to be fixed upstream.

-Maxim

$ /home/maxim/src/build/upstream/build_asan/./bin/clang -cc1 
-internal-isystem 
/home/maxim/src/build/upstream/build_asan/lib/clang/5.0.0/include 
-nostdsysteminc -analyze -analyzer-constraints=range 
-analyzer-checker=osx,unix,core,alpha.security.taint -w -verify 
/home/maxim/src/llvm-upstream/tools/clang/test/Analysis/redefined_system.c
=================================================================
==30739==ERROR: AddressSanitizer: heap-use-after-free on address 
0x602000000eb8 at pc 0x00000848963e bp 0x7ffe83e19d10 sp 0x7ffe83e19d08
WRITE of size 4 at 0x602000000eb8 thread T0
     #0 0x848963d in fetch_sub 
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/atomic_base.h:624:16
     #1 0x848963d in Release 
/home/maxim/src/llvm-upstream/include/llvm/ADT/IntrusiveRefCntPtr.h:97
     #2 0x848963d in release 
/home/maxim/src/llvm-upstream/include/llvm/ADT/IntrusiveRefCntPtr.h:126
     #3 0x848963d in release 
/home/maxim/src/llvm-upstream/include/llvm/ADT/IntrusiveRefCntPtr.h:188
     #4 0x848963d in ~IntrusiveRefCntPtr 
/home/maxim/src/llvm-upstream/include/llvm/ADT/IntrusiveRefCntPtr.h:161
     #5 0x848963d in ~IdDynMatcher 
/home/maxim/src/llvm-upstream/tools/clang/lib/ASTMatchers/ASTMatchersInternal.cpp:74
     #6 0x848963d in clang::ast_matchers::internal::(anonymous 
namespace)::IdDynMatcher::~IdDynMatcher() 
/home/maxim/src/llvm-upstream/tools/clang/lib/ASTMatchers/ASTMatchersInternal.cpp:74
     #7 0x8173510 in Release 
/home/maxim/src/llvm-upstream/include/llvm/ADT/IntrusiveRefCntPtr.h:100:7
     #8 0x8173510 in release 
/home/maxim/src/llvm-upstream/include/llvm/ADT/IntrusiveRefCntPtr.h:126
     #9 0x8173510 in release 
/home/maxim/src/llvm-upstream/include/llvm/ADT/IntrusiveRefCntPtr.h:188
     #10 0x8173510 in ~IntrusiveRefCntPtr 
/home/maxim/src/llvm-upstream/include/llvm/ADT/IntrusiveRefCntPtr.h:161
     #11 0x8173510 in ~DynTypedMatcher 
/home/maxim/src/llvm-upstream/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h:315
     #12 0x8173510 in ~WrapperMatcherInterface 
/home/maxim/src/llvm-upstream/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h:451
     #13 0x8173510 in 
clang::ast_matchers::internal::HasDeclarationMatcher<clang::DeclRefExpr, 
clang::ast_matchers::internal::Matcher<clang::Decl> 
 >::~HasDeclarationMatcher() 
/home/maxim/src/llvm-upstream/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h:717
     #14 0x8167c80 in Release 
/home/maxim/src/llvm-upstream/include/llvm/ADT/IntrusiveRefCntPtr.h:100:7
     #15 0x8167c80 in release 
/home/maxim/src/llvm-upstream/include/llvm/ADT/IntrusiveRefCntPtr.h:126
     #16 0x8167c80 in release 
/home/maxim/src/llvm-upstream/include/llvm/ADT/IntrusiveRefCntPtr.h:188
     #17 0x8167c80 in ~IntrusiveRefCntPtr 
/home/maxim/src/llvm-upstream/include/llvm/ADT/IntrusiveRefCntPtr.h:161
     #18 0x8167c80 in ~DynTypedMatcher 
/home/maxim/src/llvm-upstream/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h:315
     #19 0x8167c80 in ~WrapperMatcherInterface 
/home/maxim/src/llvm-upstream/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h:451
     #20 0x8167c80 in 
clang::ast_matchers::internal::HasDescendantMatcher<clang::Expr, 
clang::Stmt>::~HasDescendantMatcher() 
/home/maxim/src/llvm-upstream/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h:1319
     #21 0x7fdda7b6f1a8 in __run_exit_handlers 
/build/eglibc-MjiXCM/eglibc-2.19/stdlib/exit.c:82
     #22 0x7fdda7b6f1f4 in exit 
/build/eglibc-MjiXCM/eglibc-2.19/stdlib/exit.c:104
     #23 0x7fdda7b54f4b in __libc_start_main 
/build/eglibc-MjiXCM/eglibc-2.19/csu/libc-start.c:321
     #24 0x8601fd in _start 
(/home/maxim/src/build/upstream/build_asan/bin/clang-5.0+0x8601fd)

0x602000000eb8 is located 8 bytes inside of 16-byte region 
[0x602000000eb0,0x602000000ec0)
freed by thread T0 here:
     #0 0x96a520 in operator delete(void*) 
/home/maxim/src/llvm-upstream/projects/compiler-rt/lib/asan/asan_new_delete.cc:126
     #1 0x32c99ba in destroy 
/home/maxim/src/llvm-upstream/lib/Support/ManagedStatic.cpp:75:3
     #2 0x32c99ba in llvm::llvm_shutdown() 
/home/maxim/src/llvm-upstream/lib/Support/ManagedStatic.cpp:87
     #3 0x97452b in ~llvm_shutdown_obj 
/home/maxim/src/llvm-upstream/include/llvm/Support/ManagedStatic.h:92:26
     #4 0x97452b in main 
/home/maxim/src/llvm-upstream/tools/clang/tools/driver/driver.cpp:512
     #5 0x7fdda7b54f44 in __libc_start_main 
/build/eglibc-MjiXCM/eglibc-2.19/csu/libc-start.c:287

previously allocated by thread T0 here:
     #0 0x9697a0 in operator new(unsigned long) 
/home/maxim/src/llvm-upstream/projects/compiler-rt/lib/asan/asan_new_delete.cc:82
     #1 0x848bcdd in 
llvm::object_creator<clang::ast_matchers::internal::(anonymous 
namespace)::TrueMatcherImpl>::call() 
/home/maxim/src/llvm-upstream/include/llvm/Support/ManagedStatic.h:24:32
     #2 0x32c93c3 in 
llvm::ManagedStaticBase::RegisterManagedStatic(void* (*)(), void 
(*)(void*)) const 
/home/maxim/src/llvm-upstream/lib/Support/ManagedStatic.cpp:45:19
     #3 0x84823f0 in operator* 
/home/maxim/src/llvm-upstream/include/llvm/Support/ManagedStatic.h:67:7
     #4 0x84823f0 in 
clang::ast_matchers::internal::DynTypedMatcher::trueMatcher(clang::ast_type_traits::ASTNodeKind) 
/home/maxim/src/llvm-upstream/tools/clang/lib/ASTMatchers/ASTMatchersInternal.cpp:165
     #5 0x816f4f8 in operator Matcher<clang::VarDecl> 
/home/maxim/src/llvm-upstream/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h:1145:12
     #6 0x816f4f8 in 
clang::ast_matchers::internal::BindableMatcher<clang::VarDecl> 
clang::ast_matchers::internal::makeAllOfComposite<clang::VarDecl>(llvm::ArrayRef<clang::ast_matchers::internal::Matcher<clang::VarDecl> 
const*>) 
/home/maxim/src/llvm-upstream/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h:1282
     #7 0x816f0b3 in 
clang::ast_matchers::internal::BindableMatcher<clang::Decl> 
clang::ast_matchers::internal::makeDynCastAllOfComposite<clang::Decl, 
clang::VarDecl>(llvm::ArrayRef<clang::ast_matchers::internal::Matcher<clang::VarDecl> 
const*>) 
/home/maxim/src/llvm-upstream/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h:1311:7
     #8 0x813f3a2 in operator() 
/home/maxim/src/llvm-upstream/tools/clang/include/clang/ASTMatchers/ASTMatchersInternal.h:72:39
     #9 0x813f3a2 in (anonymous 
namespace)::NumberObjectConversionChecker::checkASTCodeBody(clang::Decl 
const*, clang::ento::AnalysisManager&, clang::ento::BugReporter&) const 
/home/maxim/src/llvm-upstream/tools/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp:341
     #10 0x852fe39 in operator() 
/home/maxim/src/llvm-upstream/tools/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h:59:12
     #11 0x852fe39 in 
clang::ento::CheckerManager::runCheckersOnASTBody(clang::Decl const*, 
clang::ento::AnalysisManager&, clang::ento::BugReporter&) 
/home/maxim/src/llvm-upstream/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp:86
     #12 0x60315c1 in (anonymous 
namespace)::AnalysisConsumer::HandleCode(clang::Decl*, unsigned int, 
clang::ento::ExprEngine::InliningModes, llvm::DenseSet<clang::Decl 
const*, llvm::DenseMapInfo<clang::Decl const*> >*) 
/home/maxim/src/llvm-upstream/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:683:17
     #13 0x6020cb0 in clang::RecursiveASTVisitor<(anonymous 
namespace)::AnalysisConsumer>::TraverseDecl(clang::Decl*) 
/home/maxim/src/llvm-upstream/tools/clang/include/clang/AST/RecursiveASTVisitor.h
     #14 0x601bebf in (anonymous 
namespace)::AnalysisConsumer::HandleTranslationUnit(clang::ASTContext&) 
/home/maxim/src/llvm-upstream/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:546:7
     #15 0x60c31ab in clang::ParseAST(clang::Sema&, bool, bool) 
/home/maxim/src/llvm-upstream/tools/clang/lib/Parse/ParseAST.cpp:159:13
     #16 0x4515a7e in clang::FrontendAction::Execute() 
/home/maxim/src/llvm-upstream/tools/clang/lib/Frontend/FrontendAction.cpp:856:8
     #17 0x44221e0 in 
clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) 
/home/maxim/src/llvm-upstream/tools/clang/lib/Frontend/CompilerInstance.cpp:970:11
     #18 0x46f8cb1 in 
clang::ExecuteCompilerInvocation(clang::CompilerInstance*) 
/home/maxim/src/llvm-upstream/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:249:25
     #19 0x97b098 in cc1_main(llvm::ArrayRef<char const*>, char const*, 
void*) 
/home/maxim/src/llvm-upstream/tools/clang/tools/driver/cc1_main.cpp:221:13
     #20 0x974865 in ExecuteCC1Tool 
/home/maxim/src/llvm-upstream/tools/clang/tools/driver/driver.cpp:299:12
     #21 0x974865 in main 
/home/maxim/src/llvm-upstream/tools/clang/tools/driver/driver.cpp:380
     #22 0x7fdda7b54f44 in __libc_start_main 
/build/eglibc-MjiXCM/eglibc-2.19/csu/libc-start.c:287

SUMMARY: AddressSanitizer: heap-use-after-free 
/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/bits/atomic_base.h:624:16 
in fetch_sub
Shadow bytes around the buggy address:
   0x0c047fff8180: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fa
   0x0c047fff8190: fa fa fd fa fa fa fd fd fa fa fd fd fa fa fd fa
   0x0c047fff81a0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
   0x0c047fff81b0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
   0x0c047fff81c0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fd
=>0x0c047fff81d0: fa fa fd fd fa fa fd[fd]fa fa fd fa fa fa fd fd
   0x0c047fff81e0: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fa
   0x0c047fff81f0: fa fa fd fd fa fa fd fa fa fa fd fa fa fa fd fd
   0x0c047fff8200: fa fa fd fa fa fa fd fd fa fa fd fa fa fa fd fa
   0x0c047fff8210: fa fa fd fd fa fa fd fa fa fa fd fa fa fa fd fa
   0x0c047fff8220: fa fa fd fd fa fa fd fa fa fa fd fd fa fa fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
   Addressable:           00
   Partially addressable: 01 02 03 04 05 06 07
   Heap left redzone:       fa
   Freed heap region:       fd
   Stack left redzone:      f1
   Stack mid redzone:       f2
   Stack right redzone:     f3
   Stack after return:      f5
   Stack use after scope:   f8
   Global redzone:          f9
   Global init order:       f6
   Poisoned by user:        f7
   Container overflow:      fc
   Array cookie:            ac
   Intra object redzone:    bb
   ASan internal:           fe
   Left alloca redzone:     ca
   Right alloca redzone:    cb
==30739==ABORTING

>
> Also it seems to have been refactored out a few weeks ago, so there's 
> no static matcher here anymore.
>
> 06/06/2017 12:45 PM, Maxim Ostapenko wrote:
>> On 06/06/17 12:41, Artem Dergachev via cfe-dev wrote:
>>> I think i've also noticed that static matcher objects don't work, 
>>> but didn't pay enough attention to figure out why.
>>>
>>> In clang-tidy, as far as i understand, they don't use static 
>>> matchers, but instead they have long-lived MatchFinder objects 
>>> filled with all the matchers they need, so they don't need to 
>>> construct the same matchers again and again. Maybe that'd be a 
>>> viable approach in your case?
>>
>> Hm, but tools/extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp 
>> actually has a static matcher:
>>
>> /// \brief Matcher that finds expressions that are candidates to be 
>> wrapped with
>> /// 'std::move'.
>> ///
>> /// Binds the id \c AutoPtrOwnershipTransferId to the expression.
>> static StatementMatcher MovableArgumentMatcher =
>>     expr(allOf(isLValue(), hasType(AutoPtrType)))
>>         .bind(AutoPtrOwnershipTransferId);
>>
>> Or perhaps I'm missing something?
>>
>> -Maxim
>>
>>>
>>> 06/06/2017 12:15 PM, Aleksandr wrote:
>>>> Hello,
>>>>
>>>> I need help. I see, that using static Matcher generate error on 
>>>> deallocated itself. For example, if we use:
>>>> static StatementMatcher MatcherA = callExpr();
>>>> MatcherA on dealloc tyrying to release reference counter of itself, 
>>>> but reference counter was deleted by method llvm_shutdown, so it 
>>>> use free memory.
>>>> Is it ok? We shouldn't use static matchers, or we have bug in 
>>>> implementation in reference counter. What is it case?
>>>
>>> _______________________________________________
>>> cfe-dev mailing list
>>> cfe-dev at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
>>
>




More information about the cfe-dev mailing list