adch99 adch99 - 1 year ago 103
C++ Question

Invalid write with read operation in Valgrind

For some reason Valgrind seems to give an invalid write at a line where the ifstream.read is called (in the searchInFile function). gdb seems to segfault at the same line but I can't figure out the problem. If a read function is being called, how is there a write operation taking place?

#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdlib>

#define FILENAME "./test.dat"

using namespace std;

struct record
{
long long int phoneNumber;
char name[10];
char address[75];
};

int searchInFile(long long int phoneNo)
{
/*
Search if a record with the given phone no.
exists in the file. Returns the number of
records before the required record. Returns
-1 if no such record exists.
*/

int ctr = 0;
record * buffer = NULL;
ifstream file(FILENAME, ios::binary);

while(file.read( reinterpret_cast<char*>(buffer), sizeof(record)))
{
if(buffer->phoneNumber == phoneNo)
{
file.close();
return(ctr);
}

ctr++;
}

file.close();

if(buffer->phoneNumber == phoneNo)
return(ctr);

return(-1);
}

void displayRecord(long long int phoneNo)
{
/*
Displays the record with given phone no.
*/

int location = searchInFile(phoneNo);
record * buffer = NULL;


if(location == -1)
cout << "Invalid Number! No such record exists!" << endl;

else
{
ifstream file(FILENAME, ios::binary);

cout << "Reading Error Code: " << file.read(reinterpret_cast<char*>(buffer), sizeof(record));

cout << "Phone Number: " << buffer->phoneNumber << endl;
cout << "Name: " << buffer->name << endl;
cout << "Address: " << buffer->address << endl;

file.close();
}
}

void saveRecord(record toSave)
{
/*
Saves a new record to file
*/
ofstream ofile(FILENAME, ios::app | ios::binary);
//ofile.seekp(0, ios::end);
ofile.write( reinterpret_cast<char*>(&toSave), sizeof(record));
ofile.close();
}


int main()
{
record test = {(long long int)9988776655, "Debug", "Address of Debugger"};
saveRecord(test);
displayRecord((long long int) 9988776655);
return(0);
}


Here is the Valgrind and gdb output for it:

Syscall param write(buf) points to uninitialised byte(s)
at 0x543B870: __write_nocancel (syscall-template.S:81)
by 0x4EB18D5: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EE9A77: std::basic_filebuf<char, std::char_traits<char> >::_M_convert_to_external(char*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EEA4D2: std::basic_filebuf<char, std::char_traits<char> >::overflow(int) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EE9CA2: std::basic_filebuf<char, std::char_traits<char> >::_M_terminate_output() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EE9D4A: std::basic_filebuf<char, std::char_traits<char> >::close() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EEBB4C: std::basic_ofstream<char, std::char_traits<char> >::close() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4011A5: saveRecord(record) (test.cpp:84)
by 0x4012F1: main (test.cpp:91)
Address 0x5a1b31d is 93 bytes inside a block of size 8,192 alloc'd
at 0x4C2B8A8: operator new[](unsigned long) (vg_replace_malloc.c:423)
by 0x4EE98AB: std::basic_filebuf<char, std::char_traits<char> >::_M_allocate_internal_buffer() (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EE9EC1: std::basic_filebuf<char, std::char_traits<char> >::open(char const*, std::_Ios_Openmode) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EEB747: std::basic_ofstream<char, std::char_traits<char> >::basic_ofstream(char const*, std::_Ios_Openmode) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x40117E: saveRecord(record) (test.cpp:81)
by 0x4012F1: main (test.cpp:91)

Invalid write of size 1
at 0x4ED338E: std::basic_streambuf<char, std::char_traits<char> >::xsgetn(char*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EE8D0D: std::basic_filebuf<char, std::char_traits<char> >::xsgetn(char*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EB4CAA: std::istream::read(char*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x400EDD: searchInFile(long long) (test.cpp:30)
by 0x400FAA: displayRecord(long long) (test.cpp:55)
by 0x401300: main (test.cpp:92)
Address 0x0 is not stack'd, malloc'd or (recently) free'd


Process terminating with default action of signal 11 (SIGSEGV)
Access not within mapped region at address 0x0
at 0x4ED338E: std::basic_streambuf<char, std::char_traits<char> >::xsgetn(char*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EE8D0D: std::basic_filebuf<char, std::char_traits<char> >::xsgetn(char*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x4EB4CAA: std::istream::read(char*, long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
by 0x400EDD: searchInFile(long long) (test.cpp:30)
by 0x400FAA: displayRecord(long long) (test.cpp:55)
by 0x401300: main (test.cpp:92)
If you believe this happened as a result of a stack
overflow in your program's main thread (unlikely but
possible), you can try to increase the size of the
main thread stack using the --main-stacksize= flag.
The main thread stack size used in this run was 8388608.

HEAP SUMMARY:
in use at exit: 8,760 bytes in 2 blocks
total heap usage: 4 allocs, 2 frees, 17,520 bytes allocated

LEAK SUMMARY:
definitely lost: 0 bytes in 0 blocks
indirectly lost: 0 bytes in 0 blocks
possibly lost: 0 bytes in 0 blocks
still reachable: 8,760 bytes in 2 blocks
suppressed: 0 bytes in 0 blocks

ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)


Note that the test.dat file was deleted before each run.

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7b7338e in std::basic_streambuf<char, std::char_traits<char> >::xsgetn(char*, long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
(gdb) bt
#0 0x00007ffff7b7338e in std::basic_streambuf<char, std::char_traits<char> >::xsgetn(char*, long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1 0x00007ffff7b88d0e in std::basic_filebuf<char, std::char_traits<char> >::xsgetn(char*, long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#2 0x00007ffff7b54cab in std::istream::read(char*, long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3 0x0000000000400ede in searchInFile (phoneNo=9988776655) at test.cpp:30
#4 0x0000000000400fab in displayRecord (phoneNo=9988776655) at test.cpp:55
#5 0x0000000000401301 in main () at test.cpp:92


The only thing I can think of is that
buffer
is being written into over here, but that doesn't get me anywhere.

Answer Source

The read() method is writing the information it has read into your buffer, and I suspect valgrind thinks this write is invalid, so start looking at how your buffer is allocated.

In this case it is clearly correct. You need to allocate memory to buffer for it to put the file contents into.

eg

record * buffer = new record;
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download