]>
Commit | Line | Data |
---|---|---|
bac41a7b A |
1 | /* |
2 | * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. | |
3 | * | |
4 | * The contents of this file constitute Original Code as defined in and are | |
5 | * subject to the Apple Public Source License Version 1.2 (the 'License'). | |
6 | * You may not use this file except in compliance with the License. Please obtain | |
7 | * a copy of the License at http://www.apple.com/publicsource and read it before | |
8 | * using this file. | |
9 | * | |
10 | * This Original Code and all software distributed under the License are | |
11 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS | |
12 | * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT | |
13 | * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | |
14 | * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the | |
15 | * specific language governing rights and limitations under the License. | |
16 | */ | |
17 | ||
18 | ||
19 | // | |
20 | // cssmalloc - memory allocation in the CDSA world | |
21 | // | |
22 | #ifndef _H_CSSMALLOC | |
23 | #define _H_CSSMALLOC | |
24 | ||
25 | #include <Security/utilities.h> | |
26 | #include <Security/cssm.h> | |
27 | #include <cstring> | |
28 | #include <set> | |
29 | ||
30 | #ifdef _CPP_CSSMALLOC | |
31 | # pragma export on | |
32 | #endif | |
33 | ||
34 | namespace Security | |
35 | { | |
36 | ||
37 | // | |
38 | // An abstract allocator superclass, based on the simple malloc/realloc/free paradigm | |
39 | // that CDSA loves so much. If you have an allocation strategy and want objects | |
40 | // to be allocated through it, inherit from this. | |
41 | // | |
42 | class CssmAllocator { | |
43 | public: | |
44 | virtual ~CssmAllocator(); | |
45 | virtual void *malloc(size_t) = 0; | |
46 | virtual void free(void *) = 0; | |
47 | virtual void *realloc(void *, size_t) = 0; | |
48 | ||
49 | // | |
50 | // Template versions for added expressiveness. | |
51 | // Note that the integers are element counts, not byte sizes. | |
52 | // | |
53 | template <class T> T *alloc() | |
54 | { return reinterpret_cast<T *>(malloc(sizeof(T))); } | |
55 | ||
56 | template <class T> T *alloc(uint32 count) | |
57 | { return reinterpret_cast<T *>(malloc(sizeof(T) * count)); } | |
58 | ||
59 | template <class T> T *alloc(T *old, uint32 count) | |
60 | { return reinterpret_cast<T *>(realloc(old, sizeof(T) * count)); } | |
61 | ||
62 | template <class Data> CssmData alloc(const Data &source) | |
63 | { | |
64 | size_t length = source.length(); | |
65 | return CssmData(memcpy(malloc(length), source.data(), length), length); | |
66 | } | |
67 | ||
68 | // | |
69 | // Happier malloc/realloc for any type. Note that these still have | |
70 | // the original (byte-sized) argument profile. | |
71 | // | |
72 | template <class T> T *malloc(size_t size) | |
73 | { return reinterpret_cast<T *>(malloc(size)); } | |
74 | ||
75 | template <class T> T *realloc(void *addr, size_t size) | |
76 | { return reinterpret_cast<T *>(realloc(addr, size)); } | |
77 | ||
78 | // All right, if you *really* have to have calloc... | |
79 | void *calloc(size_t size, unsigned int count) | |
80 | { | |
81 | void *addr = malloc(size * count); | |
82 | memset(addr, 0, size * count); | |
83 | return addr; | |
84 | } | |
85 | ||
86 | // compare CssmAllocators for identity | |
87 | virtual bool operator == (const CssmAllocator &alloc) const; | |
88 | ||
89 | public: | |
90 | // allocator chooser options | |
91 | enum { | |
92 | normal = 0x0000, | |
93 | sensitive = 0x0001 | |
94 | }; | |
95 | ||
96 | static CssmAllocator &standard(uint32 request = normal); | |
97 | }; | |
98 | ||
99 | ||
100 | // | |
101 | // A POD wrapper for the memory functions structure passed around in CSSM. | |
102 | // | |
103 | class CssmMemoryFunctions : public PodWrapper<CssmMemoryFunctions, CSSM_MEMORY_FUNCS> { | |
104 | public: | |
105 | CssmMemoryFunctions(const CSSM_MEMORY_FUNCS &funcs) | |
106 | { *(CSSM_MEMORY_FUNCS *)this = funcs; } | |
107 | CssmMemoryFunctions() { } | |
108 | ||
109 | void *malloc(size_t size) const; | |
110 | void free(void *mem) const { free_func(mem, AllocRef); } | |
111 | void *realloc(void *mem, size_t size) const; | |
112 | void *calloc(uint32 count, size_t size) const; | |
113 | ||
114 | bool operator == (const CSSM_MEMORY_FUNCS &other) const | |
115 | { return !memcmp(this, &other, sizeof(*this)); } | |
116 | }; | |
117 | ||
118 | inline void *CssmMemoryFunctions::malloc(size_t size) const | |
119 | { | |
120 | if (void *addr = malloc_func(size, AllocRef)) | |
121 | return addr; | |
122 | throw std::bad_alloc(); | |
123 | } | |
124 | ||
125 | inline void *CssmMemoryFunctions::calloc(uint32 count, size_t size) const | |
126 | { | |
127 | if (void *addr = calloc_func(count, size, AllocRef)) | |
128 | return addr; | |
129 | throw std::bad_alloc(); | |
130 | } | |
131 | ||
132 | inline void *CssmMemoryFunctions::realloc(void *mem, size_t size) const | |
133 | { | |
134 | if (void *addr = realloc_func(mem, size, AllocRef)) | |
135 | return addr; | |
136 | throw std::bad_alloc(); | |
137 | } | |
138 | ||
139 | ||
140 | // | |
141 | // A CssmAllocator based on CssmMemoryFunctions | |
142 | // | |
143 | class CssmMemoryFunctionsAllocator : public CssmAllocator { | |
144 | public: | |
145 | CssmMemoryFunctionsAllocator(const CssmMemoryFunctions &memFuncs) : functions(memFuncs) { } | |
146 | ||
147 | void *malloc(size_t size); | |
148 | void free(void *addr); | |
149 | void *realloc(void *addr, size_t size); | |
150 | ||
151 | operator const CssmMemoryFunctions & () const { return functions; } | |
152 | ||
153 | private: | |
154 | const CssmMemoryFunctions functions; | |
155 | }; | |
156 | ||
157 | } // end namespace Security | |
158 | ||
159 | // | |
160 | // Global C++ allocation hooks to use CssmAllocators | |
161 | // | |
162 | inline void *operator new (size_t size, CssmAllocator &allocator) | |
163 | { return allocator.malloc(size); } | |
164 | ||
165 | // | |
166 | // You'd think that this is operator delete(const T *, CssmAllocator &), but you'd | |
167 | // be wrong. Specialized operator delete is only called during constructor cleanup. | |
168 | // Use this to cleanly destroy things. | |
169 | // | |
170 | template <class T> | |
171 | inline void destroy(T *obj, CssmAllocator &alloc) | |
172 | { | |
173 | obj->~T(); | |
174 | alloc.free(obj); | |
175 | } | |
176 | ||
177 | // untyped (release memory only, no destructor call) | |
178 | inline void destroy(void *obj, CssmAllocator &alloc) | |
179 | { | |
180 | alloc.free(obj); | |
181 | } | |
182 | ||
183 | namespace Security | |
184 | { | |
185 | ||
186 | // | |
187 | // A MemoryFunctions object based on a CssmAllocator. | |
188 | // Note that we don't copy the CssmAllocator object. It needs to live (at least) | |
189 | // as long as any CssmAllocatorMemoryFunctions object based on it. | |
190 | // | |
191 | class CssmAllocatorMemoryFunctions : public CssmMemoryFunctions { | |
192 | public: | |
193 | CssmAllocatorMemoryFunctions(CssmAllocator &alloc); | |
194 | CssmAllocatorMemoryFunctions() { /*IFDEBUG(*/ AllocRef = NULL /*)*/ ; } // later assignment req'd | |
195 | ||
196 | private: | |
197 | static void *relayMalloc(size_t size, void *ref); | |
198 | static void relayFree(void *mem, void *ref); | |
199 | static void *relayRealloc(void *mem, size_t size, void *ref); | |
200 | static void *relayCalloc(uint32 count, size_t size, void *ref); | |
201 | ||
202 | static CssmAllocator &allocator(void *ref) | |
203 | { return *reinterpret_cast<CssmAllocator *>(ref); } | |
204 | }; | |
205 | ||
206 | ||
207 | // | |
208 | // A mixin class to automatically manage your allocator. | |
209 | // To allow allocation (of your object) from any instance of CssmAllocator, | |
210 | // inherit from CssmHeap. Your users can then create heap instances of your thing by | |
211 | // new (an-allocator) YourClass(...) | |
212 | // or (still) | |
213 | // new YourClass(...) | |
214 | // for the default allocation source. The beauty is that when someone does a | |
215 | // delete pointer-to-your-instance | |
216 | // then the magic fairies will find the allocator that created the object and ask it | |
217 | // to free the memory (by calling its free() method). | |
218 | // The price of all that glory is memory overhead - typically one pointer per object. | |
219 | // | |
220 | class CssmHeap { | |
221 | public: | |
222 | void *operator new (size_t size, CssmAllocator *alloc = NULL); | |
223 | void operator delete (void *addr, size_t size); | |
224 | void operator delete (void *addr, size_t size, CssmAllocator *alloc); | |
225 | }; | |
226 | ||
227 | ||
228 | // | |
229 | // Here is a version of auto_ptr that works with CssmAllocators. It is designed | |
230 | // to be pretty much a drop-in replacement. It requires an allocator as a constructor | |
231 | // argument, of course. | |
232 | // Note that CssmAutoPtr<void> is perfectly valid, unlike its auto_ptr look-alike. | |
233 | // You can't dereference it, naturally. | |
234 | // | |
235 | template <class T> | |
236 | class CssmAutoPtr { | |
237 | public: | |
238 | CssmAllocator &allocator; | |
239 | ||
240 | CssmAutoPtr(CssmAllocator &alloc = CssmAllocator::standard()) | |
241 | : allocator(alloc), mine(NULL) { } | |
242 | CssmAutoPtr(CssmAllocator &alloc, T *p) | |
243 | : allocator(alloc), mine(p) { } | |
244 | CssmAutoPtr(T *p) | |
245 | : allocator(CssmAllocator::standard()), mine(p) { } | |
246 | template <class T1> CssmAutoPtr(CssmAutoPtr<T1> &src) | |
247 | : allocator(src.allocator), mine(src.release()) { } | |
248 | template <class T1> CssmAutoPtr(CssmAllocator &alloc, CssmAutoPtr<T1> &src) | |
249 | : allocator(alloc), mine(rc.release()) { assert(allocator == src.allocator); } | |
250 | ||
251 | ~CssmAutoPtr() { destroy(mine); } | |
252 | ||
253 | T *get() const throw() { return mine; } | |
254 | T *release() { T *result = mine; mine = NULL; return result; } | |
255 | void reset() { allocator.free(mine); mine = NULL; } | |
256 | ||
257 | operator T * () const { return mine; } | |
258 | T *operator -> () const { return mine; } | |
259 | T &operator * () const { assert(mine); return *mine; } | |
260 | ||
261 | private: | |
262 | T *mine; | |
263 | }; | |
264 | ||
265 | // specialization for void (i.e. void *), omitting the troublesome dereferencing ops. | |
266 | template <> | |
267 | class CssmAutoPtr<void> { | |
268 | public: | |
269 | CssmAllocator &allocator; | |
270 | ||
271 | CssmAutoPtr(CssmAllocator &alloc) : allocator(alloc), mine(NULL) { } | |
272 | CssmAutoPtr(CssmAllocator &alloc, void *p) : allocator(alloc), mine(p) { } | |
273 | template <class T1> CssmAutoPtr(CssmAutoPtr<T1> &src) | |
274 | : allocator(src.allocator), mine(src.release()) { } | |
275 | template <class T1> CssmAutoPtr(CssmAllocator &alloc, CssmAutoPtr<T1> &src) | |
276 | : allocator(alloc), mine(rc.release()) { assert(allocator == src.allocator); } | |
277 | ||
278 | ~CssmAutoPtr() { destroy(mine, allocator); } | |
279 | ||
280 | void *get() throw() { return mine; } | |
281 | void *release() { void *result = mine; mine = NULL; return result; } | |
282 | void reset() { allocator.free(mine); mine = NULL; } | |
283 | ||
284 | private: | |
285 | void *mine; | |
286 | }; | |
287 | ||
288 | ||
289 | // | |
290 | // Convenience forms of CssmAutoPtr that automatically make their (initial) object. | |
291 | // | |
292 | template <class T> | |
293 | class CssmNewAutoPtr : public CssmAutoPtr<T> { | |
294 | public: | |
295 | CssmNewAutoPtr(CssmAllocator &alloc = CssmAllocator::standard()) | |
296 | : CssmAutoPtr<T>(alloc, new(alloc) T) { } | |
297 | ||
298 | template <class A1> | |
299 | CssmNewAutoPtr(CssmAllocator &alloc, A1 &arg1) : CssmAutoPtr<T>(alloc, new(alloc) T(arg1)) { } | |
300 | template <class A1> | |
301 | CssmNewAutoPtr(CssmAllocator &alloc, const A1 &arg1) | |
302 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1)) { } | |
303 | ||
304 | template <class A1, class A2> | |
305 | CssmNewAutoPtr(CssmAllocator &alloc, A1 &arg1, A2 &arg2) | |
306 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { } | |
307 | template <class A1, class A2> | |
308 | CssmNewAutoPtr(CssmAllocator &alloc, const A1 &arg1, A2 &arg2) | |
309 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { } | |
310 | template <class A1, class A2> | |
311 | CssmNewAutoPtr(CssmAllocator &alloc, A1 &arg1, const A2 &arg2) | |
312 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { } | |
313 | template <class A1, class A2> | |
314 | CssmNewAutoPtr(CssmAllocator &alloc, const A1 &arg1, const A2 &arg2) | |
315 | : CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { } | |
316 | }; | |
317 | ||
318 | ||
319 | // | |
320 | // A CssmAllocator that keeps track of allocations and can throw everything | |
321 | // away unless explicitly committed. | |
322 | // | |
323 | class TrackingAllocator : public CssmAllocator | |
324 | { | |
325 | public: | |
326 | TrackingAllocator(CssmAllocator &inAllocator) : mAllocator(inAllocator) {} | |
327 | virtual ~TrackingAllocator(); | |
328 | ||
329 | void *malloc(size_t inSize) | |
330 | { | |
331 | void *anAddress = mAllocator.malloc(inSize); | |
332 | mAllocSet.insert(anAddress); | |
333 | return anAddress; | |
334 | } | |
335 | ||
336 | void free(void *inAddress) | |
337 | { | |
338 | mAllocator.free(inAddress); | |
339 | mAllocSet.erase(inAddress); | |
340 | } | |
341 | ||
342 | void *realloc(void *inAddress, size_t inNewSize) | |
343 | { | |
344 | void *anAddress = mAllocator.realloc(inAddress, inNewSize); | |
345 | if (anAddress != inAddress) | |
346 | { | |
347 | mAllocSet.erase(inAddress); | |
348 | mAllocSet.insert(anAddress); | |
349 | } | |
350 | ||
351 | return anAddress; | |
352 | } | |
353 | ||
354 | void commit() { mAllocSet.clear(); } | |
355 | private: | |
356 | typedef std::set<void *> AllocSet; | |
357 | ||
358 | CssmAllocator &mAllocator; | |
359 | AllocSet mAllocSet; | |
360 | }; | |
361 | ||
362 | } // end namespace Security | |
363 | ||
364 | #ifdef _CPP_CSSMALLOC | |
365 | # pragma export off | |
366 | #endif | |
367 | ||
368 | #endif //_H_CSSMALLOC |