X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/72a12576750f52947eb043106ba5c12c0d07decf..b1ab9ed8d0e0f1c3b66d7daa8fd5564444c56195:/libsecurity_utilities/lib/alloc.h diff --git a/libsecurity_utilities/lib/alloc.h b/libsecurity_utilities/lib/alloc.h new file mode 100644 index 00000000..100354ab --- /dev/null +++ b/libsecurity_utilities/lib/alloc.h @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2000-2004 Apple Computer, Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The 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. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// alloc - abstract malloc-like allocator abstraction +// +#ifndef _H_ALLOC +#define _H_ALLOC + +#include +#include + +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 Allocator { +public: + virtual ~Allocator(); + 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)); } + + + // + // 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 Allocators for identity + virtual bool operator == (const Allocator &alloc) const throw(); + +public: + // allocator chooser options + enum { + normal = 0x0000, + sensitive = 0x0001 + }; + + static Allocator &standard(UInt32 request = normal); +}; + + +// +// You'd think that this is operator delete(const T *, Allocator &), 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, Allocator &alloc) throw() +{ + obj->~T(); + alloc.free(obj); +} + +// untyped (release memory only, no destructor call) +inline void destroy(void *obj, Allocator &alloc) throw() +{ + alloc.free(obj); +} + + +// +// A mixin class to automagically manage your allocator. +// To allow allocation (of your object) from any instance of Allocator, +// 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, Allocator *alloc = NULL) throw(std::bad_alloc); + void operator delete (void *addr, size_t size) throw(); + void operator delete (void *addr, size_t size, Allocator *alloc) throw(); +}; + + +// +// Here is a version of auto_ptr that works with Allocators. 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: + Allocator &allocator; + + CssmAutoPtr(Allocator &alloc = Allocator::standard()) + : allocator(alloc), mine(NULL) { } + CssmAutoPtr(Allocator &alloc, T *p) + : allocator(alloc), mine(p) { } + CssmAutoPtr(T *p) + : allocator(Allocator::standard()), mine(p) { } + template CssmAutoPtr(CssmAutoPtr &src) + : allocator(src.allocator), mine(src.release()) { } + template CssmAutoPtr(Allocator &alloc, CssmAutoPtr &src) + : allocator(alloc), mine(src.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: + Allocator &allocator; + + CssmAutoPtr(Allocator &alloc) : allocator(alloc), mine(NULL) { } + CssmAutoPtr(Allocator &alloc, void *p) : allocator(alloc), mine(p) { } + template CssmAutoPtr(CssmAutoPtr &src) + : allocator(src.allocator), mine(src.release()) { } + template CssmAutoPtr(Allocator &alloc, CssmAutoPtr &src) + : allocator(alloc), mine(src.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(Allocator &alloc = Allocator::standard()) + : CssmAutoPtr(alloc, new(alloc) T) { } + + template + CssmNewAutoPtr(Allocator &alloc, A1 &arg1) : CssmAutoPtr(alloc, new(alloc) T(arg1)) { } + template + CssmNewAutoPtr(Allocator &alloc, const A1 &arg1) + : CssmAutoPtr(alloc, new(alloc) T(arg1)) { } + + template + CssmNewAutoPtr(Allocator &alloc, A1 &arg1, A2 &arg2) + : CssmAutoPtr(alloc, new(alloc) T(arg1, arg2)) { } + template + CssmNewAutoPtr(Allocator &alloc, const A1 &arg1, A2 &arg2) + : CssmAutoPtr(alloc, new(alloc) T(arg1, arg2)) { } + template + CssmNewAutoPtr(Allocator &alloc, A1 &arg1, const A2 &arg2) + : CssmAutoPtr(alloc, new(alloc) T(arg1, arg2)) { } + template + CssmNewAutoPtr(Allocator &alloc, const A1 &arg1, const A2 &arg2) + : CssmAutoPtr(alloc, new(alloc) T(arg1, arg2)) { } +}; + + +} // end namespace Security + + +// +// Global C++ allocation hooks to use Allocators (global namespace) +// +inline void *operator new (size_t size, Allocator &allocator) throw (std::bad_alloc) +{ return allocator.malloc(size); } + +inline void *operator new[] (size_t size, Allocator &allocator) throw (std::bad_alloc) +{ return allocator.malloc(size); } + + +#endif //_H_ALLOC