Invalid free after reading object from file

Sep 8, 2010 at 9:44am
Hello,

I'm having trouble with a template class I've written. I'ld like to save and load the data, but my class crashes when I'm loading.
The function looks like this and works when T is a built-in datatype like double. But when I'm using a self created class, it crashes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
	
MyClass(std::string filename){
  std::ifstream input (filename.c_str(), std::ios::binary);
  if (!input){
    throw IOError(msg);
  }
  // allocate memory 
  values = new T[numberOfEntries];
  T value;
  int i =0;
//  for (int i = 0; i<numberOfEntries; i++){
  input.read((char*)&value, sizeof(T));
  values[i] = value;
//  }
  input.close();
}

The error message is an invalid free message:
*** glibc detected *** ./myProgram: free(): invalid pointer: 0x10696d70 ***

I thought this was a problem with the destructor of the class I'm using as argument, but the destructor works fine. Strange enough, if I comment out the input.read() line, the code runs fine (but doesn't do the job of course)

Thanks for some hints and ideas!
Sep 8, 2010 at 9:46am
I have to add that the code runs through and crashes when the constructor is left and the local variable 'value' is destroyed.
Sep 8, 2010 at 9:48am
closed account (EzwRko23)

but the destructor works fine


In C and C++, if some part of the code happens to work fine, it doesn't actually mean it is correct. It may crash, if you change something elsewhere, even if it seems to be completely unrelated.


So, are you really sure the constructor / destructor is ok? Are you sure there is no other bug in the program? Often C++ programs crash many lines after the buggy instruction was executed. So the destructor might not be the problem.

Try running your progam under valgrind. It gives much more info than glibc.

Last edited on Sep 8, 2010 at 9:50am
Sep 8, 2010 at 9:53am
Another thing I tried was to formulate this as a non-template class. The problem remains the same. There must be some point where value is already destroyed so there is an error when it is destroyed a second time.
Sep 8, 2010 at 9:54am
The destructor of my class really has nothing to do as there is no memory allocated in the class.
Sep 8, 2010 at 11:01am
Ok, I've written a mini-example that crashes. It also does not crash when I comment out the in.read(..) line. Maybe there is something wrong with the boost-vector destructor?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <fstream>
#include <string>
#include <boost/numeric/ublas/vector.hpp>

namespace ublas = boost::numeric::ublas;


class myTestClass {
public:
	myTestClass() {
		v = ublas::vector<double> (6);
	}
private:
	ublas::vector<double> v;
};


int main (int argc, const char* argv[]){

	myTestClass objectToSave;
	std::string filename ("testfile.dat");

	std::ofstream out (filename.c_str(), std::ios::binary);

	out.write((char*)&objectToSave, sizeof(myTestClass));

	out.close();

	std::cout << "File written.\n";

	myTestClass h;

	std::ifstream in (filename.c_str(), std::ios::binary);

	in.read((char*)&h, sizeof(myTestClass));

	in.close();

	std::cout << "Object loaded.\n";
}


The output is
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
File written.
Object loaded.
*** glibc detected *** ./test: double free or corruption (fasttop): 0x096d8040 ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6[0xb75e10d1]
/lib/tls/i686/cmov/libc.so.6[0xb75e27d2]
/lib/tls/i686/cmov/libc.so.6(cfree+0x6d)[0xb75e58ad]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0xb77b86f1]
./test[0x80491d5]
./test[0x8049083]
./test[0x8048f19]
./test[0x8048fd3]
./test[0x8048e2a]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xb758cb56]
./test[0x8048ba1]
Last edited on Sep 8, 2010 at 11:03am
Sep 8, 2010 at 11:08am
Ok, it is not a problem with the boost library. This example also crashes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

class myTestClass {
public:
	myTestClass() {
		v = std::vector<double>();
		v.push_back(1.3f);
	}
private:
	std::vector<double> v;
};


int main (int argc, const char* argv[]){

	myTestClass objectToSave;
	std::string filename ("testfile.dat");

	std::ofstream out (filename.c_str(), std::ios::binary);

	out.write((char*)&objectToSave, sizeof(myTestClass));

	out.close();

	std::cout << "File written.\n";

	myTestClass h;

	std::ifstream in (filename.c_str(), std::ios::binary);

	in.read((char*)&h, sizeof(myTestClass));

	in.close();

	std::cout << "Object loaded.\n";
}


This is the output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
==19959== Memcheck, a memory error detector
==19959== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==19959== Using Valgrind-3.5.0-Debian and LibVEX; rerun with -h for copyright info
==19959== Command: ./test
==19959== 
File written.
Object loaded.
==19959== Invalid free() / delete / delete[]
==19959==    at 0x402454D: operator delete(void*) (vg_replace_malloc.c:346)
==19959==    by 0x8049A46: __gnu_cxx::new_allocator<double>::deallocate(double*, unsigned int) (new_allocator.h:95)
==19959==    by 0x8049598: std::_Vector_base<double, std::allocator<double> >::_M_deallocate(double*, unsigned int) (stl_vector.h:146)
==19959==    by 0x8049409: std::_Vector_base<double, std::allocator<double> >::~_Vector_base() (stl_vector.h:132)
==19959==    by 0x80490C4: std::vector<double, std::allocator<double> >::~vector() (stl_vector.h:313)
==19959==    by 0x8049074: myTestClass::~myTestClass() (MDAVSphericalHarmonicsSeriesSaveTest.cpp:10)
==19959==    by 0x8048F29: main (MDAVSphericalHarmonicsSeriesSaveTest.cpp:42)
==19959==  Address 0x42be028 is 0 bytes inside a block of size 8 free'd
==19959==    at 0x402454D: operator delete(void*) (vg_replace_malloc.c:346)
==19959==    by 0x8049A46: __gnu_cxx::new_allocator<double>::deallocate(double*, unsigned int) (new_allocator.h:95)
==19959==    by 0x8049598: std::_Vector_base<double, std::allocator<double> >::_M_deallocate(double*, unsigned int) (stl_vector.h:146)
==19959==    by 0x8049409: std::_Vector_base<double, std::allocator<double> >::~_Vector_base() (stl_vector.h:132)
==19959==    by 0x80490C4: std::vector<double, std::allocator<double> >::~vector() (stl_vector.h:313)
==19959==    by 0x8049074: myTestClass::~myTestClass() (MDAVSphericalHarmonicsSeriesSaveTest.cpp:10)
==19959==    by 0x8048EB7: main (MDAVSphericalHarmonicsSeriesSaveTest.cpp:42)
==19959== 
==19959== 
==19959== HEAP SUMMARY:
==19959==     in use at exit: 8 bytes in 1 blocks
==19959==   total heap usage: 7 allocs, 7 frees, 17,129 bytes allocated
==19959== 
==19959== 8 bytes in 1 blocks are definitely lost in loss record 1 of 1
==19959==    at 0x4025390: operator new(unsigned int) (vg_replace_malloc.c:214)
==19959==    by 0x8049CF1: __gnu_cxx::new_allocator<double>::allocate(unsigned int, void const*) (new_allocator.h:89)
==19959==    by 0x8049A0B: std::_Vector_base<double, std::allocator<double> >::_M_allocate(unsigned int) (stl_vector.h:140)
==19959==    by 0x80497CC: std::vector<double, std::allocator<double> >::_M_insert_aux(__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >, double const&) (vector.tcc:322)
==19959==    by 0x80493A6: std::vector<double, std::allocator<double> >::push_back(double const&) (stl_vector.h:741)
==19959==    by 0x804903E: myTestClass::myTestClass() (MDAVSphericalHarmonicsSeriesSaveTest.cpp:14)
==19959==    by 0x8048E27: main (MDAVSphericalHarmonicsSeriesSaveTest.cpp:34)
==19959== 
==19959== LEAK SUMMARY:
==19959==    definitely lost: 8 bytes in 1 blocks
==19959==    indirectly lost: 0 bytes in 0 blocks
==19959==      possibly lost: 0 bytes in 0 blocks
==19959==    still reachable: 0 bytes in 0 blocks
==19959==         suppressed: 0 bytes in 0 blocks
==19959== 
==19959== For counts of detected and suppressed errors, rerun with: -v
==19959== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 17 from 6)
Sep 8, 2010 at 11:36am
Now if I modify the main as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main (int argc, const char* argv[]){

	myTestClass objectToSave;
	std::string filename ("testfile.dat");

	std::ofstream out (filename.c_str(), std::ios::out | std::ios::binary);

	out.write((char*)&objectToSave, sizeof(myTestClass));

	out.close();

	std::cout << "File written.\n";

	myTestClass *h = new myTestClass();

	std::ifstream in (filename.c_str(), std::ios::in | std::ios::binary);

	in.read((char*)h, sizeof(myTestClass));

	in.close();

	for (int i = 0; i<h->v.size(); i++)
		std::cout << h->v[i] << "\n";

	std::cout << "Object loaded.\n";
}

it works. But if I delete the pointer h at the end of the routine, I get the same invalid free error message. So somewhere in between the h is already deleted...
Sep 8, 2010 at 11:41am
And then again, when I use a double instead of a vector<double> in myTestClass, I am allowed to delete the h myself:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <fstream>
#include <string>

class myTestClass {
public:
	myTestClass() {
		v = 1.3f;
	}

	double v;
};


int main (int argc, const char* argv[]){

	myTestClass objectToSave;
	std::string filename ("testfile.dat");

	std::ofstream out (filename.c_str(), std::ios::out | std::ios::binary);

	out.write((char*)&objectToSave, sizeof(myTestClass));

	out.close();

	std::cout << "File written.\n";

	myTestClass *h = new myTestClass();

	std::ifstream in (filename.c_str(), std::ios::in | std::ios::binary);

	in.read((char*)h, sizeof(myTestClass));

	in.close();

	std::cout << "Object loaded.\n";
	delete h;
}


Runs without an error...
Topic archived. No new replies allowed.