/* * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. * * The contents of this file constitute Original Code as defined in and are * subject to the Apple Public Source License Version 1.2 (the 'License'). * You may not use this file except in compliance with the License. Please obtain * a copy of the License at http://www.apple.com/publicsource and read it before * using this file. * * This Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the * specific language governing rights and limitations under the License. */ // // cssmalloc - memory allocation in the CDSA world // #ifndef _H_CSSMALLOC #define _H_CSSMALLOC #include #include #include #ifdef _CPP_CSSMALLOC # pragma export on #endif namespace Security { // // An abstract allocator superclass, based on the simple malloc/realloc/free paradigm // that CDSA loves so much. If you have an allocation strategy and want objects // to be allocated through it, inherit from this. // class CssmAllocator { public: virtual ~CssmAllocator(); virtual void *malloc(size_t) throw(std::bad_alloc) = 0; virtual void free(void *) throw() = 0; virtual void *realloc(void *, size_t) throw(std::bad_alloc) = 0; // // Template versions for added expressiveness. // Note that the integers are element counts, not byte sizes. // template T *alloc() throw(std::bad_alloc) { return reinterpret_cast(malloc(sizeof(T))); } template T *alloc(uint32 count) throw(std::bad_alloc) { return reinterpret_cast(malloc(sizeof(T) * count)); } template T *alloc(T *old, uint32 count) throw(std::bad_alloc) { return reinterpret_cast(realloc(old, sizeof(T) * count)); } template CssmData alloc(const Data &source) throw(std::bad_alloc) { size_t length = source.length(); return CssmData(memcpy(malloc(length), source.data(), length), length); } // // Happier malloc/realloc for any type. Note that these still have // the original (byte-sized) argument profile. // template T *malloc(size_t size) throw(std::bad_alloc) { return reinterpret_cast(malloc(size)); } template T *realloc(void *addr, size_t size) throw(std::bad_alloc) { return reinterpret_cast(realloc(addr, size)); } // All right, if you *really* have to have calloc... void *calloc(size_t size, unsigned int count) throw(std::bad_alloc) { void *addr = malloc(size * count); memset(addr, 0, size * count); return addr; } // compare CssmAllocators for identity virtual bool operator == (const CssmAllocator &alloc) const throw(); public: // allocator chooser options enum { normal = 0x0000, sensitive = 0x0001 }; static CssmAllocator &standard(uint32 request = normal); }; // // A POD wrapper for the memory functions structure passed around in CSSM. // class CssmMemoryFunctions : public PodWrapper { public: CssmMemoryFunctions(const CSSM_MEMORY_FUNCS &funcs) { *(CSSM_MEMORY_FUNCS *)this = funcs; } CssmMemoryFunctions() { } void *malloc(size_t size) const throw(std::bad_alloc); void free(void *mem) const throw() { free_func(mem, AllocRef); } void *realloc(void *mem, size_t size) const throw(std::bad_alloc); void *calloc(uint32 count, size_t size) const throw(std::bad_alloc); bool operator == (const CSSM_MEMORY_FUNCS &other) const throw() { return !memcmp(this, &other, sizeof(*this)); } }; inline void *CssmMemoryFunctions::malloc(size_t size) const throw(std::bad_alloc) { if (void *addr = malloc_func(size, AllocRef)) return addr; throw std::bad_alloc(); } inline void *CssmMemoryFunctions::calloc(uint32 count, size_t size) const throw(std::bad_alloc) { if (void *addr = calloc_func(count, size, AllocRef)) return addr; throw std::bad_alloc(); } inline void *CssmMemoryFunctions::realloc(void *mem, size_t size) const throw(std::bad_alloc) { if (void *addr = realloc_func(mem, size, AllocRef)) return addr; throw std::bad_alloc(); } // // A CssmAllocator based on CssmMemoryFunctions // class CssmMemoryFunctionsAllocator : public CssmAllocator { public: CssmMemoryFunctionsAllocator(const CssmMemoryFunctions &memFuncs) : functions(memFuncs) { } void *malloc(size_t size) throw(std::bad_alloc); void free(void *addr) throw(); void *realloc(void *addr, size_t size) throw(std::bad_alloc); operator const CssmMemoryFunctions & () const throw() { return functions; } private: const CssmMemoryFunctions functions; }; } // end namespace Security // // Global C++ allocation hooks to use CssmAllocators // inline void *operator new (size_t size, CssmAllocator &allocator) throw(std::bad_alloc) { return allocator.malloc(size); } // // You'd think that this is operator delete(const T *, CssmAllocator &), but you'd // be wrong. Specialized operator delete is only called during constructor cleanup. // Use this to cleanly destroy things. // template inline void destroy(T *obj, CssmAllocator &alloc) throw() { obj->~T(); alloc.free(obj); } // untyped (release memory only, no destructor call) inline void destroy(void *obj, CssmAllocator &alloc) throw() { alloc.free(obj); } namespace Security { // // A MemoryFunctions object based on a CssmAllocator. // Note that we don't copy the CssmAllocator object. It needs to live (at least) // as long as any CssmAllocatorMemoryFunctions object based on it. // class CssmAllocatorMemoryFunctions : public CssmMemoryFunctions { public: CssmAllocatorMemoryFunctions(CssmAllocator &alloc); CssmAllocatorMemoryFunctions() { /*IFDEBUG(*/ AllocRef = NULL /*)*/ ; } // later assignment req'd private: static void *relayMalloc(size_t size, void *ref) throw(std::bad_alloc); static void relayFree(void *mem, void *ref) throw(); static void *relayRealloc(void *mem, size_t size, void *ref) throw(std::bad_alloc); static void *relayCalloc(uint32 count, size_t size, void *ref) throw(std::bad_alloc); static CssmAllocator &allocator(void *ref) throw() { return *reinterpret_cast(ref); } }; // // A mixin class to automagically manage your allocator. // To allow allocation (of your object) from any instance of CssmAllocator, // inherit from CssmHeap. Your users can then create heap instances of your thing by // new (an-allocator) YourClass(...) // or (still) // new YourClass(...) // for the default allocation source. The beauty is that when someone does a // delete pointer-to-your-instance // then the magic fairies will find the allocator that created the object and ask it // to free the memory (by calling its free() method). // The price of all that glory is memory overhead - typically one pointer per object. // class CssmHeap { public: void *operator new (size_t size, CssmAllocator *alloc = NULL) throw(std::bad_alloc); void operator delete (void *addr, size_t size) throw(); void operator delete (void *addr, size_t size, CssmAllocator *alloc) throw(); }; // // Here is a version of auto_ptr that works with CssmAllocators. It is designed // to be pretty much a drop-in replacement. It requires an allocator as a constructor // argument, of course. // Note that CssmAutoPtr is perfectly valid, unlike its auto_ptr look-alike. // You can't dereference it, naturally. // template class CssmAutoPtr { public: CssmAllocator &allocator; CssmAutoPtr(CssmAllocator &alloc = CssmAllocator::standard()) : allocator(alloc), mine(NULL) { } CssmAutoPtr(CssmAllocator &alloc, T *p) : allocator(alloc), mine(p) { } CssmAutoPtr(T *p) : allocator(CssmAllocator::standard()), mine(p) { } template CssmAutoPtr(CssmAutoPtr &src) : allocator(src.allocator), mine(src.release()) { } template CssmAutoPtr(CssmAllocator &alloc, CssmAutoPtr &src) : allocator(alloc), mine(rc.release()) { assert(allocator == src.allocator); } ~CssmAutoPtr() { allocator.free(mine); } T *get() const throw() { return mine; } T *release() { T *result = mine; mine = NULL; return result; } void reset() { allocator.free(mine); mine = NULL; } operator T * () const { return mine; } T *operator -> () const { return mine; } T &operator * () const { assert(mine); return *mine; } private: T *mine; }; // specialization for void (i.e. void *), omitting the troublesome dereferencing ops. template <> class CssmAutoPtr { public: CssmAllocator &allocator; CssmAutoPtr(CssmAllocator &alloc) : allocator(alloc), mine(NULL) { } CssmAutoPtr(CssmAllocator &alloc, void *p) : allocator(alloc), mine(p) { } template CssmAutoPtr(CssmAutoPtr &src) : allocator(src.allocator), mine(src.release()) { } template CssmAutoPtr(CssmAllocator &alloc, CssmAutoPtr &src) : allocator(alloc), mine(rc.release()) { assert(allocator == src.allocator); } ~CssmAutoPtr() { destroy(mine, allocator); } void *get() throw() { return mine; } void *release() { void *result = mine; mine = NULL; return result; } void reset() { allocator.free(mine); mine = NULL; } private: void *mine; }; // // Convenience forms of CssmAutoPtr that automatically make their (initial) object. // template class CssmNewAutoPtr : public CssmAutoPtr { public: CssmNewAutoPtr(CssmAllocator &alloc = CssmAllocator::standard()) : CssmAutoPtr(alloc, new(alloc) T) { } template CssmNewAutoPtr(CssmAllocator &alloc, A1 &arg1) : CssmAutoPtr(alloc, new(alloc) T(arg1)) { } template CssmNewAutoPtr(CssmAllocator &alloc, const A1 &arg1) : CssmAutoPtr(alloc, new(alloc) T(arg1)) { } template CssmNewAutoPtr(CssmAllocator &alloc, A1 &arg1, A2 &arg2) : CssmAutoPtr(alloc, new(alloc) T(arg1, arg2)) { } template CssmNewAutoPtr(CssmAllocator &alloc, const A1 &arg1, A2 &arg2) : CssmAutoPtr(alloc, new(alloc) T(arg1, arg2)) { } template CssmNewAutoPtr(CssmAllocator &alloc, A1 &arg1, const A2 &arg2) : CssmAutoPtr(alloc, new(alloc) T(arg1, arg2)) { } template CssmNewAutoPtr(CssmAllocator &alloc, const A1 &arg1, const A2 &arg2) : CssmAutoPtr(alloc, new(alloc) T(arg1, arg2)) { } }; // // A generic helper for the unhappily ubiquitous CSSM-style // (count, pointer-to-array) style of arrays. // template class CssmVector { public: CssmVector(uint32 &cnt, Base * &vec, CssmAllocator &alloc = CssmAllocator::standard()) : count(cnt), vector(reinterpret_cast(vec)), allocator(alloc) { count = 0; vector = NULL; } ~CssmVector() { allocator.free(vector); } uint32 &count; Wrapper * &vector; CssmAllocator &allocator; public: Wrapper &operator [] (uint32 ix) { assert(ix < count); return vector[ix]; } void operator += (const Wrapper &add) { vector = reinterpret_cast(allocator.realloc(vector, (count + 1) * sizeof(Wrapper))); //@@@???compiler bug??? vector = allocator.alloc(vector, count + 1); vector[count++] = add; } }; } // end namespace Security #ifdef _CPP_CSSMALLOC # pragma export off #endif #endif //_H_CSSMALLOC