• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

secblock.h

00001 // secblock.h - written and placed in the public domain by Wei Dai
00002 
00003 #ifndef CRYPTOPP_SECBLOCK_H
00004 #define CRYPTOPP_SECBLOCK_H
00005 
00006 #include "config.h"
00007 #include "misc.h"
00008 #include <assert.h>
00009 
00010 #if defined(CRYPTOPP_MEMALIGN_AVAILABLE) || defined(CRYPTOPP_MM_MALLOC_AVAILABLE) || defined(QNX)
00011     #include <malloc.h>
00012 #else
00013     #include <stdlib.h>
00014 #endif
00015 
00016 NAMESPACE_BEGIN(CryptoPP)
00017 
00018 // ************** secure memory allocation ***************
00019 
00020 template<class T>
00021 class AllocatorBase
00022 {
00023 public:
00024     typedef T value_type;
00025     typedef size_t size_type;
00026 #ifdef CRYPTOPP_MSVCRT6
00027     typedef ptrdiff_t difference_type;
00028 #else
00029     typedef std::ptrdiff_t difference_type;
00030 #endif
00031     typedef T * pointer;
00032     typedef const T * const_pointer;
00033     typedef T & reference;
00034     typedef const T & const_reference;
00035 
00036     pointer address(reference r) const {return (&r);}
00037     const_pointer address(const_reference r) const {return (&r); }
00038     void construct(pointer p, const T& val) {new (p) T(val);}
00039     void destroy(pointer p) {p->~T();}
00040     size_type max_size() const {return ~size_type(0)/sizeof(T);}    // switch to std::numeric_limits<T>::max later
00041 
00042 protected:
00043     static void CheckSize(size_t n)
00044     {
00045         if (n > ~size_t(0) / sizeof(T))
00046             throw InvalidArgument("AllocatorBase: requested size would cause integer overflow");
00047     }
00048 };
00049 
00050 #define CRYPTOPP_INHERIT_ALLOCATOR_TYPES    \
00051 typedef typename AllocatorBase<T>::value_type value_type;\
00052 typedef typename AllocatorBase<T>::size_type size_type;\
00053 typedef typename AllocatorBase<T>::difference_type difference_type;\
00054 typedef typename AllocatorBase<T>::pointer pointer;\
00055 typedef typename AllocatorBase<T>::const_pointer const_pointer;\
00056 typedef typename AllocatorBase<T>::reference reference;\
00057 typedef typename AllocatorBase<T>::const_reference const_reference;
00058 
00059 #if defined(_MSC_VER) && (_MSC_VER < 1300)
00060 // this pragma causes an internal compiler error if placed immediately before std::swap(a, b)
00061 #pragma warning(push)
00062 #pragma warning(disable: 4700)  // VC60 workaround: don't know how to get rid of this warning
00063 #endif
00064 
00065 template <class T, class A>
00066 typename A::pointer StandardReallocate(A& a, T *p, typename A::size_type oldSize, typename A::size_type newSize, bool preserve)
00067 {
00068     if (oldSize == newSize)
00069         return p;
00070 
00071     if (preserve)
00072     {
00073         typename A::pointer newPointer = a.allocate(newSize, NULL);
00074         memcpy_s(newPointer, sizeof(T)*newSize, p, sizeof(T)*STDMIN(oldSize, newSize));
00075         a.deallocate(p, oldSize);
00076         return newPointer;
00077     }
00078     else
00079     {
00080         a.deallocate(p, oldSize);
00081         return a.allocate(newSize, NULL);
00082     }
00083 }
00084 
00085 #if defined(_MSC_VER) && (_MSC_VER < 1300)
00086 #pragma warning(pop)
00087 #endif
00088 
00089 template <class T, bool T_Align16 = false>
00090 class AllocatorWithCleanup : public AllocatorBase<T>
00091 {
00092 public:
00093     CRYPTOPP_INHERIT_ALLOCATOR_TYPES
00094 
00095     pointer allocate(size_type n, const void * = NULL)
00096     {
00097         CheckSize(n);
00098         if (n == 0)
00099             return NULL;
00100 
00101         if (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16 && n*sizeof(T) >= 16)
00102         {
00103             byte *p;
00104         #ifdef CRYPTOPP_MM_MALLOC_AVAILABLE
00105             while (!(p = (byte *)_mm_malloc(sizeof(T)*n, 16)))
00106         #elif defined(CRYPTOPP_MEMALIGN_AVAILABLE)
00107             while (!(p = (byte *)memalign(16, sizeof(T)*n)))
00108         #elif defined(CRYPTOPP_MALLOC_ALIGNMENT_IS_16)
00109             while (!(p = (byte *)malloc(sizeof(T)*n)))
00110         #else
00111             while (!(p = (byte *)malloc(sizeof(T)*n + 16)))
00112         #endif
00113                 CallNewHandler();
00114 
00115         #ifdef CRYPTOPP_NO_ALIGNED_ALLOC
00116             size_t adjustment = 16-((size_t)p%16);
00117             p += adjustment;
00118             p[-1] = (byte)adjustment;
00119         #endif
00120 
00121             assert(IsAlignedOn(p, 16));
00122             return (pointer)p;
00123         }
00124 
00125         pointer p;
00126         while (!(p = (pointer)malloc(sizeof(T)*n)))
00127             CallNewHandler();
00128         return p;
00129     }
00130 
00131     void deallocate(void *p, size_type n)
00132     {
00133         memset_z(p, 0, n*sizeof(T));
00134 
00135         if (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16 && n*sizeof(T) >= 16)
00136         {
00137         #ifdef CRYPTOPP_MM_MALLOC_AVAILABLE
00138             _mm_free(p);
00139         #elif defined(CRYPTOPP_NO_ALIGNED_ALLOC)
00140             p = (byte *)p - ((byte *)p)[-1];
00141             free(p);
00142         #else
00143             free(p);
00144         #endif
00145             return;
00146         }
00147 
00148         free(p);
00149     }
00150 
00151     pointer reallocate(T *p, size_type oldSize, size_type newSize, bool preserve)
00152     {
00153         return StandardReallocate(*this, p, oldSize, newSize, preserve);
00154     }
00155 
00156     // VS.NET STL enforces the policy of "All STL-compliant allocators have to provide a
00157     // template class member called rebind".
00158     template <class U> struct rebind { typedef AllocatorWithCleanup<U, T_Align16> other; };
00159 #if _MSC_VER >= 1500
00160     AllocatorWithCleanup() {}
00161     template <class U, bool A> AllocatorWithCleanup(const AllocatorWithCleanup<U, A> &) {}
00162 #endif
00163 };
00164 
00165 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<byte>;
00166 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word16>;
00167 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word32>;
00168 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word64>;
00169 #if CRYPTOPP_BOOL_X86
00170 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word, true>;   // for Integer
00171 #endif
00172 
00173 template <class T>
00174 class NullAllocator : public AllocatorBase<T>
00175 {
00176 public:
00177     CRYPTOPP_INHERIT_ALLOCATOR_TYPES
00178 
00179     pointer allocate(size_type n, const void * = NULL)
00180     {
00181         assert(false);
00182         return NULL;
00183     }
00184 
00185     void deallocate(void *p, size_type n)
00186     {
00187         assert(false);
00188     }
00189 
00190     size_type max_size() const {return 0;}
00191 };
00192 
00193 // This allocator can't be used with standard collections because
00194 // they require that all objects of the same allocator type are equivalent.
00195 // So this is for use with SecBlock only.
00196 template <class T, size_t S, class A = NullAllocator<T>, bool T_Align16 = false>
00197 class FixedSizeAllocatorWithCleanup : public AllocatorBase<T>
00198 {
00199 public:
00200     CRYPTOPP_INHERIT_ALLOCATOR_TYPES
00201 
00202     FixedSizeAllocatorWithCleanup() : m_allocated(false) {}
00203 
00204     pointer allocate(size_type n)
00205     {
00206         assert(IsAlignedOn(m_array, 8));
00207 
00208         if (n <= S && !m_allocated)
00209         {
00210             m_allocated = true;
00211             return GetAlignedArray();
00212         }
00213         else
00214             return m_fallbackAllocator.allocate(n);
00215     }
00216 
00217     pointer allocate(size_type n, const void *hint)
00218     {
00219         if (n <= S && !m_allocated)
00220         {
00221             m_allocated = true;
00222             return GetAlignedArray();
00223         }
00224         else
00225             return m_fallbackAllocator.allocate(n, hint);
00226     }
00227 
00228     void deallocate(void *p, size_type n)
00229     {
00230         if (p == GetAlignedArray())
00231         {
00232             assert(n <= S);
00233             assert(m_allocated);
00234             m_allocated = false;
00235             memset(p, 0, n*sizeof(T));
00236         }
00237         else
00238             m_fallbackAllocator.deallocate(p, n);
00239     }
00240 
00241     pointer reallocate(pointer p, size_type oldSize, size_type newSize, bool preserve)
00242     {
00243         if (p == GetAlignedArray() && newSize <= S)
00244         {
00245             assert(oldSize <= S);
00246             if (oldSize > newSize)
00247                 memset(p + newSize, 0, (oldSize-newSize)*sizeof(T));
00248             return p;
00249         }
00250 
00251         pointer newPointer = allocate(newSize, NULL);
00252         if (preserve)
00253             memcpy(newPointer, p, sizeof(T)*STDMIN(oldSize, newSize));
00254         deallocate(p, oldSize);
00255         return newPointer;
00256     }
00257 
00258     size_type max_size() const {return STDMAX(m_fallbackAllocator.max_size(), S);}
00259 
00260 private:
00261 #ifdef __BORLANDC__
00262     T* GetAlignedArray() {return m_array;}
00263     T m_array[S];
00264 #else
00265     T* GetAlignedArray() {return (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? (T*)(((byte *)m_array) + (0-(size_t)m_array)%16) : m_array;}
00266     CRYPTOPP_ALIGN_DATA(8) T m_array[(CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? S+8/sizeof(T) : S];
00267 #endif
00268     A m_fallbackAllocator;
00269     bool m_allocated;
00270 };
00271 
00272 //! a block of memory allocated using A
00273 template <class T, class A = AllocatorWithCleanup<T> >
00274 class SecBlock
00275 {
00276 public:
00277     typedef typename A::value_type value_type;
00278     typedef typename A::pointer iterator;
00279     typedef typename A::const_pointer const_iterator;
00280     typedef typename A::size_type size_type;
00281 
00282     explicit SecBlock(size_type size=0)
00283         : m_size(size) {m_ptr = m_alloc.allocate(size, NULL);}
00284     SecBlock(const SecBlock<T, A> &t)
00285         : m_size(t.m_size) {m_ptr = m_alloc.allocate(m_size, NULL); memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, m_size*sizeof(T));}
00286     SecBlock(const T *t, size_type len)
00287         : m_size(len)
00288     {
00289         m_ptr = m_alloc.allocate(len, NULL);
00290         if (t == NULL)
00291             memset_z(m_ptr, 0, len*sizeof(T));
00292         else
00293             memcpy(m_ptr, t, len*sizeof(T));
00294     }
00295 
00296     ~SecBlock()
00297         {m_alloc.deallocate(m_ptr, m_size);}
00298 
00299 #ifdef __BORLANDC__
00300     operator T *() const
00301         {return (T*)m_ptr;}
00302 #else
00303     operator const void *() const
00304         {return m_ptr;}
00305     operator void *()
00306         {return m_ptr;}
00307 
00308     operator const T *() const
00309         {return m_ptr;}
00310     operator T *()
00311         {return m_ptr;}
00312 #endif
00313 
00314 //  T *operator +(size_type offset)
00315 //      {return m_ptr+offset;}
00316 
00317 //  const T *operator +(size_type offset) const
00318 //      {return m_ptr+offset;}
00319 
00320 //  T& operator[](size_type index)
00321 //      {assert(index >= 0 && index < m_size); return m_ptr[index];}
00322 
00323 //  const T& operator[](size_type index) const
00324 //      {assert(index >= 0 && index < m_size); return m_ptr[index];}
00325 
00326     iterator begin()
00327         {return m_ptr;}
00328     const_iterator begin() const
00329         {return m_ptr;}
00330     iterator end()
00331         {return m_ptr+m_size;}
00332     const_iterator end() const
00333         {return m_ptr+m_size;}
00334 
00335     typename A::pointer data() {return m_ptr;}
00336     typename A::const_pointer data() const {return m_ptr;}
00337 
00338     size_type size() const {return m_size;}
00339     bool empty() const {return m_size == 0;}
00340 
00341     byte * BytePtr() {return (byte *)m_ptr;}
00342     const byte * BytePtr() const {return (const byte *)m_ptr;}
00343     size_type SizeInBytes() const {return m_size*sizeof(T);}
00344 
00345     //! set contents and size
00346     void Assign(const T *t, size_type len)
00347     {
00348         New(len);
00349         memcpy_s(m_ptr, m_size*sizeof(T), t, len*sizeof(T));
00350     }
00351 
00352     //! copy contents and size from another SecBlock
00353     void Assign(const SecBlock<T, A> &t)
00354     {
00355         New(t.m_size);
00356         memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, m_size*sizeof(T));
00357     }
00358 
00359     SecBlock<T, A>& operator=(const SecBlock<T, A> &t)
00360     {
00361         Assign(t);
00362         return *this;
00363     }
00364 
00365     // append to this object
00366     SecBlock<T, A>& operator+=(const SecBlock<T, A> &t)
00367     {
00368         size_type oldSize = m_size;
00369         Grow(m_size+t.m_size);
00370         memcpy_s(m_ptr+oldSize, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
00371         return *this;
00372     }
00373 
00374     // append operator
00375     SecBlock<T, A> operator+(const SecBlock<T, A> &t)
00376     {
00377         SecBlock<T, A> result(m_size+t.m_size);
00378         memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T));
00379         memcpy_s(result.m_ptr+m_size, t.m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
00380         return result;
00381     }
00382 
00383     bool operator==(const SecBlock<T, A> &t) const
00384     {
00385         return m_size == t.m_size && VerifyBufsEqual(m_ptr, t.m_ptr, m_size*sizeof(T));
00386     }
00387 
00388     bool operator!=(const SecBlock<T, A> &t) const
00389     {
00390         return !operator==(t);
00391     }
00392 
00393     //! change size, without preserving contents
00394     void New(size_type newSize)
00395     {
00396         m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false);
00397         m_size = newSize;
00398     }
00399 
00400     //! change size and set contents to 0
00401     void CleanNew(size_type newSize)
00402     {
00403         New(newSize);
00404         memset_z(m_ptr, 0, m_size*sizeof(T));
00405     }
00406 
00407     //! change size only if newSize > current size. contents are preserved
00408     void Grow(size_type newSize)
00409     {
00410         if (newSize > m_size)
00411         {
00412             m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
00413             m_size = newSize;
00414         }
00415     }
00416 
00417     //! change size only if newSize > current size. contents are preserved and additional area is set to 0
00418     void CleanGrow(size_type newSize)
00419     {
00420         if (newSize > m_size)
00421         {
00422             m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
00423             memset(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T));
00424             m_size = newSize;
00425         }
00426     }
00427 
00428     //! change size and preserve contents
00429     void resize(size_type newSize)
00430     {
00431         m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
00432         m_size = newSize;
00433     }
00434 
00435     //! swap contents and size with another SecBlock
00436     void swap(SecBlock<T, A> &b)
00437     {
00438         std::swap(m_alloc, b.m_alloc);
00439         std::swap(m_size, b.m_size);
00440         std::swap(m_ptr, b.m_ptr);
00441     }
00442 
00443 //private:
00444     A m_alloc;
00445     size_type m_size;
00446     T *m_ptr;
00447 };
00448 
00449 typedef SecBlock<byte> SecByteBlock;
00450 typedef SecBlock<byte, AllocatorWithCleanup<byte, true> > AlignedSecByteBlock;
00451 typedef SecBlock<word> SecWordBlock;
00452 
00453 //! a SecBlock with fixed size, allocated statically
00454 template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S> >
00455 class FixedSizeSecBlock : public SecBlock<T, A>
00456 {
00457 public:
00458     explicit FixedSizeSecBlock() : SecBlock<T, A>(S) {}
00459 };
00460 
00461 template <class T, unsigned int S, bool T_Align16 = true>
00462 class FixedSizeAlignedSecBlock : public FixedSizeSecBlock<T, S, FixedSizeAllocatorWithCleanup<T, S, NullAllocator<T>, T_Align16> >
00463 {
00464 };
00465 
00466 //! a SecBlock that preallocates size S statically, and uses the heap when this size is exceeded
00467 template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S, AllocatorWithCleanup<T> > >
00468 class SecBlockWithHint : public SecBlock<T, A>
00469 {
00470 public:
00471     explicit SecBlockWithHint(size_t size) : SecBlock<T, A>(size) {}
00472 };
00473 
00474 template<class T, bool A, class U, bool B>
00475 inline bool operator==(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (true);}
00476 template<class T, bool A, class U, bool B>
00477 inline bool operator!=(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (false);}
00478 
00479 NAMESPACE_END
00480 
00481 NAMESPACE_BEGIN(std)
00482 template <class T, class A>
00483 inline void swap(CryptoPP::SecBlock<T, A> &a, CryptoPP::SecBlock<T, A> &b)
00484 {
00485     a.swap(b);
00486 }
00487 
00488 #if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES))
00489 // working for STLport 5.1.3 and MSVC 6 SP5
00490 template <class _Tp1, class _Tp2>
00491 inline CryptoPP::AllocatorWithCleanup<_Tp2>&
00492 __stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*)
00493 {
00494     return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a);
00495 }
00496 #endif
00497 
00498 NAMESPACE_END
00499 
00500 #endif

Generated on Sun Jul 25 2010 14:44:11 for Crypto++ by  doxygen 1.7.1