OSDN Git Service

[analyzer][StackAddressEscape] Tie warnings to the diagnostic checkers rather then...
authorKirstóf Umann <dkszelethus@gmail.com>
Fri, 10 Apr 2020 22:21:48 +0000 (00:21 +0200)
committerKirstóf Umann <dkszelethus@gmail.com>
Wed, 20 May 2020 00:26:40 +0000 (02:26 +0200)
Differential Revision: https://reviews.llvm.org/D78101

clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
clang/test/Analysis/incorrect-checker-names.cpp
clang/test/Analysis/incorrect-checker-names.mm

index 237053d..49ab25e 100644 (file)
@@ -78,13 +78,16 @@ public:
              const char *description)
       : BugType(checker, name, categories::LogicError), desc(description) {}
 
+  BuiltinBug(class CheckerNameRef checker, const char *name)
+      : BugType(checker, name, categories::LogicError), desc(name) {}
+
   BuiltinBug(const CheckerBase *checker, const char *name)
       : BugType(checker, name, categories::LogicError), desc(name) {}
 
   StringRef getDescription() const { return desc; }
 };
 
-} // end ento namespace
+} // namespace ento
 
 } // end clang namespace
 #endif
index 21fc65a..b5c9356 100644 (file)
@@ -43,6 +43,7 @@ public:
   };
 
   DefaultBool ChecksEnabled[CK_NumCheckKinds];
+  CheckerNameRef CheckNames[CK_NumCheckKinds];
 
   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
   void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
@@ -156,7 +157,8 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C,
     return;
   if (!BT_returnstack)
     BT_returnstack = std::make_unique<BuiltinBug>(
-        this, "Return of address to stack-allocated memory");
+        CheckNames[CK_StackAddrEscapeChecker],
+        "Return of address to stack-allocated memory");
   // Generate a report for this bug.
   SmallString<128> buf;
   llvm::raw_svector_ostream os(buf);
@@ -195,7 +197,8 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
       continue;
     if (!BT_capturedstackasync)
       BT_capturedstackasync = std::make_unique<BuiltinBug>(
-          this, "Address of stack-allocated memory is captured");
+          CheckNames[CK_StackAddrAsyncEscapeChecker],
+          "Address of stack-allocated memory is captured");
     SmallString<128> Buf;
     llvm::raw_svector_ostream Out(Buf);
     SourceRange Range = genName(Out, Region, C.getASTContext());
@@ -218,7 +221,8 @@ void StackAddrEscapeChecker::checkReturnedBlockCaptures(
       continue;
     if (!BT_capturedstackret)
       BT_capturedstackret = std::make_unique<BuiltinBug>(
-          this, "Address of stack-allocated memory is captured");
+          CheckNames[CK_StackAddrEscapeChecker],
+          "Address of stack-allocated memory is captured");
     SmallString<128> Buf;
     llvm::raw_svector_ostream Out(Buf);
     SourceRange Range = genName(Out, Region, C.getASTContext());
@@ -277,7 +281,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
 
   // The CK_CopyAndAutoreleaseBlockObject cast causes the block to be copied
   // so the stack address is not escaping here.
-  if (auto *ICE = dyn_cast<ImplicitCastExpr>(RetE)) {
+  if (const auto *ICE = dyn_cast<ImplicitCastExpr>(RetE)) {
     if (isa<BlockDataRegion>(R) &&
         ICE->getCastKind() == CK_CopyAndAutoreleaseBlockObject) {
       return;
@@ -333,7 +337,8 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
 
   if (!BT_stackleak)
     BT_stackleak = std::make_unique<BuiltinBug>(
-        this, "Stack address stored into global variable",
+        CheckNames[CK_StackAddrEscapeChecker],
+        "Stack address stored into global variable",
         "Stack address was saved into a global variable. "
         "This is dangerous because the address will become "
         "invalid after returning from the function");
@@ -371,14 +376,13 @@ bool ento::shouldRegisterStackAddrEscapeBase(const CheckerManager &mgr) {
 
 #define REGISTER_CHECKER(name)                                                 \
   void ento::register##name(CheckerManager &Mgr) {                             \
-    StackAddrEscapeChecker *Chk =                                              \
-        Mgr.getChecker<StackAddrEscapeChecker>();                              \
+    StackAddrEscapeChecker *Chk = Mgr.getChecker<StackAddrEscapeChecker>();    \
     Chk->ChecksEnabled[StackAddrEscapeChecker::CK_##name] = true;              \
+    Chk->CheckNames[StackAddrEscapeChecker::CK_##name] =                       \
+        Mgr.getCurrentCheckerName();                                           \
   }                                                                            \
                                                                                \
-  bool ento::shouldRegister##name(const CheckerManager &mgr) {                     \
-    return true;                                                               \
-  }
+  bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
 
 REGISTER_CHECKER(StackAddrEscapeChecker)
 REGISTER_CHECKER(StackAddrAsyncEscapeChecker)
index 3519e15..9854a50 100644 (file)
@@ -5,9 +5,16 @@
 int* stack_addr_escape_base() {
   int x = 0;
   // FIXME: This shouldn't be tied to a modeling checker.
-  return &x; // expected-warning{{Address of stack memory associated with local variable 'x' returned to caller [core.StackAddrEscapeBase]}}
+  return &x; // expected-warning{{Address of stack memory associated with local variable 'x' returned to caller [core.StackAddressEscape]}}
   // expected-note-re@-1{{{{^Address of stack memory associated with local variable 'x' returned to caller$}}}}
   // Just a regular compiler warning.
   // expected-warning@-3{{address of stack memory associated with local variable 'x' returned}}
 }
 
+char const *p;
+
+void f0() {
+  char const str[] = "This will change";
+  p = str;
+} // expected-warning{{Address of stack memory associated with local variable 'str' is still referred to by the global variable 'p' upon returning to the caller.  This will be a dangling reference [core.StackAddressEscape]}}
+// expected-note@-1{{Address of stack memory associated with local variable 'str' is still referred to by the global variable 'p' upon returning to the caller.  This will be a dangling reference}}
index 11b6a21..861f81e 100644 (file)
@@ -1,5 +1,6 @@
-// RUN: %clang_analyze_cc1 -fblocks -verify %s -Wno-objc-root-class \
+// RUN: %clang_analyze_cc1 -fblocks -fobjc-arc -verify %s -Wno-objc-root-class \
 // RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-checker=alpha.core.StackAddressAsyncEscape \
 // RUN:   -analyzer-checker=nullability \
 // RUN:   -analyzer-checker=osx
 
@@ -126,3 +127,32 @@ void use_out_param_leak() {
   // FIXME: This shouldn't be tied to a modeling checker.
   write_into_out_param_on_success(&obj); // expected-warning{{Potential leak of an object stored into 'obj' [osx.cocoa.RetainCountBase]}}
 }
+
+typedef struct dispatch_queue_s *dispatch_queue_t;
+typedef void (^dispatch_block_t)(void);
+void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
+typedef long dispatch_once_t;
+void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
+typedef long dispatch_time_t;
+void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
+void dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block);
+
+extern dispatch_queue_t queue;
+extern dispatch_once_t *predicate;
+extern dispatch_time_t when;
+
+dispatch_block_t get_leaking_block() {
+  int leaked_x = 791;
+  int *p = &leaked_x;
+  return ^void(void) {
+    *p = 1;
+  };
+  // expected-warning@-3 {{Address of stack memory associated with local variable 'leaked_x' \
+is captured by a returned block [core.StackAddressEscape]}}
+}
+
+void test_returned_from_func_block_async() {
+  dispatch_async(queue, get_leaking_block());
+  // expected-warning@-1 {{Address of stack memory associated with local variable 'leaked_x' \
+is captured by an asynchronously-executed block [alpha.core.StackAddressAsyncEscape]}}
+}