1 // secblock.h - written and placed in the public domain by Wei Dai
3 #ifndef CRYPTOPP_SECBLOCK_H
4 #define CRYPTOPP_SECBLOCK_H
10 #if defined(CRYPTOPP_MEMALIGN_AVAILABLE) || defined(CRYPTOPP_MM_MALLOC_AVAILABLE) || defined(QNX)
16 NAMESPACE_BEGIN(CryptoPP)
18 // ************** secure memory allocation ***************
25 typedef size_t size_type;
26 #ifdef CRYPTOPP_MSVCRT6
27 typedef ptrdiff_t difference_type;
29 typedef std::ptrdiff_t difference_type;
32 typedef const T * const_pointer;
33 typedef T & reference;
34 typedef const T & const_reference;
36 pointer address(reference r) const {return (&r);}
37 const_pointer address(const_reference r) const {return (&r); }
38 void construct(pointer p, const T& val) {new (p) T(val);}
39 void destroy(pointer p) {p->~T();}
40 size_type max_size() const {return ~size_type(0)/sizeof(T);} // switch to std::numeric_limits<T>::max later
43 static void CheckSize(size_t n)
45 if (n > ~size_t(0) / sizeof(T))
46 throw InvalidArgument("AllocatorBase: requested size would cause integer overflow");
50 #define CRYPTOPP_INHERIT_ALLOCATOR_TYPES \
51 typedef typename AllocatorBase<T>::value_type value_type;\
52 typedef typename AllocatorBase<T>::size_type size_type;\
53 typedef typename AllocatorBase<T>::difference_type difference_type;\
54 typedef typename AllocatorBase<T>::pointer pointer;\
55 typedef typename AllocatorBase<T>::const_pointer const_pointer;\
56 typedef typename AllocatorBase<T>::reference reference;\
57 typedef typename AllocatorBase<T>::const_reference const_reference;
59 #if defined(_MSC_VER) && (_MSC_VER < 1300)
60 // this pragma causes an internal compiler error if placed immediately before std::swap(a, b)
62 #pragma warning(disable: 4700) // VC60 workaround: don't know how to get rid of this warning
65 template <class T, class A>
66 typename A::pointer StandardReallocate(A& a, T *p, typename A::size_type oldSize, typename A::size_type newSize, bool preserve)
68 if (oldSize == newSize)
73 typename A::pointer newPointer = a.allocate(newSize, NULL);
74 memcpy_s(newPointer, sizeof(T)*newSize, p, sizeof(T)*STDMIN(oldSize, newSize));
75 a.deallocate(p, oldSize);
80 a.deallocate(p, oldSize);
81 return a.allocate(newSize, NULL);
85 #if defined(_MSC_VER) && (_MSC_VER < 1300)
89 template <class T, bool T_Align16 = false>
90 class AllocatorWithCleanup : public AllocatorBase<T>
93 CRYPTOPP_INHERIT_ALLOCATOR_TYPES
95 pointer allocate(size_type n, const void * = NULL)
101 if (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16 && n*sizeof(T) >= 16)
104 #ifdef CRYPTOPP_MM_MALLOC_AVAILABLE
105 while (!(p = (byte *)_mm_malloc(sizeof(T)*n, 16)))
106 #elif defined(CRYPTOPP_MEMALIGN_AVAILABLE)
107 while (!(p = (byte *)memalign(16, sizeof(T)*n)))
108 #elif defined(CRYPTOPP_MALLOC_ALIGNMENT_IS_16)
109 while (!(p = (byte *)malloc(sizeof(T)*n)))
111 while (!(p = (byte *)malloc(sizeof(T)*n + 16)))
115 #ifdef CRYPTOPP_NO_ALIGNED_ALLOC
116 size_t adjustment = 16-((size_t)p%16);
118 p[-1] = (byte)adjustment;
121 assert(IsAlignedOn(p, 16));
126 while (!(p = (pointer)malloc(sizeof(T)*n)))
131 void deallocate(void *p, size_type n)
133 memset_z(p, 0, n*sizeof(T));
135 if (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16 && n*sizeof(T) >= 16)
137 #ifdef CRYPTOPP_MM_MALLOC_AVAILABLE
139 #elif defined(CRYPTOPP_NO_ALIGNED_ALLOC)
140 p = (byte *)p - ((byte *)p)[-1];
151 pointer reallocate(T *p, size_type oldSize, size_type newSize, bool preserve)
153 return StandardReallocate(*this, p, oldSize, newSize, preserve);
156 // VS.NET STL enforces the policy of "All STL-compliant allocators have to provide a
157 // template class member called rebind".
158 template <class U> struct rebind { typedef AllocatorWithCleanup<U, T_Align16> other; };
160 AllocatorWithCleanup() {}
161 template <class U, bool A> AllocatorWithCleanup(const AllocatorWithCleanup<U, A> &) {}
165 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<byte>;
166 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word16>;
167 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word32>;
168 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word64>;
169 #if CRYPTOPP_BOOL_X86
170 CRYPTOPP_DLL_TEMPLATE_CLASS AllocatorWithCleanup<word, true>; // for Integer
174 class NullAllocator : public AllocatorBase<T>
177 CRYPTOPP_INHERIT_ALLOCATOR_TYPES
179 pointer allocate(size_type n, const void * = NULL)
185 void deallocate(void *p, size_type n)
187 //// Bitcoin: don't know why this trips, probably a false alarm, depends on the compiler used.
191 size_type max_size() const {return 0;}
194 // This allocator can't be used with standard collections because
195 // they require that all objects of the same allocator type are equivalent.
196 // So this is for use with SecBlock only.
197 template <class T, size_t S, class A = NullAllocator<T>, bool T_Align16 = false>
198 class FixedSizeAllocatorWithCleanup : public AllocatorBase<T>
201 CRYPTOPP_INHERIT_ALLOCATOR_TYPES
203 FixedSizeAllocatorWithCleanup() : m_allocated(false) {}
205 pointer allocate(size_type n)
207 assert(IsAlignedOn(m_array, 8));
209 if (n <= S && !m_allocated)
212 return GetAlignedArray();
215 return m_fallbackAllocator.allocate(n);
218 pointer allocate(size_type n, const void *hint)
220 if (n <= S && !m_allocated)
223 return GetAlignedArray();
226 return m_fallbackAllocator.allocate(n, hint);
229 void deallocate(void *p, size_type n)
231 if (p == GetAlignedArray())
236 memset(p, 0, n*sizeof(T));
239 m_fallbackAllocator.deallocate(p, n);
242 pointer reallocate(pointer p, size_type oldSize, size_type newSize, bool preserve)
244 if (p == GetAlignedArray() && newSize <= S)
246 assert(oldSize <= S);
247 if (oldSize > newSize)
248 memset(p + newSize, 0, (oldSize-newSize)*sizeof(T));
252 pointer newPointer = allocate(newSize, NULL);
254 memcpy(newPointer, p, sizeof(T)*STDMIN(oldSize, newSize));
255 deallocate(p, oldSize);
259 size_type max_size() const {return STDMAX(m_fallbackAllocator.max_size(), S);}
263 T* GetAlignedArray() {return m_array;}
266 T* GetAlignedArray() {return (CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? (T*)(((byte *)m_array) + (0-(size_t)m_array)%16) : m_array;}
267 CRYPTOPP_ALIGN_DATA(8) T m_array[(CRYPTOPP_BOOL_ALIGN16_ENABLED && T_Align16) ? S+8/sizeof(T) : S];
269 A m_fallbackAllocator;
273 //! a block of memory allocated using A
274 template <class T, class A = AllocatorWithCleanup<T> >
278 typedef typename A::value_type value_type;
279 typedef typename A::pointer iterator;
280 typedef typename A::const_pointer const_iterator;
281 typedef typename A::size_type size_type;
283 explicit SecBlock(size_type size=0)
284 : m_size(size) {m_ptr = m_alloc.allocate(size, NULL);}
285 SecBlock(const SecBlock<T, A> &t)
286 : 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));}
287 SecBlock(const T *t, size_type len)
290 m_ptr = m_alloc.allocate(len, NULL);
292 memset_z(m_ptr, 0, len*sizeof(T));
294 memcpy(m_ptr, t, len*sizeof(T));
298 {m_alloc.deallocate(m_ptr, m_size);}
304 operator const void *() const
309 operator const T *() const
315 // T *operator +(size_type offset)
316 // {return m_ptr+offset;}
318 // const T *operator +(size_type offset) const
319 // {return m_ptr+offset;}
321 // T& operator[](size_type index)
322 // {assert(index >= 0 && index < m_size); return m_ptr[index];}
324 // const T& operator[](size_type index) const
325 // {assert(index >= 0 && index < m_size); return m_ptr[index];}
329 const_iterator begin() const
332 {return m_ptr+m_size;}
333 const_iterator end() const
334 {return m_ptr+m_size;}
336 typename A::pointer data() {return m_ptr;}
337 typename A::const_pointer data() const {return m_ptr;}
339 size_type size() const {return m_size;}
340 bool empty() const {return m_size == 0;}
342 byte * BytePtr() {return (byte *)m_ptr;}
343 const byte * BytePtr() const {return (const byte *)m_ptr;}
344 size_type SizeInBytes() const {return m_size*sizeof(T);}
346 //! set contents and size
347 void Assign(const T *t, size_type len)
350 memcpy_s(m_ptr, m_size*sizeof(T), t, len*sizeof(T));
353 //! copy contents and size from another SecBlock
354 void Assign(const SecBlock<T, A> &t)
357 memcpy_s(m_ptr, m_size*sizeof(T), t.m_ptr, m_size*sizeof(T));
360 SecBlock<T, A>& operator=(const SecBlock<T, A> &t)
366 // append to this object
367 SecBlock<T, A>& operator+=(const SecBlock<T, A> &t)
369 size_type oldSize = m_size;
370 Grow(m_size+t.m_size);
371 memcpy_s(m_ptr+oldSize, m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
376 SecBlock<T, A> operator+(const SecBlock<T, A> &t)
378 SecBlock<T, A> result(m_size+t.m_size);
379 memcpy_s(result.m_ptr, result.m_size*sizeof(T), m_ptr, m_size*sizeof(T));
380 memcpy_s(result.m_ptr+m_size, t.m_size*sizeof(T), t.m_ptr, t.m_size*sizeof(T));
384 bool operator==(const SecBlock<T, A> &t) const
386 return m_size == t.m_size && VerifyBufsEqual(m_ptr, t.m_ptr, m_size*sizeof(T));
389 bool operator!=(const SecBlock<T, A> &t) const
391 return !operator==(t);
394 //! change size, without preserving contents
395 void New(size_type newSize)
397 m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, false);
401 //! change size and set contents to 0
402 void CleanNew(size_type newSize)
405 memset_z(m_ptr, 0, m_size*sizeof(T));
408 //! change size only if newSize > current size. contents are preserved
409 void Grow(size_type newSize)
411 if (newSize > m_size)
413 m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
418 //! change size only if newSize > current size. contents are preserved and additional area is set to 0
419 void CleanGrow(size_type newSize)
421 if (newSize > m_size)
423 m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
424 memset(m_ptr+m_size, 0, (newSize-m_size)*sizeof(T));
429 //! change size and preserve contents
430 void resize(size_type newSize)
432 m_ptr = m_alloc.reallocate(m_ptr, m_size, newSize, true);
436 //! swap contents and size with another SecBlock
437 void swap(SecBlock<T, A> &b)
439 std::swap(m_alloc, b.m_alloc);
440 std::swap(m_size, b.m_size);
441 std::swap(m_ptr, b.m_ptr);
450 typedef SecBlock<byte> SecByteBlock;
451 typedef SecBlock<byte, AllocatorWithCleanup<byte, true> > AlignedSecByteBlock;
452 typedef SecBlock<word> SecWordBlock;
454 //! a SecBlock with fixed size, allocated statically
455 template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S> >
456 class FixedSizeSecBlock : public SecBlock<T, A>
459 explicit FixedSizeSecBlock() : SecBlock<T, A>(S) {}
462 template <class T, unsigned int S, bool T_Align16 = true>
463 class FixedSizeAlignedSecBlock : public FixedSizeSecBlock<T, S, FixedSizeAllocatorWithCleanup<T, S, NullAllocator<T>, T_Align16> >
467 //! a SecBlock that preallocates size S statically, and uses the heap when this size is exceeded
468 template <class T, unsigned int S, class A = FixedSizeAllocatorWithCleanup<T, S, AllocatorWithCleanup<T> > >
469 class SecBlockWithHint : public SecBlock<T, A>
472 explicit SecBlockWithHint(size_t size) : SecBlock<T, A>(size) {}
475 template<class T, bool A, class U, bool B>
476 inline bool operator==(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (true);}
477 template<class T, bool A, class U, bool B>
478 inline bool operator!=(const CryptoPP::AllocatorWithCleanup<T, A>&, const CryptoPP::AllocatorWithCleanup<U, B>&) {return (false);}
483 template <class T, class A>
484 inline void swap(CryptoPP::SecBlock<T, A> &a, CryptoPP::SecBlock<T, A> &b)
489 #if defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) || (defined(_STLPORT_VERSION) && !defined(_STLP_MEMBER_TEMPLATE_CLASSES))
490 // working for STLport 5.1.3 and MSVC 6 SP5
491 template <class _Tp1, class _Tp2>
492 inline CryptoPP::AllocatorWithCleanup<_Tp2>&
493 __stl_alloc_rebind(CryptoPP::AllocatorWithCleanup<_Tp1>& __a, const _Tp2*)
495 return (CryptoPP::AllocatorWithCleanup<_Tp2>&)(__a);