double free or corruption (out) when file.close() is reached

the code below is part of a library I am implementing. Either the library and the executable using this library are build with no errors or warnings, but when I try execute the code, the error "double free or corruption (out)" is throw when the program reaches the line file.close() in the end of this function (all the data is correctly read by the function). Anyone can anything wrong with this method?

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
void Bitmap::read_file(const char * file_name) {
  fstream file(file_name, ios_base::in);

  if (file.is_open()) {
    string line_one, line_two, line_pixels;

    while(getline(file, line_one)) {
      if(line_one.at(0) != '#') {
        if(line_one == "P1")
          this->magicNumber = P1;
        else
          this->magicNumber = P4;
        break;
      }
    }

    while(getline(file, line_two)) {
      string width, height;
      stringstream ss(line_two);

      if(line_two.at(0) != '#') {
        if(getline(ss, width, ' '))
          this->width = stoi(width);

        if(getline(ss, height, ' '))
          this->height = stoi(height);

        break;
      }
    }

    if(this->magicNumber == P1) {
      this->pixels = new Matrix<int>(this->width, this->height);

      vector<int> p;
      while(getline(file, line_pixels)) {
        if(line_pixels.size() > 0 && line_pixels.at(0) != '#') {
          string number;
          stringstream ss(line_pixels);
          while(getline(ss, number, ' ')) {
            int data = stoi(number);
            p.push_back(data);
          }
        }
      }

      int count = 0;
      for(int i=0; i<height; i++) {
        for(int j=0; j<width; j++) {
          this->pixels->set(i, j, p[count++]);
        }
      }
    }

    if(this->magicNumber == P4) {
      this->pixels = new Matrix<int>(this->width, this->height);

      vector<int> p;
      int size = width * height;
      for(int i=0; i<size; i++) {
        char byte[1];
        file.read(byte, 1);
        unsigned char c = (unsigned char)byte[0];
        for(int x=0; x != 8; x++)
          p.push_back( (c & (1 << x)) != 0 );
      }

      int count = 0;
      for(int i=0; i<height; i++) {
        for(int j=0; j<width; j++) {
          this->pixels->set(i, j, p[count++]);
        }
      }
    }
  }

  file.close();
}
Last edited on
That all looks good to me, except that you'll insert a total of 8*size items into p at line 65, but you only extract "size" items at line 71.

It's possible that the heap corruption occurs earlier in your program and isn't detected until line 77.
Yes, this part seems that need to be fixed, but the error occurs even when the execution do not reach this part (magicNumber != P4. gdb do not indicate very precisely where the corruption occurs. I already tried valgrind and -fsanitize=address, and I cannot find this source. Any other ideas to do that?
output of the gdb run:

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
(gdb) run
Starting program: /media/kleber/Disco/GitHub/game/release/game2d /home/kleber/Imagens/teste.pbm
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
double free or corruption (out)

Program received signal SIGABRT, Aborted.
__pthread_kill_implementation (no_tid=0, signo=6, threadid=140737344042816) at ./nptl/pthread_kill.c:44
44      ./nptl/pthread_kill.c: No such file or directory.
(gdb) backtrace
#0  __pthread_kill_implementation (no_tid=0, signo=6, threadid=140737344042816) at ./nptl/pthread_kill.c:44
#1  __pthread_kill_internal (signo=6, threadid=140737344042816) at ./nptl/pthread_kill.c:78
#2  __GI___pthread_kill (threadid=140737344042816, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
#3  0x00007ffff78d8476 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4  0x00007ffff78be7f3 in __GI_abort () at ./stdlib/abort.c:79
#5  0x00007ffff791f6f6 in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7ffff7a71b8c "%s\n") at ../sysdeps/posix/libc_fatal.c:155
#6  0x00007ffff7936d7c in malloc_printerr (str=str@entry=0x7ffff7a747b0 "double free or corruption (out)") at ./malloc/malloc.c:5664
#7  0x00007ffff7938ef0 in _int_free (av=0x7ffff7aafc80 <main_arena>, p=0x5555555709c0, have_lock=<optimized out>) at ./malloc/malloc.c:4588
#8  0x00007ffff793b4d3 in __GI___libc_free (mem=mem@entry=0x5555555709d0) at ./malloc/malloc.c:3391
#9  0x00007ffff7914da7 in _IO_deallocate_file (fp=0x5555555709d0) at ./libio/libioP.h:862
#10 _IO_new_fclose (fp=0x5555555709d0) at ./libio/iofclose.c:74
#11 0x00007ffff7bb0ca0 in std::__basic_file<char>::close() () from /lib/x86_64-linux-gnu/libstdc++.so.6
#12 0x00007ffff7bf8342 in std::basic_filebuf<char, std::char_traits<char> >::close() () from /lib/x86_64-linux-gnu/libstdc++.so.6
#13 0x00007ffff7bfa041 in std::basic_fstream<char, std::char_traits<char> >::close() () from /lib/x86_64-linux-gnu/libstdc++.so.6
#14 0x00007ffff7d12761 in Bitmap::read_file (this=0x5555555709b0, file_name=0x7fffffffe1c0 "/home/kleber/Imagens/teste.pbm") at src/bitmap.cpp:99
#15 0x00007ffff7d11fe1 in Bitmap::Bitmap (this=0x5555555709b0, file_name=0x7fffffffe1c0 "/home/kleber/Imagens/teste.pbm") at src/bitmap.cpp:16
#16 0x000055555555909f in main (argc=2, argv=0x7fffffffde28) at src/Main.cpp:24
output for valgrind command: https://pastebin.com/gRGEHbji
The problem may not be related to this code, but in code that is executed earlier. However, I would include some 'sanity' checks in the given code. eg L47, L68 - is the size of p at least height * width?

What are the args for Matrix? When created it uses (width, height), but when accessed it uses (height, width) ?? May be right, but just seems inconsistent.

This may help to localise the error:

1
2
3
4
5
6
7
8
9
10
11
12
13
void Bitmap::read_file(const char * file_name) {

    // fstream file(file_name, ios_base::in);

    // open file
    std::filebuf fbuf ;
    char buffer[1024*16] {} ;
    fbuf.pubsetbuf( buffer, sizeof(buffer) ) ;
    fbuf.open( file_name, std::ios_base::in ) ;
    std::istream file( std::addressof(fbuf) ) ;

    // use (read from) file
    // ... 
This gave me the same output when running gdb and command backtrace from before. What the new code is doing exactly, and Do I need execute some other command to visualize the result it could provide me?
> This gave me the same output when running gdb and command backtrace from before.

The error means that a deallocation function (eg. free) was called on the same pointer more than once. This could also mean that some area of memory (free store) is getting trashed; for example a pointer to dynamically allocated memory internally held by an object could be corrupted. (This could have happened before the function in question was entered into.) Try to verify that there is no out of bounds access to memory in the program.

> What the new code is doing exactly

The new code tries to avoid dynamic memory allocation for the stream (when it is in use) by using local objects with automatic storage duration.
It first creates a stream buffer fbuf for the file, then replaces its internal buffer with a local array of characters buffer and finally creates an input stream file which uses
fbuf as its stream buffer.
Your valgrind report says
==26715== Invalid write of size 4
==26715== at 0x4B01107: Bitmap::read_file(char const*) (bitmap.cpp:32)
==26715== by 0x4B00FE0: Bitmap::Bitmap(char*) (bitmap.cpp:16)
==26715== by 0x10D09E: main (Main.cpp:24)
==26715== Address 0x51ca238 is 0 bytes after a block of size 8 alloc'd
==26715== at 0x4849013: operator new(unsigned long) (vg_replace_malloc.c:422)
==26715== by 0x10D082: main (Main.cpp:24)
==26715==

So what are you doing at line 24 in Main.cpp?
1
2
3
4
5
6
     this->pixels = new Matrix<int>(this->width, this->height);
...
      int count = 0;
      for(int i=0; i<height; i++) {
        for(int j=0; j<width; j++) {
          this->pixels->set(i, j, p[count++]);

Have you got the height/width the wrong way round when filling the pixels matrix?

Also, valgrind can drop you into the debugger at the point it detects the first memory fault.
This allows you to inspect the cause of the first problem.
Last edited on
Which line is line 32? I'm asking because I don't think you have posted all the content of bitmap.cpp, right?
The code in Main.cpp might be relevant too.

Is read_file called through an uninitialized/dangling pointer?

Are you making copies of the Bitmap objects, and if so, have you implemented the copy constructor and copy assignment operator (correctly)?
Last edited on
Registered users can post here. Sign in or register to post.