]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2000-2004,2011-2012,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | ||
24 | ||
25 | // | |
26 | // alloc - abstract malloc-like allocator abstraction | |
27 | // | |
28 | #ifndef _H_ALLOC | |
29 | #define _H_ALLOC | |
30 | ||
31 | #include <security_utilities/utilities.h> | |
32 | #include <cstring> | |
33 | ||
34 | namespace Security | |
35 | { | |
36 | ||
37 | ||
38 | // | |
39 | // An abstract allocator superclass, based on the simple malloc/realloc/free paradigm | |
40 | // that CDSA loves so much. If you have an allocation strategy and want objects | |
41 | // to be allocated through it, inherit from this. | |
42 | // | |
43 | class Allocator { | |
44 | public: | |
45 | virtual ~Allocator(); | |
46 | virtual void *malloc(size_t) throw(std::bad_alloc) = 0; | |
47 | virtual void free(void *) throw() = 0; | |
48 | virtual void *realloc(void *, size_t) throw(std::bad_alloc) = 0; | |
49 | ||
50 | // | |
51 | // Template versions for added expressiveness. | |
52 | // Note that the integers are element counts, not byte sizes. | |
53 | // | |
54 | template <class T> T *alloc() throw(std::bad_alloc) | |
55 | { return reinterpret_cast<T *>(malloc(sizeof(T))); } | |
56 | ||
57 | template <class T> T *alloc(UInt32 count) throw(std::bad_alloc) | |
ecaf5866 A |
58 | { |
59 | size_t bytes = 0; | |
60 | if (__builtin_mul_overflow(sizeof(T), count, &bytes)) { | |
61 | throw std::bad_alloc(); | |
62 | } | |
63 | return reinterpret_cast<T *>(malloc(bytes)); | |
64 | ||
65 | } | |
b1ab9ed8 A |
66 | |
67 | template <class T> T *alloc(T *old, UInt32 count) throw(std::bad_alloc) | |
ecaf5866 A |
68 | { |
69 | size_t bytes = 0; | |
70 | if (__builtin_mul_overflow(sizeof(T), count, &bytes)) { | |
71 | throw std::bad_alloc(); | |
72 | } | |
73 | return reinterpret_cast<T *>(realloc(old, bytes)); | |
74 | } | |
b1ab9ed8 A |
75 | |
76 | ||
77 | // | |
78 | // Happier malloc/realloc for any type. Note that these still have | |
79 | // the original (byte-sized) argument profile. | |
80 | // | |
81 | template <class T> T *malloc(size_t size) throw(std::bad_alloc) | |
82 | { return reinterpret_cast<T *>(malloc(size)); } | |
83 | ||
84 | template <class T> T *realloc(void *addr, size_t size) throw(std::bad_alloc) | |
85 | { return reinterpret_cast<T *>(realloc(addr, size)); } | |
86 | ||
87 | // All right, if you *really* have to have calloc... | |
427c49bc | 88 | void *calloc(size_t size, size_t count) throw(std::bad_alloc) |
b1ab9ed8 | 89 | { |
fa7225c8 A |
90 | size_t bytes = 0; |
91 | if(__builtin_mul_overflow(size, count, &bytes)) { | |
92 | // Multiplication overflowed. | |
93 | throw std::bad_alloc(); | |
94 | } | |
95 | void *addr = malloc(bytes); | |
96 | memset(addr, 0, bytes); | |
b1ab9ed8 A |
97 | return addr; |
98 | } | |
99 | ||
100 | // compare Allocators for identity | |
101 | virtual bool operator == (const Allocator &alloc) const throw(); | |
102 | ||
103 | public: | |
104 | // allocator chooser options | |
105 | enum { | |
106 | normal = 0x0000, | |
107 | sensitive = 0x0001 | |
108 | }; | |
109 | ||
110 | static Allocator &standard(UInt32 request = normal); | |
111 | }; | |
112 | ||
113 | ||
114 | // | |
115 | // You'd think that this is operator delete(const T *, Allocator &), but you'd | |
116 | // be wrong. Specialized operator delete is only called during constructor cleanup. | |
117 | // Use this to cleanly destroy things. | |
118 | // | |
119 | template <class T> | |
120 | inline void destroy(T *obj, Allocator &alloc) throw() | |
121 | { | |
122 | obj->~T(); | |
123 | alloc.free(obj); | |
124 | } | |
125 | ||
126 | // untyped (release memory only, no destructor call) | |
127 | inline void destroy(void *obj, Allocator &alloc) throw() | |
128 | { | |
129 | alloc.free(obj); | |
130 | } | |
131 | ||
132 | ||
133 | // | |
134 | // A mixin class to automagically manage your allocator. | |
135 | // To allow allocation (of your object) from any instance of Allocator, | |
136 | // inherit from CssmHeap. Your users can then create heap instances of your thing by | |
137 | // new (an-allocator) YourClass(...) | |
138 | // or (still) | |
139 | // new YourClass(...) | |
140 | // for the default allocation source. The beauty is that when someone does a | |
141 | // delete pointer-to-your-instance | |
142 | // then the magic fairies will find the allocator that created the object and ask it | |
143 | // to free the memory (by calling its free() method). | |
144 | // The price of all that glory is memory overhead - typically one pointer per object. | |
145 | // | |
146 | class CssmHeap { | |
147 | public: | |
148 | void *operator new (size_t size, Allocator *alloc = NULL) throw(std::bad_alloc); | |
149 | void operator delete (void *addr, size_t size) throw(); | |
150 | void operator delete (void *addr, size_t size, Allocator *alloc) throw(); | |
151 | }; | |
152 | ||
153 | ||
154 | // | |
155 | // Here is a version of auto_ptr that works with Allocators. It is designed | |
156 | // to be pretty much a drop-in replacement. It requires an allocator as a constructor | |
157 | // argument, of course. | |
158 | // Note that CssmAutoPtr<void> is perfectly valid, unlike its auto_ptr look-alike. | |
159 | // You can't dereference it, naturally. | |
160 | // | |
161 | template <class T> | |
162 | class CssmAutoPtr { | |
163 | public: | |
164 | Allocator &allocator; | |
165 | ||
166 | CssmAutoPtr(Allocator &alloc = Allocator::standard()) | |
167 | : allocator(alloc), mine(NULL) { } | |
168 | CssmAutoPtr(Allocator &alloc, T *p) | |
169 | : allocator(alloc), mine(p) { } | |
170 | CssmAutoPtr(T *p) | |
171 | : allocator(Allocator::standard()), mine(p) { } | |
172 | template <class T1> CssmAutoPtr(CssmAutoPtr<T1> &src) | |
173 | : allocator(src.allocator), mine(src.release()) { } | |
174 | template <class T1> CssmAutoPtr(Allocator &alloc, CssmAutoPtr<T1> &src) | |
175 | : allocator(alloc), mine(src.release()) { assert(allocator == src.allocator); } | |
176 | ||
177 | ~CssmAutoPtr() { allocator.free(mine); } | |
178 | ||
179 | T *get() const throw() { return mine; } | |
180 | T *release() { T *result = mine; mine = NULL; return result; } | |
181 | void reset() { allocator.free(mine); mine = NULL; } | |
182 | ||
183 | operator T * () const { return mine; } | |
184 | T *operator -> () const { return mine; } | |
185 | T &operator * () const { assert(mine); return *mine; } | |
186 | ||
187 | private: | |
188 | T *mine; | |
189 | }; | |
190 | ||
191 | // specialization for void (i.e. void *), omitting the troublesome dereferencing ops. | |
192 | template <> | |
193 | class CssmAutoPtr<void> { | |
194 | public: | |
195 | Allocator &allocator; | |
196 | ||
197 | CssmAutoPtr(Allocator &alloc) : allocator(alloc), mine(NULL) { } | |
198 | CssmAutoPtr(Allocator &alloc, void *p) : allocator(alloc), mine(p) { } | |
199 | template <class T1> CssmAutoPtr(CssmAutoPtr<T1> &src) | |
200 | : allocator(src.allocator), mine(src.release()) { } | |
201 | template <class T1> CssmAutoPtr(Allocator &alloc, CssmAutoPtr<T1> &src) | |
202 | : allocator(alloc), mine(src.release()) { assert(allocator == src.allocator); } | |
203 | ||
204 | ~CssmAutoPtr() { destroy(mine, allocator); } | |
205 | ||
206 | void *get() throw() { return mine; } | |
207 | void *release() { void *result = mine; mine = NULL; return result; } | |
208 | void reset() { allocator.free(mine); mine = NULL; } | |
209 | ||
210 | private: | |
211 | void *mine; | |
212 | }; | |
213 | ||
214 | ||
215 | // | |
216 | // Convenience forms of CssmAutoPtr that automatically make their (initial) object. | |
217 | // | |
218 | template <class T> | |
219 | class CssmNewAutoPtr : public CssmAutoPtr<T> { | |
220 | public: | |
221 | CssmNewAutoPtr(Allocator &alloc = Allocator::standard()) | |
222 | : CssmAutoPtr<T>(alloc, new(alloc) T) { } | |
223 | ||
224 | template <class A1> | |
225 | CssmNewAutoPtr(Allocator &alloc, A1 &arg1) : CssmAutoPtr<T>(alloc, new(alloc) T(arg1)) { } | |
226 | template <class A1> | |
227 | CssmNewAutoPtr(Allocator &alloc, const A1 &arg1) | |
228 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1)) { } | |
229 | ||
230 | template <class A1, class A2> | |
231 | CssmNewAutoPtr(Allocator &alloc, A1 &arg1, A2 &arg2) | |
232 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { } | |
233 | template <class A1, class A2> | |
234 | CssmNewAutoPtr(Allocator &alloc, const A1 &arg1, A2 &arg2) | |
235 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { } | |
236 | template <class A1, class A2> | |
237 | CssmNewAutoPtr(Allocator &alloc, A1 &arg1, const A2 &arg2) | |
238 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { } | |
239 | template <class A1, class A2> | |
240 | CssmNewAutoPtr(Allocator &alloc, const A1 &arg1, const A2 &arg2) | |
241 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { } | |
242 | }; | |
243 | ||
244 | ||
245 | } // end namespace Security | |
246 | ||
247 | ||
248 | // | |
249 | // Global C++ allocation hooks to use Allocators (global namespace) | |
250 | // | |
251 | inline void *operator new (size_t size, Allocator &allocator) throw (std::bad_alloc) | |
252 | { return allocator.malloc(size); } | |
253 | ||
254 | inline void *operator new[] (size_t size, Allocator &allocator) throw (std::bad_alloc) | |
255 | { return allocator.malloc(size); } | |
256 | ||
257 | ||
258 | #endif //_H_ALLOC |