r336495 - [analyzer] Highlight c_str() call in DanglingInternalBufferChecker.
Reka Kovacs via cfe-commits
cfe-commits at lists.llvm.org
Sat Jul 7 12:27:18 PDT 2018
Author: rkovacs
Date: Sat Jul 7 12:27:18 2018
New Revision: 336495
URL: http://llvm.org/viewvc/llvm-project?rev=336495&view=rev
Log:
[analyzer] Highlight c_str() call in DanglingInternalBufferChecker.
Add a bug visitor to DanglingInternalBufferChecker that places a note
at the point where the dangling pointer was obtained. The visitor is
handed over to MallocChecker and attached to the report there.
Differential Revision: https://reviews.llvm.org/D48522
Modified:
cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h
cfe/trunk/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
cfe/trunk/test/Analysis/dangling-internal-buffer.cpp
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h?rev=336495&r1=336494&r2=336495&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/AllocationState.h Sat Jul 7 12:27:18 2018
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_ALLOCATIONSTATE_H
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_ALLOCATIONSTATE_H
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
namespace clang {
@@ -20,6 +21,11 @@ namespace allocation_state {
ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym,
const Expr *Origin);
+/// This function provides an additional visitor that augments the bug report
+/// with information relevant to memory errors caused by the misuse of
+/// AF_InternalBuffer symbols.
+std::unique_ptr<BugReporterVisitor> getDanglingBufferBRVisitor(SymbolRef Sym);
+
} // end namespace allocation_state
} // end namespace ento
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp?rev=336495&r1=336494&r2=336495&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp Sat Jul 7 12:27:18 2018
@@ -7,30 +7,66 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines a check that marks a raw pointer to a C++ standard library
-// container's inner buffer released when the object is destroyed. This
-// information can be used by MallocChecker to detect use-after-free problems.
+// This file defines a check that marks a raw pointer to a C++ container's
+// inner buffer released when the object is destroyed. This information can
+// be used by MallocChecker to detect use-after-free problems.
//
//===----------------------------------------------------------------------===//
+#include "AllocationState.h"
#include "ClangSACheckers.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "AllocationState.h"
using namespace clang;
using namespace ento;
+// FIXME: c_str() may be called on a string object many times, so it should
+// have a list of symbols associated with it.
+REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, SymbolRef)
+
namespace {
-class DanglingInternalBufferChecker : public Checker<check::DeadSymbols,
- check::PostCall> {
+class DanglingInternalBufferChecker
+ : public Checker<check::DeadSymbols, check::PostCall> {
CallDescription CStrFn;
public:
+ class DanglingBufferBRVisitor : public BugReporterVisitor {
+ SymbolRef PtrToBuf;
+
+ public:
+ DanglingBufferBRVisitor(SymbolRef Sym) : PtrToBuf(Sym) {}
+
+ static void *getTag() {
+ static int Tag = 0;
+ return &Tag;
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override {
+ ID.AddPointer(getTag());
+ }
+
+ std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
+ const ExplodedNode *PrevN,
+ BugReporterContext &BRC,
+ BugReport &BR) override;
+
+ // FIXME: Scan the map once in the visitor's constructor and do a direct
+ // lookup by region.
+ bool isSymbolTracked(ProgramStateRef State, SymbolRef Sym) {
+ RawPtrMapTy Map = State->get<RawPtrMap>();
+ for (const auto Entry : Map) {
+ if (Entry.second == Sym)
+ return true;
+ }
+ return false;
+ }
+ };
+
DanglingInternalBufferChecker() : CStrFn("c_str") {}
/// Record the connection between the symbol returned by c_str() and the
@@ -44,10 +80,6 @@ public:
} // end anonymous namespace
-// FIXME: c_str() may be called on a string object many times, so it should
-// have a list of symbols associated with it.
-REGISTER_MAP_WITH_PROGRAMSTATE(RawPtrMap, const MemRegion *, SymbolRef)
-
void DanglingInternalBufferChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
const auto *ICall = dyn_cast<CXXInstanceCall>(&Call);
@@ -103,6 +135,41 @@ void DanglingInternalBufferChecker::chec
C.addTransition(State);
}
+std::shared_ptr<PathDiagnosticPiece>
+DanglingInternalBufferChecker::DanglingBufferBRVisitor::VisitNode(
+ const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC,
+ BugReport &BR) {
+
+ if (!isSymbolTracked(N->getState(), PtrToBuf) ||
+ isSymbolTracked(PrevN->getState(), PtrToBuf))
+ return nullptr;
+
+ const Stmt *S = PathDiagnosticLocation::getStmt(N);
+ if (!S)
+ return nullptr;
+
+ SmallString<256> Buf;
+ llvm::raw_svector_ostream OS(Buf);
+ OS << "Pointer to dangling buffer was obtained here";
+ PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
+ N->getLocationContext());
+ return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true,
+ nullptr);
+}
+
+namespace clang {
+namespace ento {
+namespace allocation_state {
+
+std::unique_ptr<BugReporterVisitor> getDanglingBufferBRVisitor(SymbolRef Sym) {
+ return llvm::make_unique<
+ DanglingInternalBufferChecker::DanglingBufferBRVisitor>(Sym);
+}
+
+} // end namespace allocation_state
+} // end namespace ento
+} // end namespace clang
+
void ento::registerDanglingInternalBufferChecker(CheckerManager &Mgr) {
registerNewDeleteChecker(Mgr);
Mgr.registerChecker<DanglingInternalBufferChecker>();
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=336495&r1=336494&r2=336495&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Sat Jul 7 12:27:18 2018
@@ -1993,6 +1993,11 @@ void MallocChecker::ReportUseAfterFree(C
R->markInteresting(Sym);
R->addRange(Range);
R->addVisitor(llvm::make_unique<MallocBugVisitor>(Sym));
+
+ const RefState *RS = C.getState()->get<RegionState>(Sym);
+ if (RS->getAllocationFamily() == AF_InternalBuffer)
+ R->addVisitor(allocation_state::getDanglingBufferBRVisitor(Sym));
+
C.emitReport(std::move(R));
}
}
Modified: cfe/trunk/test/Analysis/dangling-internal-buffer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/dangling-internal-buffer.cpp?rev=336495&r1=336494&r2=336495&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/dangling-internal-buffer.cpp (original)
+++ cfe/trunk/test/Analysis/dangling-internal-buffer.cpp Sat Jul 7 12:27:18 2018
@@ -6,7 +6,7 @@ template< typename CharT >
class basic_string {
public:
~basic_string();
- const CharT *c_str();
+ const CharT *c_str() const;
};
typedef basic_string<char> string;
@@ -25,17 +25,29 @@ void deref_after_scope_char() {
const char *c;
{
std::string s;
- c = s.c_str();
+ c = s.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}}
} // expected-note {{Internal buffer is released because the object was destroyed}}
consume(c); // expected-warning {{Use of memory after it is freed}}
// expected-note at -1 {{Use of memory after it is freed}}
}
+void deref_after_scope_char2() {
+ const char *c;
+ {
+ std::string s;
+ c = s.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}}
+ } // expected-note {{Internal buffer is released because the object was destroyed}}
+ std::string s;
+ const char *c2 = s.c_str();
+ consume(c); // expected-warning {{Use of memory after it is freed}}
+ // expected-note at -1 {{Use of memory after it is freed}}
+}
+
void deref_after_scope_wchar_t() {
const wchar_t *w;
{
std::wstring ws;
- w = ws.c_str();
+ w = ws.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}}
} // expected-note {{Internal buffer is released because the object was destroyed}}
consume(w); // expected-warning {{Use of memory after it is freed}}
// expected-note at -1 {{Use of memory after it is freed}}
@@ -45,7 +57,7 @@ void deref_after_scope_char16_t() {
const char16_t *c16;
{
std::u16string s16;
- c16 = s16.c_str();
+ c16 = s16.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}}
} // expected-note {{Internal buffer is released because the object was destroyed}}
consume(c16); // expected-warning {{Use of memory after it is freed}}
// expected-note at -1 {{Use of memory after it is freed}}
@@ -55,7 +67,7 @@ void deref_after_scope_char32_t() {
const char32_t *c32;
{
std::u32string s32;
- c32 = s32.c_str();
+ c32 = s32.c_str(); // expected-note {{Pointer to dangling buffer was obtained here}}
} // expected-note {{Internal buffer is released because the object was destroyed}}
consume(c32); // expected-warning {{Use of memory after it is freed}}
// expected-note at -1 {{Use of memory after it is freed}}
More information about the cfe-commits
mailing list