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