1 : // Copyright 2014 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 : //
15 : // Declares a quarantine, which is used to temporarily house allocations after
16 : // they've been freed, permitting use-after-frees to be detected.
17 :
18 : #ifndef SYZYGY_AGENT_ASAN_QUARANTINE_H_
19 : #define SYZYGY_AGENT_ASAN_QUARANTINE_H_
20 :
21 : #include <vector>
22 :
23 : #include "base/logging.h"
24 :
25 : namespace agent {
26 : namespace asan {
27 :
28 : // The interface that quarantines must satisfy. They store literal copies of
29 : // objects of type |ObjectType|.
30 : //
31 : // Placing objects in the quarantine and removing them from it are factored
32 : // out as two separate steps. Thus it is possible for a quarantine invariant
33 : // to be invalidated by a call to 'Push', which won't be restored until
34 : // sufficient calls to 'Pop' have been made.
35 : //
36 : // This has been templated on the object type to allow easier unittesting.
37 : //
38 : // @tparam ObjectType The type of object stored by the quarantine.
39 : template<typename ObjectType>
40 : class QuarantineInterface {
41 : public:
42 : typedef ObjectType Object;
43 : typedef std::vector<Object> ObjectVector;
44 :
45 : // Constructor.
46 E : QuarantineInterface() { }
47 :
48 : // Virtual destructor.
49 E : virtual ~QuarantineInterface() { }
50 :
51 : // Places an allocation in the quarantine. This routine must be called under
52 : // Lock.
53 : // @param The object to place in the quarantine.
54 : // @returns true if the has been accepted by and placed in the quarantine,
55 : // and false if its entry has been refused.
56 : virtual bool Push(const Object& object) = 0;
57 :
58 : // Potentially removes an object from the quarantine to maintain the
59 : // invariant. This routine must be thread-safe, and implement its own locking.
60 : // @param object Is filled in with a copy of the removed object.
61 : // @returns true if an object was removed, false otherwise. If this returns
62 : // false then the cache invariant is satisfied.
63 : virtual bool Pop(Object* object) = 0;
64 :
65 : // Removes all objects from the quarantine, placing them in the provided
66 : // vector. This routine must be thread-safe, and implement its own locking.
67 : virtual void Empty(ObjectVector* objects) = 0;
68 :
69 : // The number of objects currently in the quarantine.
70 : // @returns the number of objects in the quarantine.
71 : virtual size_t GetCount() = 0;
72 :
73 : // An automatic quarantine lock.
74 : //
75 : // This class is nested into the QuarantineInterface class to avoid a
76 : // complicated template definition. It also avoids exposing the Lock/Unlock
77 : // functions.
78 : class AutoQuarantineLock {
79 : public:
80 : // Constructor. Automatically lock the quarantine.
81 E : AutoQuarantineLock(QuarantineInterface* quarantine,
82 : const ObjectType& object)
83 : : quarantine_(quarantine) {
84 E : DCHECK_NE(reinterpret_cast<QuarantineInterface*>(NULL), quarantine_);
85 E : lock_index_ = quarantine_->GetLockId(object);
86 E : quarantine_->Lock(lock_index_);
87 E : }
88 :
89 : // Destructor. Automatically unlock the quarantine.
90 E : ~AutoQuarantineLock() {
91 E : quarantine_->Unlock(lock_index_);
92 E : }
93 :
94 : private:
95 : // The bucket to lock in the quarantine.
96 : size_t lock_index_;
97 :
98 : // The quarantine to lock.
99 : QuarantineInterface* quarantine_;
100 :
101 : DISALLOW_COPY_AND_ASSIGN(AutoQuarantineLock);
102 : };
103 :
104 : private:
105 : // Get the lock ID associated with a given object in the quarantine. This is
106 : // useful in the case where there's several buckets in the quarantine.
107 : // @param object The object for which we want to retrieve the lock ID
108 : // associated with it.
109 : // @returns the lock ID associated with this object.
110 : virtual size_t GetLockId(const Object& object) = 0;
111 :
112 : // Lock the quarantine.
113 : // @param id The bucket to lock, ignored if the quarantine isn't sharded.
114 : virtual void Lock(size_t id) = 0;
115 :
116 : // Unlock the quarantine.
117 : // @param id The bucket to lock, ignored if the quarantine isn't sharded.
118 : virtual void Unlock(size_t id) = 0;
119 :
120 : DISALLOW_COPY_AND_ASSIGN(QuarantineInterface);
121 : };
122 :
123 : // Quarantines in Asan are typically storing blocks. Here they are represented
124 : // by a CompactBlockInfo, which contains information that the quarantine
125 : // frequently accesses.
126 : struct CompactBlockInfo; // Forward declaration.
127 : typedef QuarantineInterface<CompactBlockInfo> BlockQuarantineInterface;
128 :
129 : } // namespace asan
130 : } // namespace agent
131 :
132 : #endif // SYZYGY_AGENT_ASAN_QUARANTINE_H_
|