summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Checkers/DanglingInternalBufferChecker.cpp
blob: e7884ee104a35e451b86c6e2396563df92a65f5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//=== DanglingInternalBufferChecker.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++ 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.
//
//===----------------------------------------------------------------------===//

#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;

namespace {

class DanglingInternalBufferChecker : public Checker<check::PostCall> {
  CallDescription CStrFn;

public:
  DanglingInternalBufferChecker() : 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 DanglingInternalBufferChecker::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;

  auto *TypeDecl = TypedR->getValueType()->getAsCXXRecordDecl();
  if (TypeDecl->getName() != "basic_string")
    return;

  ProgramStateRef State = C.getState();

  if (Call.isCalled(CStrFn)) {
    SVal RawPtr = Call.getReturnValue();
    if (!RawPtr.isUnknown()) {
      State = State->set<RawPtrMap>(TypedR, RawPtr.getAsSymbol());
      C.addTransition(State);
    }
    return;
  }

  if (isa<CXXDestructorCall>(ICall)) {
    if (State->contains<RawPtrMap>(TypedR)) {
      const SymbolRef *StrBufferPtr = State->get<RawPtrMap>(TypedR);
      // FIXME: What if Origin is null?
      const Expr *Origin = Call.getOriginExpr();
      State = allocation_state::markReleased(State, *StrBufferPtr, Origin);
      C.addTransition(State);
      return;
    }
  }
}

void ento::registerDanglingInternalBufferChecker(CheckerManager &Mgr) {
  registerNewDeleteChecker(Mgr);
  Mgr.registerChecker<DanglingInternalBufferChecker>();
}
OpenPOWER on IntegriCloud