简体   繁体   中英

double free or corruption while reading/writing from file

Here's my code:

#include <iostream>
#include <string>
#include <fstream>

using namespace std;

class student{
private:
    string nm, addr;
    int roll;
public:
    student(string name="a", string address="a", int rollnumber=0):
    nm(name), addr(address), roll(rollnumber){}
    void show(){
        cout<<nm<<endl<<addr<<endl<<roll<<endl;
    }
};

int main(){
    fstream file1;
    file1.open("obj.file", ios::in|ios::out|ios::binary|ios::ate);
    student s1("cipher", "MyAddress", 21);
    student s2;
    file1.write(reinterpret_cast<char *>(&s1), sizeof(s1));
    file1.flush();
    file1.seekg(0,ios::beg);
    file1.read(reinterpret_cast<char *>(&s2), sizeof(s2));
    s2.show();
    return 0;
}

And here's what happened. I could not get any lead why did the error occur?

$ ./fh2 
cipher
MyAddress
21
*** Error in `./fh2': double free or corruption (fasttop): 0x08e14178 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x767c2)[0xb756f7c2]
/lib/i386-linux-gnu/libc.so.6(+0x77510)[0xb7570510]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x1f)[0xb7713a3f]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSs4_Rep10_M_destroyERKSaIcE+0x1b)[0xb777845b]
/usr/lib/i386-linux-gnu/libstdc++.so.6(+0x4671a)[0xb771171a]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSsD1Ev+0x2e)[0xb77784be]
./fh2[0x804902d]
./fh2[0x8048dc0]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0xb7512905]
./fh2[0x8048a91]
======= Memory map: ========
08048000-0804a000 r-xp 00000000 08:05 2793609    /home/cipher/cipher-codes/practice-for-cpp-exam/fh2
0804a000-0804b000 r--p 00001000 08:05 2793609    /home/cipher/cipher-codes/practice-for-cpp-exam/fh2
0804b000-0804c000 rw-p 00002000 08:05 2793609    /home/cipher/cipher-codes/practice-for-cpp-exam/fh2
08e12000-08e33000 rw-p 00000000 00:00 0          [heap]
b74b4000-b74b6000 rw-p 00000000 00:00 0 
b74b6000-b74f7000 r-xp 00000000 08:05 11707309   /lib/i386-linux-gnu/libm-2.17.so
b74f7000-b74f8000 r--p 00040000 08:05 11707309   /lib/i386-linux-gnu/libm-2.17.so
b74f8000-b74f9000 rw-p 00041000 08:05 11707309   /lib/i386-linux-gnu/libm-2.17.so
b74f9000-b76a7000 r-xp 00000000 08:05 11707258   /lib/i386-linux-gnu/libc-2.17.so
b76a7000-b76a9000 r--p 001ae000 08:05 11707258   /lib/i386-linux-gnu/libc-2.17.so
b76a9000-b76aa000 rw-p 001b0000 08:05 11707258   /lib/i386-linux-gnu/libc-2.17.so
b76aa000-b76ae000 rw-p 00000000 00:00 0 
b76ae000-b76c9000 r-xp 00000000 08:05 11706373   /lib/i386-linux-gnu/libgcc_s.so.1
b76c9000-b76ca000 r--p 0001a000 08:05 11706373   /lib/i386-linux-gnu/libgcc_s.so.1
b76ca000-b76cb000 rw-p 0001b000 08:05 11706373   /lib/i386-linux-gnu/libgcc_s.so.1
b76cb000-b77a8000 r-xp 00000000 08:05 8300861    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.18
b77a8000-b77ac000 r--p 000dc000 08:05 8300861    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.18
b77ac000-b77ad000 rw-p 000e0000 08:05 8300861    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.18
b77ad000-b77b4000 rw-p 00000000 00:00 0 
b77ca000-b77ce000 rw-p 00000000 00:00 0 
b77ce000-b77cf000 r-xp 00000000 00:00 0          [vdso]
b77cf000-b77ef000 r-xp 00000000 08:05 11707234   /lib/i386-linux-gnu/ld-2.17.so
b77ef000-b77f0000 r--p 0001f000 08:05 11707234   /lib/i386-linux-gnu/ld-2.17.so
b77f0000-b77f1000 rw-p 00020000 08:05 11707234   /lib/i386-linux-gnu/ld-2.17.so
bfd7c000-bfd9d000 rw-p 00000000 00:00 0          [stack]
[1]    24855 abort (core dumped)  ./fh2

You're copying s1 to s2 (and it's associated data members) byte-for-byte. That works for POD (plain old data) types, but that is not guaranteed to work for complex types. Your strings cannot be copied in this manner. When their destructors run they will likely be trying to deallocate the same piece of memory (their internal data stores), ie, a double delete .

You're circumventing the copy mechanism that the string class has in place precisely to avoid this sort of scenario. It's no different than calling memcpy or something similar. Won't work. You simply cannot persist non-POD types like this.

Even if you didn't get an error, it would still be wrong in a logical sense. Think about it; those strings are going to allocate their internal memory store dynamically, ie, they will store a pointer to some chunk of memory. That pointer would not be valid once the string's destructor ran, and it certainly wouldn't be valid if, say, you decided to deserialize that file a week from now.

When you write the contents of s1 you are actually copying the pointer inside the string. You then write this into s2's string. When s1 and s2 call their deconstructor they will both free the same string pointer, which is your double free.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM