I am having a bizarre error in assigning values in an array of strings. It assigns two or three intermittently and then crashes.
I am trying to implement a simple unsorted dictionary like structure using two parallel arrays(one of strings and one of integers)
Here is where in the code I think the fault is occurring.
std::ifstream infile1("out1.tmp");
std::string word;
while (getline(infile1,word)){
std::istringstream iss(word);
printf("stream created\n");
if (!(iss >> bookone.keys[i]))
break;
i++;
}
bookone is a dictionary object that has the public fields:keys and index. Even if I move the variable assignment into the class it errors in the same way.
The part that confuses me the most is that it appears to work the first few iterations.
strace provides this:
open("out1.tmp", O_RDONLY) = 5
read(5, "This\nEtext\nfile\nis\npresented\nby\n"..., 8191) = 8191
write(1, "stream created\n", 15stream created
) = 15
write(1, "stream created\n", 15stream created
) = 15
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0xd36ff8} ---
+++ killed by SIGSEGV +++
[1] 16430 segmentation fault strace ./book macbeth.txt othello.txt
and valgrind gives me a bunch of these:
==16499== Invalid read of size 8
==16499== at 0x4EAB634: std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char>, std::allocator<char> >(std::basic_istream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
==16499== by 0x401673: main (in /home/luna/sauce/books/book)
==16499== Address 0x5a00ca8 is 24 bytes before a block of size 568 alloc'd
==16499== at 0x4C28C20: malloc (vg_replace_malloc.c:296)
==16499== by 0x56C106C: __fopen_internal (iofopen.c:73)
==16499== by 0x401555: main (in /home/luna/sauce/books/book)
Related
I use Crypto++ (libcrypto++ 1.11) to embed JWT in my application. I made methods to sign and verify messages with CryptoPP::ECDSA<CryptoPP::ECP, CryptoPP::SHA256> algorithm (with secp256r1 curve). Tokens for verification can come from the outer world, so I need to verify token contents (textual data) signature knowing the public key.
The problem is that Crypto++ can cause SegFault on invalid signatures, which gives me a lot of pain in my web server.
I hoped that signatures in BER format (default serialization format in the library) have fixed length, so all I need is to compare the length of signature with some constant. However, I found out larger contents enables larger signatures, so a deeper approach is needed.
bool ES256Verifier::Verify(const std::string& data,
const std::string& signature) {
bool result = false;
try {
CryptoPP::StringSource ss(
signature + data, true,
new CryptoPP::SignatureVerificationFilter(
verifier_,
new CryptoPP::ArraySink((byte*)&result, sizeof(result))));
} catch (const CryptoPP::BERDecodeErr& err) {
LOG_WARNING() << "Signature `" << signature << "` has invalid (non-BER) format";
} catch (const CryptoPP::Exception& ex) {
LOG_WARNING() << "Signature verification has failed: " << ex.what();
}
return result;
}
Verifier verifier_ is initialized correctly (and verifies tokens successfully apart from SegFaults), but given data = "" and signature = "", for example, I always get SegFault:
__memmove_avx_unaligned_erms 0x00007fb4b9da6b38
CryptoPP::ArraySink::Put2(unsigned char const*, unsigned long, int, bool) 0x00007fb4ba414fb2
CryptoPP::BufferedTransformation::ChannelPut2(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned char const*, unsigned long, int, bool) 0x00007fb4ba3acedc
CryptoPP::StringStore::CopyRangeTo2(CryptoPP::BufferedTransformation&, unsigned long long&, unsigned long long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool) const 0x00007fb4ba414e02
CryptoPP::BufferedTransformation::Peek(unsigned char*, unsigned long) const 0x00007fb4ba3ad74a
CryptoPP::Integer::Decode(CryptoPP::BufferedTransformation&, unsigned long, CryptoPP::Integer::Signedness) 0x00007fb4ba45885c
CryptoPP::Integer::Decode(unsigned char const*, unsigned long, CryptoPP::Integer::Signedness) 0x00007fb4ba458c16
CryptoPP::DL_VerifierBase<CryptoPP::ECPPoint>::InputSignature pubkey.h:1560
CryptoPP::SignatureVerificationFilter::LastPut(unsigned char const*, unsigned long) 0x00007fb4ba4159a0
CryptoPP::FilterWithBufferedInput::PutMaybeModifiable(unsigned char*, unsigned long, int, bool, bool) 0x00007fb4ba418107
CryptoPP::BufferedTransformation::ChannelPut2(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned char const*, unsigned long, int, bool) 0x00007fb4ba3acedc
CryptoPP::BufferedTransformation::TransferMessagesTo2(CryptoPP::BufferedTransformation&, unsigned int&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool) 0x00007fb4ba3ad8fa
CryptoPP::BufferedTransformation::TransferAllTo2(CryptoPP::BufferedTransformation&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool) 0x00007fb4ba3adb21
CryptoPP::SourceTemplate<CryptoPP::StringStore>::PumpAll2 filters.h:1238
CryptoPP::Source::PumpAll filters.h:1182
CryptoPP::Source::SourceInitialize filters.h:1215
CryptoPP::StringSource::StringSource filters.h:1271
jwt::signature::algorithm::ES256Verifier::Verify es256_verifier.cpp:40
ES256_SignatureTest_Test::TestBody es256_test.cpp:29
...
So, is there a way to look at the data and signature and decide if this particular combination is going to cause SegFault due to invalid signature length?
Here's some sample code to determine the signature length using the Field Element, Signer and Verifier. The first output prints the element length and r||s length because r||s is the signature in P1363 format.
The second and third output just print the result of SignatureLength(). Your program should reject a signature shorter than SignatureLength(). There is no sense in even trying to verify a short signature since it is no good.
Note well: this only work for the DL_* signature schemes (based on discrete logs). It does not apply to TF_* signature schemes (based on trapdoor functions).
#include "cryptlib.h"
#include "eccrypto.h"
#include "osrng.h"
#include "oids.h"
#include <iostream>
int main(int argc, char* argv[])
{
using namespace CryptoPP;
AutoSeededRandomPool prng;
///// Element
DL_GroupParameters_EC<ECP> params(ASN1::secp256r1());
unsigned int elemLength = params.GetCurve().GetField().MaxElementByteLength();
std::cout << "Element length: " << elemLength << std::endl;
std::cout << "r||s length: " << 2*elemLength << std::endl;
///// Signer
ECDSA<ECP, SHA256>::Signer signer;
signer.AccessKey().Initialize(prng, params);
unsigned int signerLength = signer.SignatureLength();
std::cout << "Signer signature length: " << signerLength << std::endl;
///// Verifier
ECDSA<ECP, SHA256>::Verifier verifier(signer);
unsigned int verifierLength = verifier.SignatureLength();
std::cout << "Verifier signature length: " << verifierLength << std::endl;
return 0;
}
Running the program results in the following.
$ ./test.exe
Element length: 32
r||s length: 64
Signer signature length: 64
Verifier signature length: 64
And if you switch curves to ASN1::secp521r1(), then running the program results in the following.
$ ./test.exe
Element length: 66
r||s length: 132
Signer signature length: 132
Verifier signature length: 132
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.
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 valgrind is clearly correct. You need to allocate memory to buffer for it to put the file contents into.
eg
record * buffer = new record;
buffer is null. you do not allocate any storage to read into it, passing wrong size (it should be 0, not sizeof(record)) and dereference it later causing Undefined Behavior. write and read in valgrind refer to memory access, not to file read or write.
I am using libcurl in my C++ program to get data from a link. The program is getting result but whenever I do valgrind I see a huge memory leak.
This is my code:
#include <string>
#include <iostream>
#include <curl/curl.h>
#include <map>
using namespace std;
int main(){
string url_;
string paramname_;
string paramvalue_;
cout << "Enter domain name(without parameters): ";
cin >> url_;
cout << "Enter parameter name: ";
cin >> paramname_;
cout << "Enter parameter value: ";
cin >> paramvalue_;
CURL* c;
curl_global_init(CURL_GLOBAL_DEFAULT);
c = curl_easy_init();
string finalurl_ = url_ + "?" + paramname_ + "=" + paramvalue_;
cout << finalurl_ << endl;
curl_easy_setopt(c, CURLOPT_URL, finalurl_.c_str());
cout << curl_easy_perform(c);
curl_easy_cleanup(c);
curl_global_cleanup();
//free(c);
return 0;
}
This is what I get while running valgrind:
==2379== LEAK SUMMARY:
==2379== definitely lost: 7,648 bytes in 116 blocks
==2379== indirectly lost: 1,240 bytes in 27 blocks
==2379== possibly lost: 2,152 bytes in 51 blocks
==2379== still reachable: 103,874 bytes in 192 blocks
==2379== suppressed: 612,674 bytes in 228 blocks
==2379==
==2379== For counts of detected and suppressed errors, rerun with: -v
==2379== ERROR SUMMARY: 130 errors from 130 contexts (suppressed: 19 from 15)
[1] 2379 segmentation fault valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./test
One of the definitely lost places while running valgrind is:
==2379== 224 (64 direct, 160 indirect) bytes in 1 blocks are definitely lost in loss record 341 of 381
==2379== at 0x10009C232: calloc (vg_replace_malloc.c:714)
==2379== by 0x100E54BA0: realizeClass(objc_class*) (in /usr/lib/libobjc.A.dylib)
==2379== by 0x100E54C4D: realizeClass(objc_class*) (in /usr/lib/libobjc.A.dylib)
==2379== by 0x100E54C4D: realizeClass(objc_class*) (in /usr/lib/libobjc.A.dylib)
==2379== by 0x100E5A72D: getClass_impl(char const*) (in /usr/lib/libobjc.A.dylib)
==2379== by 0x100E5AAF2: object_setClass (in /usr/lib/libobjc.A.dylib)
==2379== by 0x10067B8BD: __CFInitialize (in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation)
==2379== by 0x10001D846: ImageLoaderMachO::doImageInit(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==2379== by 0x10001DC12: ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) (in /usr/lib/dyld)
==2379== by 0x1000194A9: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (in /usr/lib/dyld)
==2379== by 0x100019440: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (in /usr/lib/dyld)
==2379== by 0x100019440: ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, char const*, ImageLoader::InitializerTimingList&, ImageLoader::UninitedUpwards&) (in /usr/lib/dyld)
I am compiling the program using g++:
g++ -std=c++11 -g -o test -lcurl test.cpp
I am looking for ways to free up the memory. Any help would be appreciated.
I'm stumped. I'm working on a small data server for a school assignment, that's supposed to be communicating over sockets for this iteration. Most of it's working but I can't quite figure out what valgrind is complaining about, but here's what it all says.
valgrind says;
Conditional jump or move depends on uninitialised value(s)
at 0x4C2ABD9: strlen (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
by 0x510F0EF: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.17)
by 0x4078C9: netreq::cread() (netreq.c:120)
by 0x402585: event(void*) (simpleclient.C:166)
gdb is receiving a SIGPIPE seemingly at the same point in the process.
Here's the function that it is complaining about;
string netreq::cread()
{
char buf[255];
if(read(fd,buf, 255) < 0)
cout << "I cants read dat right, sorry"<<endl;
return (string)buf; //this is line 120 in netreq.c
}
thoughts? anyone fixed something similar? i've tried quite a few things but no luck yet.
read() does not terminate the array by \0 to indicate the end. You should do it by yourself.
int len;
if ((len = read(fd, buf, 255)) < 0) {
/* ... */
} else {
buf[len] = '\0';
}
return string(buf);
About once every three times I run my program, malloc reports a double free error; e.g.
myprogram(703,0xb06d9000) malloc: *** error for object 0x17dd0240: double free
*** set a breakpoint in malloc_error_break to debug
I've run the same code through valgrind more than a dozen times but it never reports a double free.
I ran the code through gdb with a breakpoint on malloc_error_break and (when the bug occurs) the error is always reported in a standard c++ library function. I isolated the parent function and valgrinded it in a test unit but no errors.
I think the parent function/standard c++ library is not to blame, it is simply freeing something it allocated but some other function in the parent program freed.
I've tried looking up which object is double freed but my gdb skills aren't up to finding the first object that was freed. Please help me find which object caused the first free and additionally any help to why my progam generates this error. Thank you.
The parent function boils down to:
int i;
double px, py;
int start, finish;
std::string comment;
std::vector<double> x, y;
std::fstream myfile;
myfile.open("filename.txt", std::ios_base::in);
// Read header
std::getline(myfile, comment);
// Read data
while(!myfile.eof())
{
myfile >> comment >> start >> comment >> finish;
for(i = 0; i <= finish-start; i++)
{
myfile >> px >> py; // double free here
x.push_back(px);
y.push_back(py);
}
}
EDIT:
My data file is something like this:
Comment: My Data
start 33 end 36
10.2 139.0076
9.22616 141.584
8.62802 141.083
8.87098 141.813
start 33 end 35
300.354 405
301.698 404.029
303.369 403.953
start 33 end 35
336.201 148.07
334.616 147.243
334.735 146.09
The backtrace from gdb is
(gdb) backtrace
#0 0x93c2d4a9 in malloc_error_break ()
#1 0x93c28497 in szone_error ()
#2 0x93b52503 in szone_free ()
#3 0x93b5236d in free ()
#4 0x93b51f24 in localeconv_l ()
#5 0x93c18163 in strtod_l$UNIX2003 ()
#6 0x93c192e0 in strtod$UNIX2003 ()
#7 0x919b76e8 in std::__convert_to_v<double> ()
#8 0x919983cf in std::num_get<char, std::istreambuf_iterator<char, std::char_traits<char> > >::do_get ()
#9 0x91991671 in std::num_get<char, std::istreambuf_iterator<char, std::char_traits<char> > >::get ()
#10 0x9198d2dc in std::istream::operator>> ()
Just to reiterate, I need help to find which object was freed the first time, I'm not so interested in refactoring my code for this function - which I don't believe is causing the problem; unless you can find something catastrophic in it.
EDIT: Changed the example code.
You appear to be using Mac OSX (you should have divulged that fact :-)
There are several environment variables which can help you debug heap corruption.
In particular, MallocStackLoggingNoCompact looks very promising.
Here is what I see:
$ cat t.c
int main()
{
char *p = strdup("hello");
free(p);
free(p);
return 0;
}
$ gdb ./a.out
GNU gdb 6.3.50-20050815 (Apple version gdb-967) (Tue Jul 14 02:11:58 UTC 2009)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-apple-darwin"...Reading symbols for shared libraries ... done
(gdb) set env MallocStackLoggingNoCompact 1
(gdb) b malloc_error_break
Breakpoint 1 at 0x13f44a9
(gdb) r
Starting program: /Users/emp-russian/a.out
bash(22634) malloc: recording malloc stacks to disk using standard recorder
bash(22634) malloc: stack logging compaction turned off; size of log files on disk can increase rapidly
bash(22634) malloc: process 22536 no longer exists, stack logs deleted from /tmp/stack-logs.22536.a.out.8D3VZO
bash(22634) malloc: stack logs being written into /tmp/stack-logs.22634.bash.kjFTGa
arch(22634) malloc: recording malloc stacks to disk using standard recorder
arch(22634) malloc: stack logging compaction turned off; size of log files on disk can increase rapidly
arch(22634) malloc: stack logs deleted from /tmp/stack-logs.22634.bash.kjFTGa
arch(22634) malloc: stack logs being written into /tmp/stack-logs.22634.arch.8L8iLX
Reading symbols for shared libraries ++. done
Breakpoint 1 at 0x909b54a9
a.out(22634) malloc: recording malloc stacks to disk using standard recorder
a.out(22634) malloc: stack logging compaction turned off; size of log files on disk can increase rapidly
a.out(22634) malloc: stack logs deleted from /tmp/stack-logs.22634.arch.8L8iLX
a.out(22634) malloc: stack logs being written into /tmp/stack-logs.22634.a.out.s1qQRw
a.out(22634) malloc: *** error for object 0x100080: double free
*** set a breakpoint in malloc_error_break to debug
Breakpoint 1, 0x909b54a9 in malloc_error_break ()
(gdb) shell ls -l /tmp/stack-logs.22634.a.out.s1qQRw
total 16
-rw------- 1 emp-russian wheel 96 Sep 12 09:42 stack-logs.index
-rw------- 1 emp-russian wheel 208 Sep 12 09:42 stack-logs.stacks
(gdb) shell malloc_history 22634 0x100080
This first part of the history we don't actually care about:
Call [2] [arg=24]: thread_a0103720 |_dyld_start | dyldbootstrap::start(mach_header const*, int, char const**, long) | dyld::_main(mach_header const*, unsigned long, int, char const**, char const**, char const**) | dyld::initializeMainExecutable() | ImageLoader::runInitializers(ImageLoader::LinkContext const&) | ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int) | ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int) | ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int) | ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) | libSystem_initializer | __keymgr_initializer | _dyld_register_func_for_add_image | dyld::registerAddCallback(void (*)(mach_header const*, long)) | dwarf2_unwind_dyld_add_image_hook | calloc | _malloc_initialize | malloc_set_zone_name | malloc_zone_malloc | __disk_stack_logging_log_stack | reap_orphaned_log_files | opendir$INODE64$UNIX2003 | __opendir2$INODE64$UNIX2003 | telldir$INODE64$UNIX2003 | malloc | malloc_zone_malloc
Call [4] [arg=0]: thread_a0103720 |_dyld_start | dyldbootstrap::start(mach_header const*, int, char const**, long) | dyld::_main(mach_header const*, unsigned long, int, char const**, char const**, char const**) | dyld::initializeMainExecutable() | ImageLoader::runInitializers(ImageLoader::LinkContext const&) | ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int) | ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int) | ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int) | ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) | libSystem_initializer | __keymgr_initializer | _dyld_register_func_for_add_image | dyld::registerAddCallback(void (*)(mach_header const*, long)) | dwarf2_unwind_dyld_add_image_hook | calloc | _malloc_initialize | malloc_set_zone_name | malloc_zone_malloc | __disk_stack_logging_log_stack | reap_orphaned_log_files | closedir$UNIX2003 | _reclaim_telldir | free | malloc_zone_free
But here is the interesting stuff:
Call [2] [arg=6]: thread_a0103720 |0x1 | start | main | strdup | malloc | malloc_zone_malloc
Call [4] [arg=0]: thread_a0103720 |0x1 | start | main | free | malloc_zone_free
Call [4] [arg=0]: thread_a0103720 |0x1 | start | main | free | malloc_zone_free
I am currently trying to track down a "trying to free unallocated pointer" error, also on MacOS. My error is triggered about one in fifty runs (with identical input) of the program, and, of course, it has never happened when I've been running it the debugger (sigh).
What I describe below is a convenient way to get a backtrace on that rare occasion when the bug is triggered, without having to interact with gdb on each run. It is an alternative to EmployedRussian's excellent tips.
Use the following gdb command file:
# malloc_error_break.gdb
break malloc_error_break
run # Add program arguments here
backtrace
Run gdb, executing the command file, like this:
gdb -x malloc_error_break.gdb --batch my_program
If the program runs without hitting the freeing problem, it will print "No stack" in response to the backtrace command, then gdb will exit (thanks to the --batch option).
If the program hits the freeing error, I will (hopefully!) get a stack before gdb exits.
This line:
myfile >> comment
will only read "Comment:" and not the entire line "Comment: My Data". The next thing read from myfile after that line will be "my", which will likely cause problems.
In particular, the first time through the outer loop, it will attempt to read the string "Data" into start, and will be unable to do so (since it can't be parsed as an integer). So the statement:
myfile >> comment >> start >> comment >> finish;
will abort and both start and finish will be left uninitialized.
Depending on the (arbitrary) uninitialized values of start and finish, this could easily make your inner loop infinite. Inserting an infinite number of elements into a vector is likely to lead to strange behavior, although I don't see the crash that you do... it just runs for a very long time and I kill it because I run out of patience.
However, when I work around this bug by removing "My Data" from the first line, I can run your program 10,000 times without a crash.
try running gdb, cont to the crash point, then print the backtrace (type bt); see if that helps you point out where the problem is (note, you have to compile your program in debugging mode, g++ -g, to print a legible backtrace).
EDIT:
On most machine, when you free/delete a memory location the pointer you're freeing is not NULL-ed. At the point where you're free-ing the memory for the second time, try adding a "= NULL", i.e.:
delete myPointer;
myPointer = NULL;
that does NOT fix the problem; however, it will isolate the possibility that the first free()/delete is also that exact same line (but on a previous execution, say, if you're on a loop).
btw, your code snippet doesn't contain any dynamically allocated memory (apart from std::string, which internally allocate memory dynamically).
Have you taken a look into what is the value of start and finish and whether the file has enough contents to fill in vectors x and y?
A better approach would be to re-factor the looping logic -- you should break the moment you hit file EOF. At this point you have left it to faith.