Segmentation Fault When Sending Struct Having Std::Vector Member

Segmentation fault when sending struct having std::vector member

Here is an example with several std::vector members that uses MPI datatypes with absolute addresses:

struct Child
{
int foo;
std::vector<float> bar;
std::vector<int> baz;

Child() : dtype(MPI_DATATYPE_NULL) {}
~Child() { if (dtype != MPI_DATATYPE_NULL) MPI_Type_free(dtype); }

const MPI_Datatype mpi_dtype();
void invalidate_dtype();

private:
MPI_Datatype dtype;
void make_dtype();
};

const MPI_Datatype Child::mpi_dtype()
{
if (dtype == MPI_DATATYPE_NULL)
make_dtype();
return dtype;
}

void Child::invalidate_dtype()
{
if (dtype != MPI_DATATYPE_NULL)
MPI_Datatype_free(&dtype);
}

void Child::make_dtype()
{
const int nblock = 3;
int block_count[nblock] = {1, bar.size(), baz.size()};
MPI_Datatype block_type[nblock] = {MPI_INT, MPI_FLOAT, MPI_INT};
MPI_Aint offset[nblock];
MPI_Get_address(&foo, &offset[0]);
MPI_Get_address(&bar[0], &offset[1]);
MPI_Get_address(&baz[0], &offset[2]);

MPI_Type_struct(nblock, block_count, offset, block_type, &dtype);
MPI_Type_commit(&dtype);
}

Sample use of that class:

Child kid;
kid.foo = 5;
kid.bar.resize(5);
kid.baz.resize(10);

if (rank == 0)
{
MPI_Send(MPI_BOTTOM, 1, kid.mpi_dtype(), 1, 0, MPI_COMM_WORLD);
}

if (rank == 1)
{
MPI_Recv(MPI_BOTTOM, 1, kid.mpi_dtype(), 0, 0, MPI_COMM_WORLD, NULL);
}

Notice the use of MPI_BOTTOM as the buffer address. MPI_BOTTOM specifies the bottom of the address space, which is 0 on architectures with flat address space. Since the offsets passed to MPI_Type_create_struct are the absolute addresses of the structure members, when those are added to 0, the result is again the absolute address of each structure member. Child::mpi_dtype() returns a lazily constructed MPI datatype specific to that instance.

Since resize() reallocates memory, which could result in the data being moved to a different location in memory, the invalidate_dtype() method should be used to force the recreation of the MPI datatype after resize() or any other operation that might trigger memory reallocation:

// ...
kid.bar.resize(100);
kid.invalidate_dtype();
// MPI_Send / MPI_Recv

Please excuse any sloppy C++ code above.

Pushing a struct datatype into a vector

The big size value is so weird, it's got to be some garbage value, not the real size.

My first guess is maybe the data type of the library you are using (OGRE) is doing it's own customized memory management, for instance the type Ogre::Vector3 may require some specific memory alignment condition (for performance consideration, or for vectorization purpose etc.). std::vector<SegData> uses the STL's default allocator, and that may not play well with the required alignment condition.

Just out of curiosity, I searched a little bit and found this post. So basically you could try to pass the STLAllocator<GeneralAllocPolicy> as the second template argument (which specifies the type of customized allocator) to std::vector. This may worth a try, just declare you vector as:

std::vector<SegData, STLAllocator<SegData,GeneralAllocPolicy> > temp;

(where in the original post, I think they forgot the second SegData template argument). If it does not work, you may need to check the library documentation page (f.e. this one) to see if there should be other allocators or it was some other issue.

Also note that, this is quite a common issue: many libraries chose to use their own memory management strategy, either due to performance optimization, or simply due to alignment constraint. For instance, the Eigen (a C++ linear algebra library) library's fixed-size vector must be accompanied with it's aligned_allocator for proper alignment (see here if you're interested in some more detail).

Hope this can help you!

C++ Segmentation Fault when attempting to write to a vector passed by reference

When you do :

procList[pid][i] = ...

You are accessing an entry object that does not exist yet : the std::vector default constructor makes it empty, it has a size of 0. This has undefined behavior.


Solution:

  • You can use resize() to add default elements on your vectors (and their subvectors !)
  • Or you can provide default elements at the construction of your vectors :
  • Or you can use brace initializers to initialize your vector directly.

Example:

vector< vector<entry> > processVector(10); // will have 10 default constructed entry objects.
vector< vector<entry> > eventVector(10); // will have 10 default constructed entry objects.

for(auto& v : processVector)
v.resize(10);
for(auto& v : eventVector)
v.resize(10);

Notes:

  • You should check for the the return of each I/O operation
  • Using the at() member function instead of operator[] on your vector will check the bounds for you, you would get something like ;

terminate called after throwing an instance of 'std::out_of_range'

what(): vector::_M_range_check

Segmentation fault: 11 c++ when using vector

The behaviour of a vector's operator[]() is undefined if it is used to access elements that do not exist.

Since you have used default-constructed vectors, their size is zero - so they have no elements to access.

If you use the .at() member function, it will check the index and throw an exception (of type std::out_of_range, which is declared in the standard header <stdexcept>) when indices are invalid. You can confirm that by wrapping the code in an appropriate try/catch block.

To eliminate the problem, you need to reize the vector (e.g. add elements to it using push_back(), resize it using resize(), etc) before using operator[](). And ensure the index is valid, since operator[]() does not resize a std::vector.

Also, temp[j] is equivalent to temp.operator[](j). For types that supply an operator[]() function, the compiler handles turning expressions like temp[j] into a call of temp.operator[](j).

Segmentation fault when assigning the return vector of a function to another vector

The segfault is happening here:

for( unsigned int i = 0; i < strings.size() - 1; ++i ) {
if( strings[i].compare(strings[i+1]) == 0 ) {

The issue is that you are comparing an unsigned value, i, with the unsigned value returned from strings.size() - 1. When strings.size() is 0, this part i < strings.size() - 1 will be checking if i is less than the greatest integer value, which will (basically) always be true.

This causes strings[i+1] to segfault when strings is length 0 or 1.

This can be fixed in many ways, but for( int i = 0; i < (int)strings.size() - 1; ++i ) { would be a quick and dirty way to fix it.

C++ Dynamic array of structs segmentation fault

Your segfault is happening because you are trying to access an out-of-bounds element of contact array. The size of contact is amount, and you are iterating it from 0 to amount + count. Obviously, amount + count >= amount, so sooner or later you will run out of bounds.

I would suggest you to use std::vector instead of a plain array. You will always be aware of it's size and will be able to iterate it safely.

If you want to keep the arrays, you will have to either reallocate contact after copying the contacts from the old file, to make it size equal to total, or make two separate arrays: one to hold the records from the old file with the size of amount elements, and another one for the newly-added contacts with the size of count elements.

As it is mentioned in the comments, your end-of-file check is wrong, this and this questions are relevant.

Segmentation fault occurs when variable set to indexed parameter

Your function's 1st loop is accessing the commun_cards array incorrectly. Its 3rd loop is accessing the array correctly. Why would you expect the 1st loop to need to access the elements any differently than the 3rd loop just because it wants to save each element to a variable?

Since you are passing in each array by pointer, you must dereference each pointer before you can then index into the elements of each array. Your 2nd and 3rd loops are doing that. Your 1st loop is not.

Your 1st loop is expecting commun_cards[i] to yield a pointer to each element, but that is simply not true, which is why *temp_card then crashes. If you really want a pointer to each element, you need to use this instead:

auto *temp_card = &(*commun_cards)[i];
// alternatively:
// auto *temp_card = (*commun_cards) + i;
cout << *temp_card << " " << temp_card->s << " " << temp_card->v << endl;

Otherwise, use a reference to each element instead of a pointer:

auto &temp_card = (*commun_cards)[i];
// alternatively:
// auto &temp_card = *((*commun_cards) + i);
cout << temp_card << " " << temp_card.s << " " << temp_card.v << endl;

If you change the function to accept the arrays by reference instead of by pointer (which I highly suggest you do), then the function would become this:

int get_winner(const card (&hand)[num_players][2], const card (&commun_cards)[5])
{
for (int i = 0; i < 5; i++) {
auto &temp_card = commun_cards[i];
cout << temp_card << " " << temp_card.s << " " << temp_card.v << endl;
}
for (int i = 0; i < num_players; i++) {
cout << hand[i][0] << ", " << hand[i][1] << endl;
}
for (int i = 0; i < 5; i++) {
cout << commun_cards[i] << endl;
}
return 0;
}

...

get_winner(hands, commun_cards);

C++ std::vector of pointers deletion and segmentation faults


void Population::clearPool( std::vector <Chromosome*> & a )
{
for ( int i = 0; i < a.size(); i++ ) {
delete a[i];
}
a.clear();
}

Notice that the vector is passed by reference. In your code, a copy of the vector is used, which means that it is unchanged in the calling program. Because you delete the pointers in the copy, the pointers in the original are now all invalid - I suspect you are using those invalid pointers in some way not shown in the code you posted.

As a couple of template solutions have been posted that use C++ library algorithms, you might also want to consider a template solution that does not:

template <class C> void FreeClear( C & cntr ) {
for ( typename C::iterator it = cntr.begin();
it != cntr.end(); ++it ) {
delete * it;
}
cntr.clear();
}

Using this you can free any container of dynamically allocated objects:

vector <Chromosome *> vc;
list <Chromosome *> lc;
// populate & use
FreeClear( lc );
FreeClear( vc );


Related Topics



Leave a reply



Submit