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>();
}
|