From 3b61581bcdfa046a5b15de356a9f8ad8b748ff9c Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Sat, 24 Mar 2012 22:46:51 -0400 Subject: [PATCH] Make aligned allocation without posix_memalign more robust Instead of guessing the right function to use, we malloc() 15 bytes more than we need, and compute the aligned offset within. The AlignedBuffer class takes care of passing the original pointer to free(). --- configure.ac | 1 + src/crypto/crypto.cc | 46 +++++++++++++++++++++++--------------------- src/crypto/crypto.h | 3 ++- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/configure.ac b/configure.ac index 1c58470..f2f7e92 100644 --- a/configure.ac +++ b/configure.ac @@ -118,6 +118,7 @@ AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_UINT8_T +AC_TYPE_UINTPTR_T # Checks for library functions. AC_FUNC_FORK diff --git a/src/crypto/crypto.cc b/src/crypto/crypto.cc index 8179b1b..31104b6 100644 --- a/src/crypto/crypto.cc +++ b/src/crypto/crypto.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "byteorder.h" @@ -47,33 +48,34 @@ long int myatoi( const char *str ) } AlignedBuffer::AlignedBuffer( size_t len, const char *data ) - : m_len( len ), m_data( NULL ) + : m_len( len ), m_allocated( NULL ), m_data( NULL ) { - void *ptr = NULL; - #if defined(HAVE_POSIX_MEMALIGN) - if( (0 != posix_memalign( (void **)&ptr, 16, len )) || (ptr == NULL) ) { + if ( ( 0 != posix_memalign( &m_allocated, 16, len ) ) + || ( m_allocated == NULL ) ) { throw std::bad_alloc(); } -#else - // Some platforms will align malloc. Let's try that first. - if( ! (ptr = malloc(len)) ) { - throw std::bad_alloc(); - } - if( (uintptr_t)ptr & 0xF ) { - // The pointer wasn't 16-byte aligned, so try again with valloc - free(ptr); - if( ! (ptr = valloc(len)) ) { - throw std::bad_alloc(); - } - if( (uintptr_t)ptr & 0xF ) { - free(ptr); - throw std::bad_alloc(); - } - } -#endif /* !defined(HAVE_POSIX_MEMALIGN) */ + m_data = (char *) m_allocated; - m_data = (char *) ptr; +#else + /* malloc() a region 15 bytes larger than we need, and find + the aligned offset within. */ + m_allocated = malloc( 15 + len ); + if ( m_allocated == NULL ) { + throw std::bad_alloc(); + } + + uintptr_t iptr = (uintptr_t) m_allocated; + if ( iptr & 0xF ) { + iptr += 16 - ( iptr & 0xF ); + } + assert( !( iptr & 0xF ) ); + assert( iptr >= (uintptr_t) m_allocated ); + assert( iptr <= ( 15 + (uintptr_t) m_allocated ) ); + + m_data = (char *) iptr; + +#endif /* !defined(HAVE_POSIX_MEMALIGN) */ if ( data ) { memcpy( m_data, data, len ); diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index ddbf12f..eab73be 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -42,13 +42,14 @@ namespace Crypto { class AlignedBuffer { private: size_t m_len; + void *m_allocated; char *m_data; public: AlignedBuffer( size_t len, const char *data = NULL ); ~AlignedBuffer() { - free( m_data ); + free( m_allocated ); } char * data( void ) const { return m_data; }