1/*
2 * Copyright (c) 2000-2004,2011-2012,2014 Apple Inc. All Rights Reserved.
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
34namespace 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//
43class Allocator {
44public:
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)
58	{ return reinterpret_cast<T *>(malloc(sizeof(T) * count)); }
59
60	template <class T> T *alloc(T *old, UInt32 count) throw(std::bad_alloc)
61	{ return reinterpret_cast<T *>(realloc(old, sizeof(T) * count)); }
62
63
64	//
65	// Happier malloc/realloc for any type. Note that these still have
66	// the original (byte-sized) argument profile.
67	//
68	template <class T> T *malloc(size_t size) throw(std::bad_alloc)
69	{ return reinterpret_cast<T *>(malloc(size)); }
70
71	template <class T> T *realloc(void *addr, size_t size) throw(std::bad_alloc)
72	{ return reinterpret_cast<T *>(realloc(addr, size)); }
73
74	// All right, if you *really* have to have calloc...
75	void *calloc(size_t size, size_t count) throw(std::bad_alloc)
76	{
77		void *addr = malloc(size * count);
78		memset(addr, 0, size * count);
79		return addr;
80	}
81
82	// compare Allocators for identity
83	virtual bool operator == (const Allocator &alloc) const throw();
84
85public:
86	// allocator chooser options
87	enum {
88		normal = 0x0000,
89		sensitive = 0x0001
90	};
91
92	static Allocator &standard(UInt32 request = normal);
93};
94
95
96//
97// You'd think that this is operator delete(const T *, Allocator &), but you'd
98// be wrong. Specialized operator delete is only called during constructor cleanup.
99// Use this to cleanly destroy things.
100//
101template <class T>
102inline void destroy(T *obj, Allocator &alloc) throw()
103{
104	obj->~T();
105	alloc.free(obj);
106}
107
108// untyped (release memory only, no destructor call)
109inline void destroy(void *obj, Allocator &alloc) throw()
110{
111	alloc.free(obj);
112}
113
114
115//
116// A mixin class to automagically manage your allocator.
117// To allow allocation (of your object) from any instance of Allocator,
118// inherit from CssmHeap. Your users can then create heap instances of your thing by
119//		new (an-allocator) YourClass(...)
120// or (still)
121//		new YourClass(...)
122// for the default allocation source. The beauty is that when someone does a
123//		delete pointer-to-your-instance
124// then the magic fairies will find the allocator that created the object and ask it
125// to free the memory (by calling its free() method).
126// The price of all that glory is memory overhead - typically one pointer per object.
127//
128class CssmHeap {
129public:
130	void *operator new (size_t size, Allocator *alloc = NULL) throw(std::bad_alloc);
131	void operator delete (void *addr, size_t size) throw();
132	void operator delete (void *addr, size_t size, Allocator *alloc) throw();
133};
134
135
136//
137// Here is a version of auto_ptr that works with Allocators. It is designed
138// to be pretty much a drop-in replacement. It requires an allocator as a constructor
139// argument, of course.
140// Note that CssmAutoPtr<void> is perfectly valid, unlike its auto_ptr look-alike.
141// You can't dereference it, naturally.
142//
143template <class T>
144class CssmAutoPtr {
145public:
146	Allocator &allocator;
147
148	CssmAutoPtr(Allocator &alloc = Allocator::standard())
149	: allocator(alloc), mine(NULL) { }
150	CssmAutoPtr(Allocator &alloc, T *p)
151	: allocator(alloc), mine(p) { }
152	CssmAutoPtr(T *p)
153	: allocator(Allocator::standard()), mine(p) { }
154	template <class T1> CssmAutoPtr(CssmAutoPtr<T1> &src)
155	: allocator(src.allocator), mine(src.release()) { }
156	template <class T1> CssmAutoPtr(Allocator &alloc, CssmAutoPtr<T1> &src)
157	: allocator(alloc), mine(src.release()) { assert(allocator == src.allocator); }
158
159	~CssmAutoPtr()				{ allocator.free(mine); }
160
161	T *get() const throw()		{ return mine; }
162	T *release()				{ T *result = mine; mine = NULL; return result; }
163	void reset()				{ allocator.free(mine); mine = NULL; }
164
165	operator T * () const		{ return mine; }
166	T *operator -> () const		{ return mine; }
167	T &operator * () const		{ assert(mine); return *mine; }
168
169private:
170	T *mine;
171};
172
173// specialization for void (i.e. void *), omitting the troublesome dereferencing ops.
174template <>
175class CssmAutoPtr<void> {
176public:
177	Allocator &allocator;
178
179	CssmAutoPtr(Allocator &alloc) : allocator(alloc), mine(NULL) { }
180	CssmAutoPtr(Allocator &alloc, void *p) : allocator(alloc), mine(p) { }
181	template <class T1> CssmAutoPtr(CssmAutoPtr<T1> &src)
182	: allocator(src.allocator), mine(src.release()) { }
183	template <class T1> CssmAutoPtr(Allocator &alloc, CssmAutoPtr<T1> &src)
184	: allocator(alloc), mine(src.release()) { assert(allocator == src.allocator); }
185
186	~CssmAutoPtr()				{ destroy(mine, allocator); }
187
188	void *get() throw()		{ return mine; }
189	void *release()				{ void *result = mine; mine = NULL; return result; }
190	void reset()				{ allocator.free(mine); mine = NULL; }
191
192private:
193	void *mine;
194};
195
196
197//
198// Convenience forms of CssmAutoPtr that automatically make their (initial) object.
199//
200template <class T>
201class CssmNewAutoPtr : public CssmAutoPtr<T> {
202public:
203	CssmNewAutoPtr(Allocator &alloc = Allocator::standard())
204	: CssmAutoPtr<T>(alloc, new(alloc) T) { }
205
206	template <class A1>
207	CssmNewAutoPtr(Allocator &alloc, A1 &arg1) : CssmAutoPtr<T>(alloc, new(alloc) T(arg1)) { }
208	template <class A1>
209	CssmNewAutoPtr(Allocator &alloc, const A1 &arg1)
210	: CssmAutoPtr<T>(alloc, new(alloc) T(arg1)) { }
211
212	template <class A1, class A2>
213	CssmNewAutoPtr(Allocator &alloc, A1 &arg1, A2 &arg2)
214	: CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { }
215	template <class A1, class A2>
216	CssmNewAutoPtr(Allocator &alloc, const A1 &arg1, A2 &arg2)
217	: CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { }
218	template <class A1, class A2>
219	CssmNewAutoPtr(Allocator &alloc, A1 &arg1, const A2 &arg2)
220	: CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { }
221	template <class A1, class A2>
222	CssmNewAutoPtr(Allocator &alloc, const A1 &arg1, const A2 &arg2)
223	: CssmAutoPtr<T>(alloc, new(alloc) T(arg1, arg2)) { }
224};
225
226
227} // end namespace Security
228
229
230//
231// Global C++ allocation hooks to use Allocators (global namespace)
232//
233inline void *operator new (size_t size, Allocator &allocator) throw (std::bad_alloc)
234{ return allocator.malloc(size); }
235
236inline void *operator new[] (size_t size, Allocator &allocator) throw (std::bad_alloc)
237{ return allocator.malloc(size); }
238
239
240#endif //_H_ALLOC
241