Konrad Kapp Konrad Kapp - 3 months ago 15
C++ Question

delete[] operator causes segmentation fault in very simple case

I have a very strange segmentation fault that occurs when I call

delete[]
on an allocated dynamic array (created with the
new
keyword). At first it occurred when I deleted a global pointer, but it also happens in the following very simple case, where I
delete[] arr


int main(int argc, char * argv [])
{
double * arr = new double [5];
delete[] arr;
}


I get the following message:

*** Error in `./energy_out': free(): invalid next size (fast): 0x0000000001741470 ***
Aborted (core dumped)


Apart from the
main
function, I define some fairly standard functions, as well as the following (defined before the
main
function)

vector<double> cos_vector()
{
vector<double> cos_vec_temp = vector<double>(int(2*pi()/trig_incr));
double curr_val = 0;
int curr_idx = 0;
while (curr_val < 2*pi())
{
cos_vec_temp[curr_idx] = cos(curr_val);
curr_idx++;
curr_val += trig_incr;
}

return cos_vec_temp;
}

const vector<double> cos_vec = cos_vector();


Note that the return value of
cos_vector
,
cos_vec_temp
, gets assigned to the global variable
cos_vec
before the main function is called.

The thing is, I know what causes the error:
cos_vec_temp
should be one element bigger, as
cos_vec_temp[curr_idx]
ends up accessing one element past the end of the vector
cos_vec_temp
. When I make
cos_vec_temp
one element larger at its creation, the error does not occur. But I do not understand why it occurs at the
delete[]
of
arr
. When I run gdb, after setting a breakpoint at the start of the
main
function, just after the creation of
arr
, I get the following output when examining contents of the variables:

(gdb) p &cos_vec[6283]
$11 = (__gnu_cxx::__alloc_traits<std::allocator<double> >::value_type *) 0x610468

(gdb) p arr
$12 = (double *) 0x610470


In the first gdb command, I show the memory location of the element just past the end of the
cos_vec
vector, which is
0x610468
. The second gdb command shows the memory location of the
arr
pointer, which is
0x610470
. Since I assigned a
double
to the invalid memory location
0x610468
, I understand it must have wrote partly over the location that starts at
0x610470
, but this was done before
arr
was even created (the function is called before
main
). So why does this affect
arr
? I would have thought that when
arr
is created, it does not "care" what was previously done to the memory location there, since it is not registered as being in use.

Any clarification would be appreciated.

NOTE:

cos_vec_temp
was previously declared as a dynamic double array of size
int(2*pi()/trig_incr)
(same size as the one in the code, but created with
new
). In that case, I also had the invalid access as above, and it also did not give any errors when I accessed the element at that location. But when I tried to call
delete[]
on the
cos_vec
global variable (which was of type
double *
then) it also gave a segmentation fault, but it did not give the message that I got for the case above.

NOTE 2:

Before you downvote me for using a dynamic array, I am just curious as to why this occurs. I normally use STL containers and all their conveniences (I almost NEVER use dynamic arrays).

Answer

Many heap allocators have meta-data stored next to the memory it allocates for you, before or after (or both) the memory. If you write out of bounds of some heap-allocated memory (and remember that std::vector dynamically allocates off the heap) you might overwrite some of this meta-data, corrupting the heap.

None of this is actually specified in the C++ specifications. All it says that going out of bounds leads to undefined behavior. What the allocators do, or store, and where it possibly store meta-data, is up to the implementation.


As for a solution, well most people tell you to use push_back instead of direct indexing, and that will solve the problem. Unfortunately it will also mean that the vector needs to be reallocated and copied a few times. That can be solved by reserving an approximate amount of memory beforehand, and then let the extra stray element lead to a reallocation and copying.

Or, or course, make better predictions for the actual amount of elements the vector will contain.

Comments