rnkovacs created this revision.
rnkovacs added reviewers: NoQ, xazax.hun, george.karpenkov.
Herald added subscribers: a.sidorin, dkrupp, szepet, baloghadamsoftware, 
whisperity, mgorny.

This check marks a raw pointer to a C++ string object's inner buffer "released"
when the object itself is destroyed. This information can be used by 
MallocChecker
to warn for use-after-free problems.

Test cases using mocks are to be added. Until then, the following file is
used for testing purposes: <<tests.cpp>>.


Repository:
  rC Clang

https://reviews.llvm.org/D47135

Files:
  include/clang/StaticAnalyzer/Checkers/Checkers.td
  lib/StaticAnalyzer/Checkers/CMakeLists.txt
  lib/StaticAnalyzer/Checkers/DanglingStringPointerChecker.cpp
  lib/StaticAnalyzer/Checkers/MallocChecker.cpp
  lib/StaticAnalyzer/Checkers/RegionState.h

Index: lib/StaticAnalyzer/Checkers/RegionState.h
===================================================================
--- /dev/null
+++ lib/StaticAnalyzer/Checkers/RegionState.h
@@ -0,0 +1,28 @@
+//===--- RegionState.h ----------------------------------------- *- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_REGIONSTATE_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_REGIONSTATE_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+
+namespace clang {
+namespace ento {
+
+namespace region_state {
+
+ProgramStateRef markReleased(ProgramStateRef State, SymbolRef Sym,
+                             const Expr *Origin);
+
+} // end namespace region_state
+
+} // end namespace ento
+} // end namespace clang
+
+#endif
Index: lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -30,6 +30,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
+#include "RegionState.h"
 #include <climits>
 #include <utility>
 
@@ -2991,6 +2992,21 @@
   }
 }
 
+namespace clang {
+namespace ento {
+namespace region_state {
+
+ProgramStateRef
+markReleased(ProgramStateRef State, SymbolRef Sym, const Expr *Origin) {
+  // FIXME: This might not be the best allocation family for this purpose.
+  AllocationFamily Family = AF_CXXNew;
+  return State->set<RegionState>(Sym, RefState::getReleased(Family, Origin));
+}
+
+} // end namespace region_state
+} // end namespace ento
+} // end namespace clang
+
 void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) {
   registerCStringCheckerBasic(mgr);
   MallocChecker *checker = mgr.registerChecker<MallocChecker>();
Index: lib/StaticAnalyzer/Checkers/DanglingStringPointerChecker.cpp
===================================================================
--- /dev/null
+++ lib/StaticAnalyzer/Checkers/DanglingStringPointerChecker.cpp
@@ -0,0 +1,85 @@
+//=== DanglingStringPointerChecker.cpp ----------------------------*- C++ -*--//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a check that marks a raw pointer to a C++ string object's
+// inner buffer released when the object is destroyed. This information can
+// then be used by MallocChecker to detect further use-after-free problems.
+//
+//===----------------------------------------------------------------------===//
+
+#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 "RegionState.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class DanglingStringPointerChecker : public Checker<check::PostCall> {
+  CallDescription CStrFn;
+
+public:
+  DanglingStringPointerChecker() : CStrFn("c_str") {}
+
+  /// Record the connection between the symbol returned by c_str() and the
+  /// corresponding string object region in the ProgramState. Mark the symbol
+  /// released if the string object is destroyed.
+  void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+};
+
+} // 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 DanglingStringPointerChecker::checkPostCall(const CallEvent &Call,
+                                                 CheckerContext &C) const {
+  const auto *ICall = dyn_cast<CXXInstanceCall>(&Call);
+  if (!ICall)
+    return;
+
+  SVal Obj = ICall->getCXXThisVal();
+  const auto *TypedR = dyn_cast_or_null<TypedValueRegion>(Obj.getAsRegion());
+  if (!TypedR)
+    return;
+
+  QualType RegType = TypedR->getValueType();
+  if (RegType.getAsString() != "std::string")
+    return;
+
+  ProgramStateRef State = C.getState();
+
+  if (Call.isCalled(CStrFn)) {
+    SymbolRef RawPtr = Call.getReturnValue().getAsSymbol();
+    State = State->set<RawPtrMap>(TypedR, RawPtr);
+    C.addTransition(State);
+    return;
+  }
+
+  if (dyn_cast<CXXDestructorCall>(ICall)) {
+    if (State->contains<RawPtrMap>(TypedR)) {
+      const SymbolRef *StrBufferPtr = State->get<RawPtrMap>(TypedR);
+      const Expr *Origin = Call.getOriginExpr();
+      State = region_state::markReleased(State, *StrBufferPtr, Origin);
+      C.addTransition(State);
+      return;
+    }
+  }
+}
+
+// TODO: This check depends on MallocChecker.
+void ento::registerDanglingStringPointerChecker(CheckerManager &Mgr) {
+  Mgr.registerChecker<DanglingStringPointerChecker>();
+}
Index: lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -27,6 +27,7 @@
   CloneChecker.cpp
   ConversionChecker.cpp
   CXXSelfAssignmentChecker.cpp
+  DanglingStringPointerChecker.cpp
   DeadStoresChecker.cpp
   DebugCheckers.cpp
   DeleteWithNonVirtualDtorChecker.cpp
Index: include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -300,6 +300,10 @@
 
 let ParentPackage = CplusplusAlpha in {
 
+def DanglingStringPointerChecker : Checker<"DanglingStringPointer">,
+  HelpText<"Checks for dangling inner raw pointers of C++ string objects">,
+  DescFile<"DanglingStringPointerChecker.cpp">;
+
 def DeleteWithNonVirtualDtorChecker : Checker<"DeleteWithNonVirtualDtor">,
   HelpText<"Reports destructions of polymorphic objects with a non-virtual "
            "destructor in their base class">,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to