Skip to content

Commit b1e7bcc

Browse files
authored
Merge pull request #2169 from hakonsbm/block_vector_glibcxx_assertion_errors
Fix container access in corner cases and add _GLIBCXX_ASSERTIONS checks to all test configurations
2 parents bb9fab8 + 4a85a34 commit b1e7bcc

File tree

4 files changed

+64
-41
lines changed

4 files changed

+64
-41
lines changed

extras/ci_build.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,14 @@ xPYTHON=0
155155
xREADLINE=0
156156
xSIONLIB=0
157157
158-
CXX_FLAGS="-pedantic -Wextra -Wno-unknown-pragmas"
158+
CXX_FLAGS="-pedantic -Wextra -Wno-unknown-pragmas -D_GLIBCXX_ASSERTIONS"
159159
160160
if [ "$xNEST_BUILD_TYPE" = "OPENMP_ONLY" ]; then
161161
xGSL=1
162162
xLIBBOOST=1
163163
xLTDL=1
164164
xOPENMP=1
165-
CXX_FLAGS="-pedantic -Wextra"
165+
CXX_FLAGS="-pedantic -Wextra -D_GLIBCXX_ASSERTIONS"
166166
fi
167167
168168
if [ "$xNEST_BUILD_TYPE" = "MPI_ONLY" ]; then
@@ -183,7 +183,7 @@ if [ "$xNEST_BUILD_TYPE" = "FULL" ]; then
183183
xPYTHON=1
184184
xREADLINE=1
185185
xSIONLIB=1
186-
CXX_FLAGS="-pedantic -Wextra"
186+
CXX_FLAGS="-pedantic -Wextra -D_GLIBCXX_ASSERTIONS"
187187
fi
188188
189189
if [ "$xNEST_BUILD_TYPE" = "FULL_NO_EXTERNAL_FEATURES" ]; then

libnestutil/block_vector.h

Lines changed: 59 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,10 @@ class bv_iterator
6262
template < typename cv_value_type_ >
6363
using iter_ = bv_iterator< value_type_, cv_value_type_&, cv_value_type_* >;
6464

65-
const BlockVector< value_type_ >* block_vector_; //!< BlockVector to which this iterator points
66-
size_t block_index_; //!< Index of the current block in the blockmap
65+
//! BlockVector to which this iterator points
66+
const BlockVector< value_type_ >* block_vector_;
67+
//! Iterator for the current block in the blockmap
68+
typename std::vector< std::vector< value_type_ > >::const_iterator block_vector_it_;
6769
//! Iterator pointing to the current element in the current block.
6870
typename std::vector< value_type_ >::const_iterator block_it_;
6971
//! Iterator pointing to the end of the current block.
@@ -81,7 +83,6 @@ class bv_iterator
8183

8284
bv_iterator()
8385
: block_vector_( nullptr )
84-
, block_index_( 0 )
8586
{
8687
}
8788

@@ -105,7 +106,7 @@ class bv_iterator
105106
* @param current_block_end Iterator pointing to the end of the current block.
106107
*/
107108
bv_iterator( const BlockVector< value_type_ >*,
108-
const size_t,
109+
const typename std::vector< std::vector< value_type_ > >::const_iterator,
109110
const typename std::vector< value_type_ >::const_iterator,
110111
const typename std::vector< value_type_ >::const_iterator );
111112

@@ -328,6 +329,7 @@ inline BlockVector< value_type_ >::BlockVector( size_t n )
328329
{
329330
blockmap_.emplace_back( max_block_size );
330331
}
332+
finish_ = begin(); // Because the blockmap has changed we need to recreate the iterator
331333
finish_ += n;
332334
}
333335

@@ -396,7 +398,11 @@ BlockVector< value_type_ >::push_back( const value_type_& value )
396398
// If this is the last element in the current block, add another block
397399
if ( finish_.block_it_ == finish_.current_block_end_ - 1 )
398400
{
401+
// Need to get the current position here, then recreate the iterator after we extend the blockmap,
402+
// because after the blockmap is changed the iterator becomes invalid.
403+
const auto current_block = finish_.block_vector_it_ - finish_.block_vector_->blockmap_.begin();
399404
blockmap_.emplace_back( max_block_size );
405+
finish_.block_vector_it_ = finish_.block_vector_->blockmap_.begin() + current_block;
400406
}
401407
*finish_ = value;
402408
++finish_;
@@ -421,16 +427,16 @@ inline size_t
421427
BlockVector< value_type_ >::size() const
422428
{
423429
size_t element_index; // Where we are in the current block
424-
if ( finish_.block_index_ >= blockmap_.size() )
430+
if ( finish_.block_vector_it_ >= blockmap_.end() )
425431
{
426432
// If the current block is completely filled
427433
element_index = 0;
428434
}
429435
else
430436
{
431-
element_index = finish_.block_it_ - blockmap_[ finish_.block_index_ ].begin();
437+
element_index = finish_.block_it_ - finish_.block_vector_it_->begin();
432438
}
433-
return finish_.block_index_ * max_block_size + element_index;
439+
return ( finish_.block_vector_it_ - finish_.block_vector_->blockmap_.begin() ) * max_block_size + element_index;
434440
}
435441

436442
template < typename value_type_ >
@@ -457,8 +463,9 @@ BlockVector< value_type_ >::erase( const_iterator first, const_iterator last )
457463
*repl_it = std::move( *element );
458464
++repl_it;
459465
}
460-
// The block that repl_it ends up in is the new final block.
461-
auto& new_final_block = blockmap_[ repl_it.block_index_ ];
466+
// The block that repl_it ends up in is the new final block. Using iterator arithmetics to avoid issues with the
467+
// const iterator.
468+
auto& new_final_block = blockmap_[ repl_it.block_vector_it_ - blockmap_.begin() ];
462469
// Here, the arithmetic says that we first subtract
463470
// new_final_block.begin(), then add it again (which seems unnecessary).
464471
// But what we really do is extracting the element index of repl_it, then
@@ -475,7 +482,7 @@ BlockVector< value_type_ >::erase( const_iterator first, const_iterator last )
475482
}
476483
assert( new_final_block.size() == max_block_size );
477484
// Erase all subsequent blocks.
478-
blockmap_.erase( blockmap_.begin() + repl_it.block_index_ + 1, blockmap_.end() );
485+
blockmap_.erase( repl_it.block_vector_it_ + 1, blockmap_.end() );
479486
// Construct new finish_ iterator
480487
finish_ = repl_it;
481488
// The iterator which is to be returned is located where the first element
@@ -492,7 +499,6 @@ BlockVector< value_type_ >::print_blocks() const
492499
std::cerr << "this: \t\t" << this << "\n";
493500
std::cerr << "finish block_vector: \t" << finish_.block_vector_ << "\n";
494501
std::cerr << "Blockmap size: " << blockmap_.size() << "\n";
495-
std::cerr << "Finish block: " << finish_.block_index_ << "\n";
496502
std::cerr << "==============================================\n";
497503
auto seq_iter = begin();
498504
for ( size_t block_index = 0; block_index != blockmap_.size() and seq_iter != end(); ++block_index )
@@ -559,28 +565,28 @@ BlockVector< value_type_ >::rend() const
559565
template < typename value_type_, typename ref_, typename ptr_ >
560566
inline bv_iterator< value_type_, ref_, ptr_ >::bv_iterator( const BlockVector< value_type_ >& block_vector )
561567
: block_vector_( &block_vector )
562-
, block_index_( 0 )
563-
, block_it_( block_vector_->blockmap_[ block_index_ ].begin() )
564-
, current_block_end_( block_vector_->blockmap_[ block_index_ ].end() )
568+
, block_vector_it_( block_vector_->blockmap_.begin() )
569+
, block_it_( block_vector_it_->begin() )
570+
, current_block_end_( block_vector_it_->end() )
565571
{
566572
}
567573

568574
template < typename value_type_, typename ref_, typename ptr_ >
569575
inline bv_iterator< value_type_, ref_, ptr_ >::bv_iterator( const iterator& other )
570576
: block_vector_( other.block_vector_ )
571-
, block_index_( other.block_index_ )
577+
, block_vector_it_( other.block_vector_it_ )
572578
, block_it_( other.block_it_ )
573579
, current_block_end_( other.current_block_end_ )
574580
{
575581
}
576582

577583
template < typename value_type_, typename ref_, typename ptr_ >
578584
inline bv_iterator< value_type_, ref_, ptr_ >::bv_iterator( const BlockVector< value_type_ >* block_vector,
579-
const size_t block_index,
585+
const typename std::vector< std::vector< value_type_ > >::const_iterator block_vector_it,
580586
const typename std::vector< value_type_ >::const_iterator block_it,
581587
const typename std::vector< value_type_ >::const_iterator current_block_end )
582588
: block_vector_( block_vector )
583-
, block_index_( block_index )
589+
, block_vector_it_( block_vector_it )
584590
, block_it_( block_it )
585591
, current_block_end_( current_block_end )
586592
{
@@ -592,9 +598,16 @@ inline bv_iterator< value_type_, ref_, ptr_ >& bv_iterator< value_type_, ref_, p
592598
++block_it_;
593599
if ( block_it_ == current_block_end_ )
594600
{
595-
++block_index_;
596-
block_it_ = block_vector_->blockmap_[ block_index_ ].begin();
597-
current_block_end_ = block_vector_->blockmap_[ block_index_ ].end();
601+
++block_vector_it_;
602+
// If we are at end() now, we are outside of the blockmap, which is
603+
// undefined. The outer iterator can be in an undefined position that
604+
// will compare as safely larger or equal to end(), but we don't set
605+
// the inner iterators.
606+
if ( block_vector_it_ != block_vector_->blockmap_.end() )
607+
{
608+
block_it_ = block_vector_it_->begin();
609+
current_block_end_ = block_vector_it_->end();
610+
}
598611
}
599612
return *this;
600613
}
@@ -604,16 +617,24 @@ inline bv_iterator< value_type_, ref_, ptr_ >& bv_iterator< value_type_, ref_, p
604617
{
605618
// If we are still within the block, we can just decrement the block iterator.
606619
// If not, we need to switch to the previous block.
607-
if ( block_it_ != block_vector_->blockmap_[ block_index_ ].begin() )
620+
if ( block_it_ != block_vector_it_->begin() )
608621
{
609622
--block_it_;
610623
}
611-
else
624+
else if ( block_vector_it_ != block_vector_->blockmap_.begin() )
612625
{
613-
--block_index_;
614-
current_block_end_ = block_vector_->blockmap_[ block_index_ ].end();
626+
--block_vector_it_;
627+
current_block_end_ = block_vector_it_->end();
615628
block_it_ = current_block_end_ - 1;
616629
}
630+
else
631+
{
632+
// We are before begin(), which is undefined. We mark this by moving the
633+
// outer iterator to an undefined position that will compare as safely smaller
634+
// than begin(). According to C++17 Standard, §27.2.6, decrementing an
635+
// iterator that is equal to begin() yields undefined behavior.
636+
--block_vector_it_;
637+
}
617638
return *this;
618639
}
619640

@@ -699,26 +720,26 @@ template < typename value_type_, typename ref_, typename ptr_ >
699720
inline typename bv_iterator< value_type_, ref_, ptr_ >::difference_type bv_iterator< value_type_, ref_, ptr_ >::
700721
operator-( const iterator& other ) const
701722
{
702-
auto this_element_index = block_it_ - block_vector_->blockmap_[ block_index_ ].begin();
703-
auto other_element_index = other.block_it_ - other.block_vector_->blockmap_[ other.block_index_ ].begin();
704-
return ( block_index_ - other.block_index_ ) * max_block_size + ( this_element_index - other_element_index );
723+
const auto this_element_index = block_it_ - block_vector_it_->begin();
724+
const auto other_element_index = other.block_it_ - other.block_vector_it_->begin();
725+
return ( block_vector_it_ - other.block_vector_it_ ) * max_block_size + ( this_element_index - other_element_index );
705726
}
706727

707728
template < typename value_type_, typename ref_, typename ptr_ >
708729
inline typename bv_iterator< value_type_, ref_, ptr_ >::difference_type bv_iterator< value_type_, ref_, ptr_ >::
709730
operator-( const const_iterator& other ) const
710731
{
711-
auto this_element_index = block_it_ - block_vector_->blockmap_[ block_index_ ].begin();
712-
auto other_element_index = other.block_it_ - other.block_vector_->blockmap_[ other.block_index_ ].begin();
713-
return ( block_index_ - other.block_index_ ) * max_block_size + ( this_element_index - other_element_index );
732+
const auto this_element_index = block_it_ - block_vector_it_->begin();
733+
const auto other_element_index = other.block_it_ - other.block_vector_it_->begin();
734+
return ( block_vector_it_ - other.block_vector_it_ ) * max_block_size + ( this_element_index - other_element_index );
714735
}
715736

716737
template < typename value_type_, typename ref_, typename ptr_ >
717738
inline typename bv_iterator< value_type_, ref_, ptr_ >::iterator& bv_iterator< value_type_, ref_, ptr_ >::operator=(
718739
const iterator& other )
719740
{
720741
block_vector_ = other.block_vector_;
721-
block_index_ = other.block_index_;
742+
block_vector_it_ = other.block_vector_it_;
722743
block_it_ = other.block_it_;
723744
current_block_end_ = other.current_block_end_;
724745
return *this;
@@ -735,26 +756,28 @@ template < typename value_type_, typename ref_, typename ptr_ >
735756
inline bool bv_iterator< value_type_, ref_, ptr_ >::operator==(
736757
const bv_iterator< value_type_, ref_, ptr_ >& rhs ) const
737758
{
738-
return ( block_index_ == rhs.block_index_ and block_it_ == rhs.block_it_ );
759+
return ( block_vector_it_ == rhs.block_vector_it_ and block_it_ == rhs.block_it_ );
739760
}
740761

741762
template < typename value_type_, typename ref_, typename ptr_ >
742763
inline bool bv_iterator< value_type_, ref_, ptr_ >::operator!=(
743764
const bv_iterator< value_type_, ref_, ptr_ >& rhs ) const
744765
{
745-
return ( block_index_ != rhs.block_index_ or block_it_ != rhs.block_it_ );
766+
return ( block_vector_it_ != rhs.block_vector_it_ or block_it_ != rhs.block_it_ );
746767
}
747768

748769
template < typename value_type_, typename ref_, typename ptr_ >
749770
inline bool bv_iterator< value_type_, ref_, ptr_ >::operator<( const bv_iterator& rhs ) const
750771
{
751-
return ( block_index_ < rhs.block_index_ or ( block_index_ == rhs.block_index_ and block_it_ < rhs.block_it_ ) );
772+
return ( block_vector_it_ < rhs.block_vector_it_
773+
or ( block_vector_it_ == rhs.block_vector_it_ and block_it_ < rhs.block_it_ ) );
752774
}
753775

754776
template < typename value_type_, typename ref_, typename ptr_ >
755777
inline bool bv_iterator< value_type_, ref_, ptr_ >::operator>( const bv_iterator& rhs ) const
756778
{
757-
return ( block_index_ > rhs.block_index_ or ( block_index_ == rhs.block_index_ and block_it_ > rhs.block_it_ ) );
779+
return ( block_vector_it_ > rhs.block_vector_it_
780+
or ( block_vector_it_ == rhs.block_vector_it_ and block_it_ > rhs.block_it_ ) );
758781
}
759782

760783
template < typename value_type_, typename ref_, typename ptr_ >
@@ -773,7 +796,7 @@ template < typename value_type_, typename ref_, typename ptr_ >
773796
inline typename bv_iterator< value_type_, ref_, ptr_ >::iterator
774797
bv_iterator< value_type_, ref_, ptr_ >::const_cast_() const
775798
{
776-
return iterator( block_vector_, block_index_, block_it_, current_block_end_ );
799+
return iterator( block_vector_, block_vector_it_, block_it_, current_block_end_ );
777800
}
778801

779802
template < typename value_type_, typename ref_, typename ptr_ >

nestkernel/mpi_manager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ nest::MPIManager::communicate( std::vector< long >& local_nodes, std::vector< lo
314314
displacements.at( i ) = displacements.at( i - 1 ) + num_nodes_per_rank.at( i - 1 );
315315
}
316316

317-
MPI_Allgatherv( &local_nodes[ 0 ],
317+
MPI_Allgatherv( &( *local_nodes.begin() ),
318318
local_nodes.size(),
319319
MPI_Type< long >::type,
320320
&global_nodes[ 0 ],

nestkernel/mpi_manager_impl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ nest::MPIManager::communicate_Allgatherv( std::vector< T >& send_buffer,
7878
std::vector< int >& recv_counts )
7979
{
8080
// attempt Allgather
81-
MPI_Allgatherv( &send_buffer[ 0 ],
81+
MPI_Allgatherv( &( *send_buffer.begin() ),
8282
send_buffer.size(),
8383
MPI_Type< T >::type,
8484
&recv_buffer[ 0 ],

0 commit comments

Comments
 (0)