Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r80515 - in trunk/boost/interprocess: . allocators allocators/detail detail ipc mem_algo/detail
From: igaztanaga_at_[hidden]
Date: 2012-09-13 14:56:10


Author: igaztanaga
Date: 2012-09-13 14:56:08 EDT (Thu, 13 Sep 2012)
New Revision: 80515
URL: http://svn.boost.org/trac/boost/changeset/80515

Log:
Added overflow checks
Text files modified:
   trunk/boost/interprocess/allocators/allocator.hpp | 8 +
   trunk/boost/interprocess/allocators/detail/allocator_common.hpp | 27 +++--
   trunk/boost/interprocess/detail/utilities.hpp | 37 ++++++++
   trunk/boost/interprocess/ipc/message_queue.hpp | 6
   trunk/boost/interprocess/mem_algo/detail/mem_algo_common.hpp | 177 ++++++++++++++++++++-------------------
   trunk/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp | 4
   trunk/boost/interprocess/offset_ptr.hpp | 2
   7 files changed, 154 insertions(+), 107 deletions(-)

Modified: trunk/boost/interprocess/allocators/allocator.hpp
==============================================================================
--- trunk/boost/interprocess/allocators/allocator.hpp (original)
+++ trunk/boost/interprocess/allocators/allocator.hpp 2012-09-13 14:56:08 EDT (Thu, 13 Sep 2012)
@@ -145,8 +145,9 @@
    pointer allocate(size_type count, cvoid_ptr hint = 0)
    {
       (void)hint;
- if(count > this->max_size())
+ if(size_overflows<sizeof(T)>(count)){
          throw bad_alloc();
+ }
       return pointer(static_cast<value_type*>(mp_mngr->allocate(count*sizeof(T))));
    }
 
@@ -192,7 +193,10 @@
    multiallocation_chain allocate_many
       (size_type elem_size, size_type num_elements)
    {
- return multiallocation_chain(mp_mngr->allocate_many(sizeof(T)*elem_size, num_elements));
+ if(size_overflows<sizeof(T)>(elem_size)){
+ throw bad_alloc();
+ }
+ return multiallocation_chain(mp_mngr->allocate_many(elem_size*sizeof(T), num_elements));
    }
 
    //!Allocates n_elements elements, each one of size elem_sizes[i]in a

Modified: trunk/boost/interprocess/allocators/detail/allocator_common.hpp
==============================================================================
--- trunk/boost/interprocess/allocators/detail/allocator_common.hpp (original)
+++ trunk/boost/interprocess/allocators/detail/allocator_common.hpp 2012-09-13 14:56:08 EDT (Thu, 13 Sep 2012)
@@ -191,8 +191,7 @@
       if(m_cached_nodes.empty()){
          m_cached_nodes = mp_node_pool->allocate_nodes(m_max_cached_nodes/2);
       }
- void *ret = ipcdetail::to_raw_pointer(m_cached_nodes.front());
- m_cached_nodes.pop_front();
+ void *ret = ipcdetail::to_raw_pointer(m_cached_nodes.pop_front());
       return ret;
    }
 
@@ -203,8 +202,7 @@
       BOOST_TRY{
          //If don't have any cached node, we have to get a new list of free nodes from the pool
          while(!m_cached_nodes.empty() && count--){
- void *ret = ipcdetail::to_raw_pointer(m_cached_nodes.front());
- m_cached_nodes.pop_front();
+ void *ret = ipcdetail::to_raw_pointer(m_cached_nodes.pop_front());
             chain.push_back(ret);
             ++allocated;
          }
@@ -357,7 +355,10 @@
    //!with deallocate(...)
    multiallocation_chain allocate_many(size_type elem_size, size_type num_elements)
    {
- return this->derived()->get_segment_manager()->allocate_many(sizeof(T)*elem_size, num_elements);
+ if(size_overflows<sizeof(T)>(elem_size)){
+ throw bad_alloc();
+ }
+ return this->derived()->get_segment_manager()->allocate_many(elem_size*sizeof(T), num_elements);
    }
 
    //!Allocates n_elements elements, each one of size elem_sizes[i]in a
@@ -457,14 +458,17 @@
       (void)hint;
       typedef typename node_pool<0>::type node_pool_t;
       node_pool_t *pool = node_pool<0>::get(this->derived()->get_node_pool());
- if(count > this->max_size())
+ if(size_overflows<sizeof(T)>(count)){
          throw bad_alloc();
- else if(Version == 1 && count == 1)
+ }
+ else if(Version == 1 && count == 1){
          return pointer(static_cast<value_type*>
          (pool->allocate_node()));
- else
+ }
+ else{
          return pointer(static_cast<value_type*>
- (pool->get_segment_manager()->allocate(sizeof(T)*count)));
+ (pool->get_segment_manager()->allocate(count*sizeof(T))));
+ }
    }
 
    //!Deallocate allocated memory. Never throws
@@ -605,13 +609,14 @@
    {
       (void)hint;
       void * ret;
- if(count > this->max_size())
+ if(size_overflows<sizeof(T)>(count)){
          throw bad_alloc();
+ }
       else if(Version == 1 && count == 1){
          ret = m_cache.cached_allocation();
       }
       else{
- ret = this->get_segment_manager()->allocate(sizeof(T)*count);
+ ret = this->get_segment_manager()->allocate(count*sizeof(T));
       }
       return pointer(static_cast<T*>(ret));
    }

Modified: trunk/boost/interprocess/detail/utilities.hpp
==============================================================================
--- trunk/boost/interprocess/detail/utilities.hpp (original)
+++ trunk/boost/interprocess/detail/utilities.hpp 2012-09-13 14:56:08 EDT (Thu, 13 Sep 2012)
@@ -31,8 +31,10 @@
 #include <boost/interprocess/containers/version_type.hpp>
 #include <boost/intrusive/pointer_traits.hpp>
 #include <boost/move/move.hpp>
+#include <boost/static_assert.hpp>
 #include <utility>
 #include <algorithm>
+#include <climits>
 
 namespace boost {
 namespace interprocess {
@@ -86,7 +88,10 @@
 template <std::size_t OrigSize, std::size_t RoundTo>
 struct ct_rounded_size
 {
- static const std::size_t value = ((OrigSize-1)/RoundTo+1)*RoundTo;
+ BOOST_STATIC_ASSERT((RoundTo != 0));
+ static const std::size_t intermediate_value = (OrigSize-1)/RoundTo+1;
+ BOOST_STATIC_ASSERT(intermediate_value <= std::size_t(-1)/RoundTo);
+ static const std::size_t value = intermediate_value*RoundTo;
 };
 
 // Gennaro Prota wrote this. Thanks!
@@ -133,6 +138,36 @@
        &const_cast<char&>(reinterpret_cast<const volatile char &>(v)));
 }
 
+template<class SizeType>
+struct sqrt_size_type_max
+{
+ static const SizeType value = (SizeType(1) << (sizeof(SizeType)*(CHAR_BIT/2)))-1;
+};
+
+template<class SizeType>
+inline bool multiplication_overflows(SizeType a, SizeType b)
+{
+ const SizeType sqrt_size_max = sqrt_size_type_max<SizeType>::value;
+ return //Fast runtime check
+ ( (a | b) > sqrt_size_max &&
+ //Slow division check
+ b && a > SizeType(-1)/b
+ );
+}
+
+template<std::size_t SztSizeOfType, class SizeType>
+inline bool size_overflows(SizeType count)
+{
+ //Compile time-check
+ BOOST_STATIC_ASSERT(SztSizeOfType <= SizeType(-1));
+ //Runtime check
+ return multiplication_overflows(SizeType(SztSizeOfType), count);
+}
+
+template<class SizeType>
+inline bool sum_overflows(SizeType a, SizeType b)
+{ return SizeType(-1) - a > b; }
+
 //Anti-exception node eraser
 template<class Cont>
 class value_eraser

Modified: trunk/boost/interprocess/ipc/message_queue.hpp
==============================================================================
--- trunk/boost/interprocess/ipc/message_queue.hpp (original)
+++ trunk/boost/interprocess/ipc/message_queue.hpp 2012-09-13 14:56:08 EDT (Thu, 13 Sep 2012)
@@ -512,7 +512,7 @@
                  msg_hdr_align = ::boost::alignment_of<msg_header>::value,
                  index_align = ::boost::alignment_of<msg_hdr_ptr_t>::value,
          r_hdr_size = ipcdetail::ct_rounded_size<sizeof(mq_hdr_t), index_align>::value,
- r_index_size = ipcdetail::get_rounded_size(sizeof(msg_hdr_ptr_t)*max_num_msg, msg_hdr_align),
+ r_index_size = ipcdetail::get_rounded_size(max_num_msg*sizeof(msg_hdr_ptr_t), msg_hdr_align),
          r_max_msg_size = ipcdetail::get_rounded_size(max_msg_size, msg_hdr_align) + sizeof(msg_header);
       return r_hdr_size + r_index_size + (max_num_msg*r_max_msg_size) +
          ipcdetail::managed_open_or_create_impl<shared_memory_object>::ManagedOpenOrCreateUserOffset;
@@ -526,7 +526,7 @@
                   msg_hdr_align = ::boost::alignment_of<msg_header>::value,
                   index_align = ::boost::alignment_of<msg_hdr_ptr_t>::value,
          r_hdr_size = ipcdetail::ct_rounded_size<sizeof(mq_hdr_t), index_align>::value,
- r_index_size = ipcdetail::get_rounded_size(sizeof(msg_hdr_ptr_t)*m_max_num_msg, msg_hdr_align),
+ r_index_size = ipcdetail::get_rounded_size(m_max_num_msg*sizeof(msg_hdr_ptr_t), msg_hdr_align),
          r_max_msg_size = ipcdetail::get_rounded_size(m_max_msg_size, msg_hdr_align) + sizeof(msg_header);
 
       //Pointer to the index
@@ -627,7 +627,7 @@
       //Create shared memory and execute functor atomically
    : m_shmem(create_only,
               name,
- get_mem_size(max_msg_size, max_num_msg),
+ get_mem_size(max_msg_size, max_num_msg),
               read_write,
               static_cast<void*>(0),
               //Prepare initialization functor

Modified: trunk/boost/interprocess/mem_algo/detail/mem_algo_common.hpp
==============================================================================
--- trunk/boost/interprocess/mem_algo/detail/mem_algo_common.hpp (original)
+++ trunk/boost/interprocess/mem_algo/detail/mem_algo_common.hpp 2012-09-13 14:56:08 EDT (Thu, 13 Sep 2012)
@@ -436,101 +436,108 @@
       }
       else{
          for(size_type i = 0; i < n_elements; ++i){
+ if(multiplication_overflows(elem_sizes[i], sizeof_element)){
+ total_request_units = 0;
+ break;
+ }
             elem_units = memory_algo->priv_get_total_units(elem_sizes[i]*sizeof_element);
             elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
+ if(sum_overflows(total_request_units, elem_units)){
+ total_request_units = 0;
+ break;
+ }
             total_request_units += elem_units;
          }
       }
 
       multiallocation_chain chain;
-
- size_type low_idx = 0;
- while(low_idx < n_elements){
- size_type total_bytes = total_request_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
- size_type min_allocation = (!sizeof_element)
- ? elem_units
- : memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
- min_allocation = min_allocation*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
-
- size_type received_size;
- std::pair<void *, bool> ret = memory_algo->priv_allocate
- (boost::interprocess::allocate_new, min_allocation, total_bytes, received_size, 0);
- if(!ret.first){
- break;
- }
-
- block_ctrl *block = memory_algo->priv_get_block(ret.first);
- size_type received_units = (size_type)block->m_size;
- char *block_address = reinterpret_cast<char*>(block);
-
- size_type total_used_units = 0;
-// block_ctrl *prev_block = 0;
- while(total_used_units < received_units){
- if(sizeof_element){
- elem_units = memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
- elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
- }
- if(total_used_units + elem_units > received_units)
+ if(total_request_units && !multiplication_overflows(total_request_units, Alignment)){
+ size_type low_idx = 0;
+ while(low_idx < n_elements){
+ size_type total_bytes = total_request_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
+ size_type min_allocation = (!sizeof_element)
+ ? elem_units
+ : memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
+ min_allocation = min_allocation*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
+
+ size_type received_size;
+ std::pair<void *, bool> ret = memory_algo->priv_allocate
+ (boost::interprocess::allocate_new, min_allocation, total_bytes, received_size, 0);
+ if(!ret.first){
                break;
- total_request_units -= elem_units;
- //This is the position where the new block must be created
- block_ctrl *new_block = reinterpret_cast<block_ctrl *>(block_address);
- assert_alignment(new_block);
-
- //The last block should take all the remaining space
- if((low_idx + 1) == n_elements ||
- (total_used_units + elem_units +
- ((!sizeof_element)
- ? elem_units
- : std::max(memory_algo->priv_get_total_units(elem_sizes[low_idx+1]*sizeof_element), ptr_size_units))
- ) > received_units){
- //By default, the new block will use the rest of the buffer
- new_block->m_size = received_units - total_used_units;
- memory_algo->priv_mark_new_allocated_block(new_block);
-
- //If the remaining units are bigger than needed and we can
- //split it obtaining a new free memory block do it.
- if((received_units - total_used_units) >= (elem_units + MemoryAlgorithm::BlockCtrlUnits)){
- size_type shrunk_received;
- size_type shrunk_request = elem_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
- bool shrink_ok = shrink
- (memory_algo
- ,memory_algo->priv_get_user_buffer(new_block)
- ,shrunk_request
- ,shrunk_request
- ,shrunk_received);
- (void)shrink_ok;
- //Shrink must always succeed with passed parameters
- BOOST_ASSERT(shrink_ok);
- //Some sanity checks
- BOOST_ASSERT(shrunk_request == shrunk_received);
- BOOST_ASSERT(elem_units == ((shrunk_request-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits));
- //"new_block->m_size" must have been reduced to elem_units by "shrink"
- BOOST_ASSERT(new_block->m_size == elem_units);
- //Now update the total received units with the reduction
- received_units = elem_units + total_used_units;
- }
- }
- else{
- new_block->m_size = elem_units;
- memory_algo->priv_mark_new_allocated_block(new_block);
             }
 
- block_address += new_block->m_size*Alignment;
- total_used_units += (size_type)new_block->m_size;
- //Check we have enough room to overwrite the intrusive pointer
- BOOST_ASSERT((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(void_pointer));
- void_pointer p = new(memory_algo->priv_get_user_buffer(new_block))void_pointer(0);
- chain.push_back(p);
- ++low_idx;
- //prev_block = new_block;
+ block_ctrl *block = memory_algo->priv_get_block(ret.first);
+ size_type received_units = (size_type)block->m_size;
+ char *block_address = reinterpret_cast<char*>(block);
+
+ size_type total_used_units = 0;
+ while(total_used_units < received_units){
+ if(sizeof_element){
+ elem_units = memory_algo->priv_get_total_units(elem_sizes[low_idx]*sizeof_element);
+ elem_units = ptr_size_units > elem_units ? ptr_size_units : elem_units;
+ }
+ if(total_used_units + elem_units > received_units)
+ break;
+ total_request_units -= elem_units;
+ //This is the position where the new block must be created
+ block_ctrl *new_block = reinterpret_cast<block_ctrl *>(block_address);
+ assert_alignment(new_block);
+
+ //The last block should take all the remaining space
+ if((low_idx + 1) == n_elements ||
+ (total_used_units + elem_units +
+ ((!sizeof_element)
+ ? elem_units
+ : std::max(memory_algo->priv_get_total_units(elem_sizes[low_idx+1]*sizeof_element), ptr_size_units))
+ ) > received_units){
+ //By default, the new block will use the rest of the buffer
+ new_block->m_size = received_units - total_used_units;
+ memory_algo->priv_mark_new_allocated_block(new_block);
+
+ //If the remaining units are bigger than needed and we can
+ //split it obtaining a new free memory block do it.
+ if((received_units - total_used_units) >= (elem_units + MemoryAlgorithm::BlockCtrlUnits)){
+ size_type shrunk_received;
+ size_type shrunk_request = elem_units*Alignment - AllocatedCtrlBytes + UsableByPreviousChunk;
+ bool shrink_ok = shrink
+ (memory_algo
+ ,memory_algo->priv_get_user_buffer(new_block)
+ ,shrunk_request
+ ,shrunk_request
+ ,shrunk_received);
+ (void)shrink_ok;
+ //Shrink must always succeed with passed parameters
+ BOOST_ASSERT(shrink_ok);
+ //Some sanity checks
+ BOOST_ASSERT(shrunk_request == shrunk_received);
+ BOOST_ASSERT(elem_units == ((shrunk_request-UsableByPreviousChunk)/Alignment + AllocatedCtrlUnits));
+ //"new_block->m_size" must have been reduced to elem_units by "shrink"
+ BOOST_ASSERT(new_block->m_size == elem_units);
+ //Now update the total received units with the reduction
+ received_units = elem_units + total_used_units;
+ }
+ }
+ else{
+ new_block->m_size = elem_units;
+ memory_algo->priv_mark_new_allocated_block(new_block);
+ }
+
+ block_address += new_block->m_size*Alignment;
+ total_used_units += (size_type)new_block->m_size;
+ //Check we have enough room to overwrite the intrusive pointer
+ BOOST_ASSERT((new_block->m_size*Alignment - AllocatedCtrlUnits) >= sizeof(void_pointer));
+ void_pointer p = new(memory_algo->priv_get_user_buffer(new_block))void_pointer(0);
+ chain.push_back(p);
+ ++low_idx;
+ }
+ //Sanity check
+ BOOST_ASSERT(total_used_units == received_units);
          }
- //Sanity check
- BOOST_ASSERT(total_used_units == received_units);
- }
 
- if(low_idx != n_elements){
- priv_deallocate_many(memory_algo, boost::move(chain));
+ if(low_idx != n_elements){
+ priv_deallocate_many(memory_algo, boost::move(chain));
+ }
       }
       return boost::move(chain);
    }
@@ -538,9 +545,7 @@
    static void priv_deallocate_many(MemoryAlgorithm *memory_algo, multiallocation_chain chain)
    {
       while(!chain.empty()){
- void *addr = to_raw_pointer(chain.front());
- chain.pop_front();
- memory_algo->priv_deallocate(addr);
+ memory_algo->priv_deallocate(to_raw_pointer(chain.pop_front()));
       }
    }
 };

Modified: trunk/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp
==============================================================================
--- trunk/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp (original)
+++ trunk/boost/interprocess/mem_algo/detail/simple_seq_fit_impl.hpp 2012-09-13 14:56:08 EDT (Thu, 13 Sep 2012)
@@ -750,9 +750,7 @@
    boost::interprocess::scoped_lock<interprocess_mutex> guard(m_header);
    //-----------------------
    while(!chain.empty()){
- void *addr = chain.front();
- chain.pop_front();
- this->priv_deallocate(addr);
+ this->priv_deallocate(to_raw_pointer(chain.pop_front()));
    }
 }
 

Modified: trunk/boost/interprocess/offset_ptr.hpp
==============================================================================
--- trunk/boost/interprocess/offset_ptr.hpp (original)
+++ trunk/boost/interprocess/offset_ptr.hpp 2012-09-13 14:56:08 EDT (Thu, 13 Sep 2012)
@@ -444,7 +444,7 @@
 //!Never throws.
 template <class T, class P, class O, std::size_t A>
 inline T * to_raw_pointer(boost::interprocess::offset_ptr<T, P, O, A> const & p)
-{ return p.get(); }
+{ return ipcdetail::to_raw_pointer(p); }
 //#if !defined(_MSC_VER) || (_MSC_VER >= 1400)
 } //namespace interprocess
 //#endif


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk