[cfe-dev] RetainCountChecker | Assertion Failure | check-clang-analysis

Artem Dergachev via cfe-dev cfe-dev at lists.llvm.org
Sun Jul 2 00:10:27 PDT 2017


Uhm, why does this thing return `const Decl &` rather than `const Decl 
*`? Anyway, whatever, never mind.


You're crashing in...

   cast<FunctionDecl>(&EN->getCodeDecl())

...because this Decl returned by `EN->getCodeDecl()` isn't a FunctionDecl.


You can easily see this from the backtrace:

Assertion failed: (isa<X>(Val) && "cast<Ty>() argument of incompatible 
type!"), function cast, file 
(...censored...)/llvm/include/llvm/Support/Casting.h, line 254.
0  libLLVMSupport.dylib                 0x00000001148fb8fc 
llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 60
1  libLLVMSupport.dylib                 0x00000001148fbec9 
PrintStackTraceSignalHandler(void*) + 25
2  libLLVMSupport.dylib                 0x00000001148f7b59 
llvm::sys::RunSignalHandlers() + 425
3  libLLVMSupport.dylib                 0x00000001148fc212 
SignalHandler(int) + 354
4  libsystem_platform.dylib             0x00007fffd872cb3a _sigtramp + 26
5  libclangStaticAnalyzerCore.dylib     0x0000000122060c7b 
llvm::alignAddr(void const*, unsigned long) + 43
6  libsystem_c.dylib                    0x00007fffd85b1420 abort + 129
7  libsystem_c.dylib                    0x00007fffd8578893 basename_r + 0
8  libclangStaticAnalyzerCheckers.dylib 0x00000001202e6fe7 
llvm::cast_retty<clang::FunctionDecl, clang::Decl const*>::ret_type 
llvm::cast<clang::FunctionDecl, clang::Decl const>(clang::Decl const*) + 103
9  libclangStaticAnalyzerCheckers.dylib 0x00000001208b7aa6 
isAnnotatedToSkipDiagnostics(clang::ento::ExplodedNode const*) + 38
(...more stuff...)

You're calling llvm::cast<> (frame 8) from your new function (frame 9), 
the only cast you have is `cast<FunctionDecl>(&EN->getCodeDecl())`, and 
the assertion message says that the argument is of incompatible type.


If you want to know what specific decl causes a problem, you can print 
it in the debugger:

$ lldb -- (...censored...)/debug/./bin/clang -cc1 -internal-isystem 
(...censored...)/debug/lib/clang/5.0.0/include -nostdsysteminc -analyze 
-analyzer-constraints=range 
-analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.Dealloc,debug.ExprInspection 
-analyzer-store=region -verify -Wno-objc-root-class 
(...censored...)/llvm/tools/clang/test/Analysis/properties.m

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
     frame #0: 0x00007fffd864bd42 libsystem_kernel.dylib`__pthread_kill + 10
     frame #1: 0x00007fffd8739787 libsystem_pthread.dylib`pthread_kill + 90
     frame #2: 0x00007fffd85b1420 libsystem_c.dylib`abort + 129
     frame #3: 0x00007fffd8578893 libsystem_c.dylib`__assert_rtn + 320
     frame #4: 0x0000000114983fe7 
libclangStaticAnalyzerCheckers.dylib`llvm::cast_retty<clang::FunctionDecl, 
clang::Decl const*>::ret_type llvm::cast<clang::FunctionDecl, 
clang::Decl const>(Val=0x00000001170ab5c0) at Casting.h:254
   * frame #5: 0x0000000114f54aa6 
libclangStaticAnalyzerCheckers.dylib`isAnnotatedToSkipDiagnostics(EN=0x0000000118815ee0) 
at RetainCountChecker.cpp:1904
(...more stuff...)

(lldb) f 5
frame #5: 0x0000000114f54aa6 
libclangStaticAnalyzerCheckers.dylib`isAnnotatedToSkipDiagnostics(EN=0x0000000118815ee0) 
at RetainCountChecker.cpp:1904
    1901
    1902    bool
    1903    isAnnotatedToSkipDiagnostics(const ExplodedNode *EN) {
-> 1904      const FunctionDecl *FD = 
cast<FunctionDecl>(&EN->getCodeDecl());
    1905      const IdentifierInfo *II = FD->getIdentifier();
    1906
    1907      if (II) {

(lldb) p EN->getCodeDecl().dump()
ObjCMethodDecl 0x1170ab5c0 
<(...censored...)/llvm/tools/clang/test/Analysis/properties.m:559:1, 
line:563:1> line:559:1 - testRetainAndRelease 'void'
(...more stuff...)

Note that frames are shifted in the debugger because it stops on the 
moment when the assertion has failed, so we're on frame 5 instead of 
frame 9 now.

If you use gdb instead of lldb, just replace "lldb --" with "gdb --args" 
in the first command, the rest is the same. If you use an IDE, then you 
should know better how to debug this.


So in this case it's ObjCMethodDecl, and Objective-C methods apparently 
aren't functions. I'd also worry about BlockDecl which may also appear here.

You should use dyn_cast<> when you're not sure if the cast succeeds - 
it'd return nullptr instead of crashing, and you can handle it.


On 7/1/17 10:12 AM, Malhar Thakkar via cfe-dev wrote:
> Dear all,
>
> I am currently trying to suppress diagnostics emitted if the function 
> under consideration has a certain annotate attribute 
> ("check_attribute_annotate" in this case).
>
> Hence, for that, I added the following piece of code to 
> RetainCountChecker.cpp but it is resulting in some assertion failures 
> while performing make -j4 check-clang-analysis.
>
>
>
> diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp 
> b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
> index 89b1291..9f367be 100644
> --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
> +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
> @@ -1894,6 +1894,20 @@ static bool isSynthesizedAccessor(const 
> StackFrameContext *SFC) {
> return SFC->getAnalysisDeclContext()->isBodyAutosynthesized();
>  }
> +bool
> +isAnnotatedToSkipDiagnostics(const ExplodedNode *EN) {
> + const FunctionDecl *FD = cast<FunctionDecl>(&EN->getCodeDecl());
> + const IdentifierInfo *II = FD->getIdentifier();
> +
> + if (II) {
> + for (const auto *Ann : FD->specific_attrs<AnnotateAttr>()){
> + if (Ann->getAnnotation() == "check_attribute_annotate")
> + return true;
> +    }
> +  }
> + return false;
> +}
> +
>  std::shared_ptr<PathDiagnosticPiece>
>  CFRefReportVisitor::VisitNode(const ExplodedNode *N, const 
> ExplodedNode *PrevN,
>            BugReporterContext &BRC, BugReport &BR) {
> @@ -3345,11 +3359,13 @@ void 
> RetainCountChecker::processNonLeakError(ProgramStateRef St,
>    }
>    assert(BT);
> -  auto report = std::unique_ptr<BugReport>(
> - new CFRefReport(*BT, C.getASTContext().getLangOpts(), 
> C.isObjCGCEnabled(),
> -    SummaryLog, N, Sym));
> -  report->addRange(ErrorRange);
> -  C.emitReport(std::move(report));
> + if (!isAnnotatedToSkipDiagnostics(N)){
> +  auto report = std::unique_ptr<BugReport>(
> + new CFRefReport(*BT, C.getASTContext().getLangOpts(), 
> C.isObjCGCEnabled(),
> +                      SummaryLog, N, Sym));
> +  report->addRange(ErrorRange);
> +  C.emitReport(std::move(report));
> +  }
>  }
> //===----------------------------------------------------------------------===//
>
> More specifically, the code highlighted in red above is causing the 
> two assertion failures mentioned below.
>
> The following test-cases are the unexpected failures:
>
>   * Analysis/inlining/RetainCountExamples.m
>   * Analysis/properties.m
>
> *Note:* The above diff is a subset of the code that I have changed. I 
> added the check *if (!isAnnotatedToSkipDiagnostics(N))* before every 
> invocation to *emitReport* to suppress raising warnings for functions 
> having the annotate attribute *check_attribute_annotate*. It seemed to 
> work for manually made test-cases but clearly there is something wrong 
> with my methodology.
>
>
> Could anyone please tell me the reason behind these assertion failures?
>
>
> Thank you.
>
>
> Regards,
> Malhar Thakkar
>>
>
> _______________________________________________
> 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