]> git.saurik.com Git - apple/security.git/blame - cdsa/cdsa_utilities/cssmalloc.h
Security-30.1.tar.gz
[apple/security.git] / cdsa / cdsa_utilities / cssmalloc.h
CommitLineData
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
34namespace 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//
42class CssmAllocator {
43public:
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
89public:
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//
103class CssmMemoryFunctions : public PodWrapper<CssmMemoryFunctions, CSSM_MEMORY_FUNCS> {
104public:
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
118inline 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
125inline 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
132inline 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//
143class CssmMemoryFunctionsAllocator : public CssmAllocator {
144public:
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
153private:
154 const CssmMemoryFunctions functions;
155};
156
157} // end namespace Security
158
159//
160// Global C++ allocation hooks to use CssmAllocators
161//
162inline 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//
170template <class T>
171inline void destroy(T *obj, CssmAllocator &alloc)
172{
173 obj->~T();
174 alloc.free(obj);
175}
176
177// untyped (release memory only, no destructor call)
178inline void destroy(void *obj, CssmAllocator &alloc)
179{
180 alloc.free(obj);
181}
182
183namespace 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//
191class CssmAllocatorMemoryFunctions : public CssmMemoryFunctions {
192public:
193 CssmAllocatorMemoryFunctions(CssmAllocator &alloc);
194 CssmAllocatorMemoryFunctions() { /*IFDEBUG(*/ AllocRef = NULL /*)*/ ; } // later assignment req'd
195
196private:
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//
220class CssmHeap {
221public:
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//
235template <class T>
236class CssmAutoPtr {
237public:
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
261private:
262 T *mine;
263};
264
265// specialization for void (i.e. void *), omitting the troublesome dereferencing ops.
266template <>
267class CssmAutoPtr<void> {
268public:
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
284private:
285 void *mine;
286};
287
288
289//
290// Convenience forms of CssmAutoPtr that automatically make their (initial) object.
291//
292template <class T>
293class CssmNewAutoPtr : public CssmAutoPtr<T> {
294public:
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//
323class TrackingAllocator : public CssmAllocator
324{
325public:
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(); }
355private:
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