Deletion of Custom Array Causes Heap Error - c++

TL;DR
Boost-Test-Framework crashes with no error given while passing all tests and leaking all memory.
Test fails multiple times with mentioned destructor implementations. Clear function also throws heap error.
What are we doing wrong with the dtor?
TL;DR
This is pertaining to a college homework assignment, and my friend's solution to said problem. In order to get more aquainted with C-style pointers and a more low-level style of programming, we needed to implement our own dynamic array.
His assignment is complete and completely functional according to our teacher's 900-LOC Boost-Test Framework. The only problem is the crash (or heap error, as no real error message pops up) when the tests exit, or an implemented dtor is called.
His dynamic array uses three pointers: pFirst, pLast and pEnd, pointing to the first element of the array, to the one past the last element in the array, and pointing to the last not-yet allocated element in the array respectively.
His program passed as long as he didn't try to delete any pointers. This is a bad idea, but hey, it let him pass the assignment. For now.
My friend has tried several times to implement a destructor, but they both cause heap errors and cause the test-framework to fail.
// Teacher's recommended dtor.
Field::~Field()
{
for(int i(0); i != this->size(); ++i)
(pFirst+i)->~T();
delete pFirst;
pFirst = pLast = pEnd = NULL;
}
and
// My recommendation to friend.
Field::~Field()
{
delete[] pFirst;
pFirst = pLast = pEnd = NULL;
}
both crash with the same heap error.
Assertion failed: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
A typical chain of tests looks like:
BOOST_AUTO_TEST_CASE( TEST_clear )
{
Field f( 3, 4.0f );
f.clear(); // Error here IF we use delete in the clear method.
BOOST_CHECK( f.size()==0 );
BOOST_CHECK( f.capacity()==4 );
} // Error here; during destruction IF we have implemented the dtor.
The clear method emits the same error when we try to replace the array, so we just have:
void Field::clear()
{
size_t capa = capacity();
T *temp =pFirst;
pFirst = new T[capa];
pLast = pFirst;
pEnd = pFirst+capa;
}
What are we doing wrong with the dtor, clear and in general when dealing with the deletion of pointers?

Assertion failed: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) indicates heap corruption. Usually it happens when you write past the end of the allocated memory.
I see the following issue in your code: in Field::clear you store the pointer to allocated memory in pFirst and immediately overwrite it by pLast. I think you should change it to pLast = pFirst;.
Teacher's recommended dtor makes no sense to me. If you allocate with new[] then deallocate with delete[], don't call each destructor separately and use delete.

If pFirst points to the first element of the array, then your "teacher's recommended dtor" is wrong. You'd need to say delete[] pFirst to deallocate the array.
But there are many issues which could be causing this, such as heap corruption caused by some other function. Try running this in a memory-corruption check program, like Valgrind, to see if you are overflowing your heap buffer.

Related

Clang warns about potential memory leak when constructor involves recursion

I am writing a class where recursion is a must when writing its constructor, then clang analyzer complains about potential memory leak of this function, although I cannot see why and can guarantee that the recursion will always terminate.
Here is the code:
VeblenNormalForm::VeblenNormalForm(CantorNormalForm* _cnf) {
terms = vnf_terms();
_is_cnf = true;
if (!_cnf->is_zero()) {
for (int i = 0; i < _cnf->terms.size(); i++) {
terms.push_back(
phi(&ZERO, new VeblenNormalForm(get<0>(_cnf->terms[i]))) * get<1>(_cnf->terms[i])
);
}
}
}
The analysis given by clang is that it tries to enter the true branch for a few times and then claims there exist a potential memory leakage. Is it a real warning or just clang analyzer doing weird things?
One problem is with exception safety. Your terms vector stores tuples of VeblenNormalForm*, which you allocate at least the second element with new.
Presumably you have corresponding deletes in your destructor, but if an exception is thrown from a constructor, the destructor will not be called.
In your case, you could allocate the first N elements correctly, but get an exception in N + 1st element. In that case, your first N elements will be leaked. terms will still get destructed properly, but since you only have raw pointers in it, nothing will be deleted properly.
You could fix this issue by making your tuple be a std::tuple<VeblenNormalForm*, std::shared_ptr<const VeblenNormalForm>>. In this case, even if you get an exception mid-construction, the smart pointers will correctly delete the well-constructed objects. This assumes the first pointer is pointing to some global variable, so it's still just a regular pointer. If that is also being dynamically allocated, you need to use a smart pointer for that as well.
Code-wise, it should look like this:
using phi = std::tuple<VeblenNormalForm*, std::shared_ptr<const VeblenNormalForm>>;
VeblenNormalForm::VeblenNormalForm(CantorNormalForm* _cnf) {
terms = vnf_terms();
_is_cnf = true;
if (!_cnf->is_zero()) {
for (int i = 0; i < _cnf->terms.size(); i++) {
terms.push_back(
phi(&ZERO, std::make_shared<VeblenNormalForm>(get<0>(_cnf->terms[i]))) * get<1>(_cnf->terms[i])
);
}
}
}
Note that these pointers point to const VeblenNormalForm. Sharing mutable data across different objects is very difficult to get right. If you can prove to yourself you will do it right, feel free to remove the const.

How to delete memory of a pointer to pointer in C++

Using Valgrind, I see that I have a problem while deleting the memory in the following function:
Obj1 Obj1::operator*(const Obj1& param) const {
int n = param.GetSize(2);
Obj2** s = new Obj2*[n];
for( int i = 0; i < n; ++i) {
s[i] = new Obj2(*this*param.GetColumn(i+1));
}
Obj1 res = foo(s,n);
for(int i=n-1;i>-1;i--) {
s[i]->~Obj2();
}
delete[] s;
return res;
Valgrind tells me that the leak comes from the line
s[i] = new Obj2(*this*param.GetColumn(i+1));
I'm not pretty sure if the problem is when I try to free the memory. Can anyone tell me how to fix this problem?
Here:
s[i] = new Obj2(*this*param.GetColumn(i+1));
you create a dynamic object and assign s[i]to point to it.
In order to delete it, you do this:
delete s[i];
Unless you do that, the allocation will leak.
You must repeat that in a loop for every i just like you repeated the allocations. You of course have to do this before you delete s itself.
s[i]->~Obj2();
Don't do that. Calling the destructor is not appropriate here. delete will call the destructor.
P.S. Don't use raw owning pointers. Use containers or smart pointers instead. std::vector is a standard containers for dynamic arrays.
P.P.S. You should avoid unnecessary dynamic allocation. Your example doesn't demonstrate any need to allocate the pointed objects dynamically. So, in this case you should probably use std::vector<Obj2>.

why vector pointer's memory automatically cleared

BS: I've tested, the question below is VS2010 specific, in my test on Mingw, vector memory is leak, the
printf("%d\n", testV->size());
gives me '10', which shows it's a leak.
In codes like below:
class Test{
public:
std::vector<int> *num;
int *n;
};
Test *t = new Test();
t->num = new std::vector<int>;
t->num->assign(10,10);
t->n = new int[20];
t->n[0] = 12345;
int *testN = t->n;
std::vector<int> *testV;
testV = t->num;
delete t;
//I can print n's memory
printf("%d\n", testN[0]); //get 12345, so memory leaked here.
//I can't print num's memory; its size is 0. in release version, it's negative number.
printf("%d\n", testV->size());
After deleting t, I see that the memory num points to is cleared, in my VS10 environment, I could see its memory cleaned to 'ee fe ee fe....'.
But the memory of n stays the same.
In my opinion, all memory comes from keyword new, should be freed by delete, well, here the num (vector) is
not 'delete'd, but rather is cleared automatically.
I want to know how vector pointer is different from other ones?
Only t's memory is released, what the members num and n point to is leaked memory.
Your test is wrong, because you can't inspect t after you've deleted it, and there are no other ways to access those members (ergo the leak).
The debug runtime will overwrite memory it deletes with a marker like eefe to detect bugs like use-after-free. A release build will not do this.
You are probably just misreading the debug output. Both the vector* and the int* memory will still be around. The debugger is probably just trying to be smarter about vectors.
If you want to do this correctly, you need to delete [] t->n; and delete t->num; before you do delete t; - but a more correct way, using object orientation "correctly", would be to let t's constructor and destructor handle the memory allocation and freeing of n and num - with that, automatically, the memory is managed correctly for the class itself.
I would also point out that it's rarely right to use a pointer to a std::vector - the vector itself doesn't take up that much space, so you probably should use std::vector<int> num; instead of a pointer to it. This would also mean that num is automatically destroyed in the destructor without any additional code required.

double free or corruption while deleting an object (another one...)

The code below move the an element to top of an array
for ( i = j; i > 0; i-- ) {
myBlk *tmp = blks[i];
blks[i] = blks[i-1];
blks[i-1] = tmp;
delete tmp;
}
as the execution reaches delete tmp, I get:
*** glibc detected *** double free or corruption (out): 0x00007fffd556ad10 ***
If I remove that statement, there is no problem. But I don't want memory to leak...
tmp is just pointing to an existing element of the array. You have not allocated tmp via new. So there is no need to delete tmp. I am assuming that the original array elements are allocated and freed in somewhere else.
Promoting comment to answer.
It seems that you are confusing a memory allocation with a pointer copy. In your loop, you are not doing any memory allocation. You are just copying a pointer - which does not allocate memory.
So you should get rid of the delete:
for ( i = j; i > 0; i-- ) {
myBlk *tmp = blks[i];
blks[i] = blks[i-1];
blks[i-1] = tmp;
}
delete is only called when there is memory allocation - which you have none of. (none inside the loop at least)
This code looks very, very odd.
My guess (based on your comment that "A pointer is created in a loop and at the end of loop, i delete that.") I suspect that the delete is superfluous.
When you call delete tmp, this frees blks[i-1], since both tmp and blks[i-1] point to the same memory. If you expect that at the end of the loop blks continues to contain valid pointers, then the delete is certainly superfluous.
You are deleting the same element every time?
You move the deleted element to what was i-1 then decrement i.

How to release the memory of structures pointed by an pointer-array?

I have a pointer array defined as some_struct * t_ptr[1000] which points to a structure some_struct.And some points of the point array are evaluated.e.g
some_struct * wpaper1 = new some_struct(); //memory leaks detected in this line
wpaper1->tAnswer = useransw;
wpaper1->tKey = key;
t_ptr[100] = wpaper1;
//there're wpaper2,wpaper3....
...
delete[] t_ptr; //release the pointers
The debug message says there're memory leaks detected in the first line code.So how can I release the memory of some_struct pointed by the t_ptr array?Do I have to use a loop to detect whether a element is evaluated and then delete it?And I'm using VS2008 on Windows.Thanks.
Your delete[] t_ptr would only be correct if you've allocated t_ptr on the heap, ala:
some_struct* t_ptr = new tpr[1000];
Then, the delete[] statement releases the memory for those 1000 pointers, but does nothing about any memory that the pointers themselves may refer to. To release that, you need to first loop over the t_ptr elements, deleting them one by one:
for (i = 0; i < 1000; ++i)
delete t_ptr[i];
delete[] t_ptr;
You must ensure the pointers are set to NULL initially, though deleting a NULL pointer is a no-operation so you don't need to check in the loop above.
It's a pain isn't it? That's why a very good guideline for new C++ programmers is to use vectors and smart pointers (e.g. from boost). Those types free themselves when they go out of scope or the program exits... you don't even have to think about it.
Yes, you have to iterate over t_ptr, and delete any elements that are non-NULL (assuming you've initialized the elements to NULL before you start allocating). You should be able to identify in your code where each delete is that matches each new.