2015-03-16 1 views
-1

Je suis parfois obtenir un std :: bad_alloc pour le code suivant:std :: bad_alloc lors de l'insertion dans std :: unordered_map?

typedef std::unordered_map<chash, block_extended_info> map_type; 
map_type m_foo; 

// the transgressor: 
auto r = m_foo.insert(map_type::value_type(id, bei)); 

Il arrive de temps en temps lors de l'exécution des cas de test qui utilisent la méthode contenant cette ligne, et d'autres fois non. J'avais changé le code pour utiliser m_foo[id] = bei, ce qui l'a fait arrêter de se produire pour une compilation, mais quand j'ai recompilé à nouveau, il a échoué, donc je l'ai changé à ce qui précède, qui a continué à échouer. De toute évidence, la question est plus profonde que cela.

Je suis à peu près sûr qu'il ne s'agit pas de manquer de mémoire car j'ai top en cours d'exécution lorsque les scénarios de test sont en cours d'exécution et qu'il n'y a aucun moyen de remplir la mémoire.

À l'origine de std :: bad_alloc? Que dans les détails de chash et block_extended_info peuvent être à l'origine de cela? Les objets de ces types sont copiés et transmis partout dans d'autres parties du code et cela ne pose aucun problème.

est ici la définition de chash:

class chash { 
    char data[32]; 
}; 

Et ce qui suit est tout ce qu'il faut pour définir block_extended_info:

class csignature { 
    chash c, r; 
}; 
enum foob { /* ... */ }; 
class ct { 
    uint64_t a, b; 
    foob c; 
}; 
typedef boost::variant< /* structs with ints, maps, vectors of ints */ > txin_v; 
typedef boost::variant< /* similar structs */ > txout_target_v; 
struct tx_out { 
    uint64_t a; 
    txout_target_v b; 
}; 
class transaction_prefix 
{ 
public: 
    size_t version; 
    uint64_t unlock_time; 
    std::vector<uint8_t> extra; 

protected: 
    std::vector<txin_v> a; 
    std::vector<tx_out> b; 
    std::vector<ct> c; 
    std::vector<ct> d; 
}; 
class transaction: public transaction_prefix 
{ 
public: 
    std::vector<std::vector<csignature> > signatures; 
}; 
struct block_header 
{ 
    uint8_t major_version; 
    uint8_t minor_version; 
    uint64_t timestamp; 
    chash prev_id; 
    uint32_t nonce; 
}; 
struct block: public block_header 
{ 
    transaction miner_tx; 
    std::vector<chash> tx_hashes; 
    uint16_t food_id; 
    csignature food_sig; 
}; 
struct block_extended_info 
{ 
    block bl; 
    uint64_t height; 
    size_t block_cumulative_size; 
    uint64_t cumulative_difficulty; 
    uint64_t already_generated_coins; 
}; 

pas à pas dans la zone concernée dans gdb, voici les dernières quelques lignes qui mènent jusqu'à la bad_alloc:

cryptonote::transaction::transaction(cryptonote::transaction const&)() at /usr/include/c++/4.8/bits/stl_vector.h:313 
313  { this->_M_impl._M_finish = 
646  { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); } 
91  : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0) 
168  { return __n != 0 ? _M_impl.allocate(__n) : 0; } 
183  this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; 
181  this->_M_impl._M_start = this->_M_allocate(__n); 
182  this->_M_impl._M_finish = this->_M_impl._M_start; 
183  this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; 
310  vector(const vector& __x) 
117  __uninit_copy(__first, __last, __result); 
cryptonote::tx_out* std::__uninitialized_copy<false>::__uninit_copy<__gnu_cxx::__normal_iterator<cryptonote::tx_out const*, std::vector<cryptonote::tx_out, std::allocator<cryptonote::tx_out> > >, cryptonote::tx_out*>(__gnu_cxx::__normal_iterator<cryptonote::tx_out const*, std::vector<cryptonote::tx_out, std::allocator<cryptonote::tx_out> > >, __gnu_cxx::__normal_iterator<cryptonote::tx_out const*, std::vector<cryptonote::tx_out, std::allocator<cryptonote::tx_out> > >, cryptonote::tx_out*)() 
    at /usr/include/c++/4.8/bits/stl_uninitialized.h:68 
68   __uninit_copy(_InputIterator __first, _InputIterator __last, 
74   for (; __first != __last; ++__first, ++__cur) 
83  } 
cryptonote::transaction::transaction(cryptonote::transaction const&)() at /usr/include/c++/4.8/bits/stl_vector.h:313 
313  { this->_M_impl._M_finish = 
646  { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); } 
91  : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0) 
646  { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); } 
168  { return __n != 0 ? _M_impl.allocate(__n) : 0; } 
101  if (__n > this->max_size()) 
104  return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); 
183  this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; 
181  this->_M_impl._M_start = this->_M_allocate(__n); 
182  this->_M_impl._M_finish = this->_M_impl._M_start; 
183  this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; 
310  vector(const vector& __x) 
74   for (; __first != __last; ++__first, ++__cur) 
71  _ForwardIterator __cur = __result; 
75  { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); } 
748  ++_M_current; 
74   for (; __first != __last; ++__first, ++__cur) 
313  { this->_M_impl._M_finish = 
646  { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); } 
91  : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0) 
646  { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); } 
168  { return __n != 0 ? _M_impl.allocate(__n) : 0; } 
183  this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; 
181  this->_M_impl._M_start = this->_M_allocate(__n); 
182  this->_M_impl._M_finish = this->_M_impl._M_start; 
183  this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; 
310  vector(const vector& __x) 
74   for (; __first != __last; ++__first, ++__cur) 
570 class transaction: public transaction_prefix 
313  { this->_M_impl._M_finish = 
646  { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); } 
91  : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0) 
646  { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); } 
168  { return __n != 0 ? _M_impl.allocate(__n) : 0; } 
101  if (__n > this->max_size()) 
104  return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); 
181  this->_M_impl._M_start = this->_M_allocate(__n); 
183  this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; 
181  this->_M_impl._M_start = this->_M_allocate(__n); 
182  this->_M_impl._M_finish = this->_M_impl._M_start; 
183  this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; 
310  vector(const vector& __x) 
74   for (; __first != __last; ++__first, ++__cur) 
101  if (__n > this->max_size()) 
75  { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); } 
646  { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); } 
91  : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0) 
168  { return __n != 0 ? _M_impl.allocate(__n) : 0; } 
101  if (__n > this->max_size()) 
102  std::__throw_bad_alloc(); 
+0

'size_t' est défini par l'implémentation. Pourquoi ne pas utiliser 'uint64_t' comme avec d'autres champs? – UmNyobe

+0

@UmNyobe: Bonne question. J'ai hérité de cette partie du code, je l'ai donc laissé tel quel. Cela pourrait-il être le problème? – xpbcreator

+0

_ @ xpbcreator_ Il est en fait impossible de diagnostiquer le problème avec le contexte de code que vous donnez. Je soupçonne que l'erreur se produit ailleurs, ou à cause d'une variable non initialisée, ou d'un comportement indéfini. –

Répondre

0

Comme πάντα ῥεῖ soupçonné, le problème était ailleurs.

Le code I répertorié était dans une fonction appelée add_block_as_invalid(...). Le site d'appel avait l'air quelque chose comme ceci:

// parameter, iterators into m_alternative_chains 
std::list<blocks_ext_by_hash::iterator>& alt_chain; 

for(auto alt_ch_iter = alt_chain.begin(); 
    alt_ch_iter != alt_chain.end(); 
    alt_ch_iter++) 
{ 
    // .... 
    auto ch_ent = *alt_ch_iter; 
    // .... 
    m_alternative_chains.erase(ch_ent); 

    for(auto alt_ch_to_orph_iter = ++alt_ch_iter; 
     alt_ch_to_orph_iter != alt_chain.end(); 
     alt_ch_to_orph_iter++) 
    { 
     add_block_as_invalid((*alt_ch_iter)->second, (*alt_ch_iter)->first); 
     m_alternative_chains.erase(*alt_ch_to_orph_iter); 
    } 
} 

L'appel à add_block_as_invalid gardé déréférencement alt_ch_iter, qui avait déjà été effacé.