I've been having a problem with allocating memory for one of my data structures. It always crashes out, but it's not always at the same place. My suspicion is that I'm trying to allocate it over the top of something that's already there, but I'm really not sure how to tell what's actually going on or how to fix it - I've tried to install valgrind, but that doesn't yet support Mac OS 10.10.
This is the code that calls the function.
stet::file f1;
f1.set_path("test/longfile1.txt"); // a file with almost 2 million lines
f1.read();
std::string all_text = f1.get_contents();
std::vector<chunk *> chunks = populate_chunks(all_text);
These are my data structures - the idea is that the text from file is split into fixed sized chunks, which are populated up to 75% capacity, but I can't seem to create all the chunks.
struct line {
std::string text;
};
struct chunk {
line *lines[MAX_CHUNK_SIZE];
};
And this is the cause of my nightmares - it crashes out on the line below all the comments.
std::vector<chunk *> populate_chunks(std::string &text) {
std::vector<std::string> all_lines;
boost::split(all_lines, text, boost::is_any_of("\n"));
size_t num_lines = all_lines.size();
std::vector<chunk *> chunks = std::vector<chunk *>( (num_lines / START_CHUNK_SIZE) * 2 );
size_t next_line_num;
for(size_t line_num = 0; line_num < num_lines; line_num = next_line_num) {
next_line_num = line_num + START_CHUNK_SIZE;
std::cout << line_num << std::endl;
chunk *c = new chunk;
chunks.push_back(c);
// This always falls over, but not always at the same point in the file.
// Never seems to be the first time. Observed range: 3072 - 59904
// Error always looks something like this:
// text(71184,0x7fff77699300) malloc: *** error for object 0x7ff389006208: incorrect checksum for freed object - object was probably modified after being freed.
// *** set a breakpoint in malloc_error_break to debug
for(size_t i = 0; i < next_line_num; ++i) {
line *l = new line;
l->text = all_lines[line_num+i];
c->lines[i] = l;
}
}
return chunks;
}
If anyone has any ideas, they'd be much appreciated - it should be noted that I'm pretty new to C++, so it's quite likely that I've missed something really stupid.
Update:
I've fiddled around with the code to change things based on the comments I've been getting:
Made chunks the function's return value, rather than a pointer
Stopped giving the all_lines vector a size on creation, allowed boost to sort that out
I also got a fedora VM up and running in order to put it through valgrind and I'm really very confused by the output.
Noted the values of MAX_CHUNK_SIZE and START_CHUNK_SIZE below.
Macro values:
#define MAX_CHUNK_SIZE 1024
#define START_CHUNK_SIZE MAX_CHUNK_SIZE * 0.75
Valgrind output after the above changes:
==24468== Memcheck, a memory error detector
==24468== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==24468== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==24468== Command: bin/text
==24468==
==24468== Invalid write of size 8
==24468== at 0x402907: populate_chunks(std::string&) (text_storage.cc:125)
==24468== by 0x402ADF: main (text_storage.cc:173)
==24468== Address 0x216b5640 is 0 bytes after a block of size 8,192 alloc'd
==24468== at 0x4C27965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24468== by 0x402888: populate_chunks(std::string&) (text_storage.cc:113)
==24468== by 0x402ADF: main (text_storage.cc:173)
==24468==
==24468==
==24468== Process terminating with default action of signal 11 (SIGSEGV)
==24468== Access not within mapped region at address 0x37D77000
==24468== at 0x402907: populate_chunks(std::string&) (text_storage.cc:125)
==24468== by 0x402ADF: main (text_storage.cc:173)
==24468== If you believe this happened as a result of a stack
==24468== overflow in your program's main thread (unlikely but
==24468== possible), you can try to increase the size of the
==24468== main thread stack using the --main-stacksize= flag.
==24468== The main thread stack size used in this run was 8388608.
==24468==
==24468== HEAP SUMMARY:
==24468== in use at exit: 371,641,698 bytes in 6,241,143 blocks
==24468== total heap usage: 6,241,190 allocs, 47 frees, 656,880,685 bytes allocated
==24468==
==24468== 16 bytes in 2 blocks are possibly lost in loss record 1 of 11
==24468== at 0x4C27965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24468== by 0x4028BC: populate_chunks(std::string&) (text_storage.cc:123)
==24468== by 0x402ADF: main (text_storage.cc:173)
==24468==
==24468== 43 bytes in 1 blocks are possibly lost in loss record 2 of 11
==24468== at 0x4C27965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24468== by 0x5340048: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x5341900: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x5341D37: 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.19)
==24468== by 0x4029F7: main (text_storage.cc:138)
==24468==
==24468== 35,727,800 (33,173,592 direct, 2,554,208 indirect) bytes in 4,146,699 blocks are definitely lost in loss record 8 of 11
==24468== at 0x4C27965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24468== by 0x4028BC: populate_chunks(std::string&) (text_storage.cc:123)
==24468== by 0x402ADF: main (text_storage.cc:173)
==24468==
==24468== 93,350,023 bytes in 1 blocks are possibly lost in loss record 9 of 11
==24468== at 0x4C27965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24468== by 0x5340048: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x5340235: std::string::_M_mutate(unsigned long, unsigned long, unsigned long) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x53403C5: std::string::_M_leak_hard() (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x5340412: std::string::begin() (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x407728: boost::range_iterator<std::string>::type boost::range_detail::range_begin<std::string>(std::string&) (begin.hpp:49)
==24468== by 0x40705D: boost::range_iterator<std::string>::type boost::range_adl_barrier::begin<std::string>(std::string&) (begin.hpp:108)
==24468== by 0x4066FC: __gnu_cxx::__normal_iterator<char*, std::string> boost::iterator_range_detail::iterator_range_impl<__gnu_cxx::__normal_iterator<char*, std::string> >::adl_begin<std::string>(std::string&) (iterator_range_core.hpp:58)
==24468== by 0x40601A: boost::iterator_range<__gnu_cxx::__normal_iterator<char*, std::string> >::iterator_range<std::string>(std::string&, boost::iterator_range_detail::range_tag) (iterator_range_core.hpp:207)
==24468== by 0x40561F: boost::iterator_range<boost::range_iterator<std::string>::type> boost::make_iterator_range<std::string>(std::string&) (iterator_range_core.hpp:559)
==24468== by 0x404BC3: boost::iterator_range<boost::range_iterator<std::string>::type> boost::range_detail::make_range<std::string>(std::string&, long) (as_literal.hpp:93)
==24468== by 0x4040E5: boost::iterator_range<boost::range_iterator<std::string>::type> boost::as_literal<std::string>(std::string&) (as_literal.hpp:102)
==24468==
==24468== 93,351,904 bytes in 1 blocks are possibly lost in loss record 10 of 11
==24468== at 0x4C27965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24468== by 0x5340048: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x5341710: char* std::string::_S_construct<char*>(char*, char*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x531F9A7: std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >::str() const (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x402523: stet::file::read() (file.cc:50)
==24468== by 0x402A2E: main (text_storage.cc:139)
==24468==
==24468== 129,441,960 bytes in 1,520,226 blocks are possibly lost in loss record 11 of 11
==24468== at 0x4C27965: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24468== by 0x5340048: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.19)
==24468== by 0x40845E: char* std::string::_S_construct<__gnu_cxx::__normal_iterator<char*, std::string> >(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, std::allocator<char> const&, std::forward_iterator_tag) (basic_string.tcc:138)
==24468== by 0x4082E8: char* std::string::_S_construct_aux<__gnu_cxx::__normal_iterator<char*, std::string> >(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, std::allocator<char> const&, std::__false_type) (basic_string.h:1725)
==24468== by 0x408177: char* std::string::_S_construct<__gnu_cxx::__normal_iterator<char*, std::string> >(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, std::allocator<char> const&) (basic_string.h:1746)
==24468== by 0x407FDA: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<__gnu_cxx::__normal_iterator<char*, std::string> >(__gnu_cxx::__normal_iterator<char*, std::string>, __gnu_cxx::__normal_iterator<char*, std::string>, std::allocator<char> const&) (basic_string.tcc:229)
==24468== by 0x407D6A: std::string boost::copy_range<std::string, boost::iterator_range<__gnu_cxx::__normal_iterator<char*, std::string> > >(boost::iterator_range<__gnu_cxx::__normal_iterator<char*, std::string> > const&) (iterator_range_core.hpp:643)
==24468== by 0x407AEA: boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >::operator()(boost::iterator_range<__gnu_cxx::__normal_iterator<char*, std::string> > const&) const (util.hpp:97)
==24468== by 0x407395: boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default>::dereference() const (transform_iterator.hpp:121)
==24468== by 0x406B72: boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default>::reference boost::iterator_core_access::dereference<boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default> >(boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default> const&) (iterator_facade.hpp:514)
==24468== by 0x40633D: boost::iterator_facade<boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default>, std::string, boost::forward_traversal_tag, std::string, long>::operator*() const (iterator_facade.hpp:639)
==24468== by 0x405895: void std::vector<std::string, std::allocator<std::string> >::_M_range_initialize<boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default> >(boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default>, boost::transform_iterator<boost::algorithm::detail::copy_iterator_rangeF<std::string, __gnu_cxx::__normal_iterator<char*, std::string> >, boost::algorithm::split_iterator<__gnu_cxx::__normal_iterator<char*, std::string> >, boost::use_default, boost::use_default>, std::input_iterator_tag) (stl_vector.h:1188)
==24468==
==24468== LEAK SUMMARY:
==24468== definitely lost: 33,173,592 bytes in 4,146,699 blocks
==24468== indirectly lost: 2,554,208 bytes in 319,276 blocks
==24468== possibly lost: 316,143,946 bytes in 1,520,231 blocks
==24468== still reachable: 19,769,952 bytes in 254,937 blocks
==24468== suppressed: 0 bytes in 0 blocks
==24468== Reachable blocks (those to which a pointer was found) are not shown.
==24468== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==24468==
==24468== For counts of detected and suppressed errors, rerun with: -v
==24468== ERROR SUMMARY: 4146708 errors from 7 contexts (suppressed: 2 from 2)
The size of the lines array in a chunk is MAX_CHUNK_SIZE, but you are accessing it far beyond that on any iteration except the first.
Your loop is for(size_t i = 0; i < next_line_num; ++i), guess what next_line_num is on your second (and beyond) iteration?
You would probably have totally avoided this problem if you had thought of another problem, which you overlooked. You only partially fill the chunks (by 75%), which makes sense. But on the last iteration you are likely to have even less lines than those needed to fill 75% of a chunk. Therefore there should be, somewhere, a test to handle this boundary. A comparison, somewhere in that loop, with num_lines. Thinking about where to put it could (but not necessarily would) have alerted you that the iteration index is not doing what you expect.
Try for(size_t i = 0; i < START_CHUNK_SIZE && line_num+i < num_lines; ++i).
For reference, this is what the final code looks like:
std::vector<chunk *> populate_chunks(std::string &text) {
std::vector<std::string> all_lines;
boost::split(all_lines, text, boost::is_any_of("\n"));
size_t num_lines = all_lines.size();
std::vector<chunk *> chunks = std::vector<chunk *>( (num_lines / START_CHUNK_SIZE) * 2 );
for(size_t next_line_num, line_num = 0; line_num < num_lines; line_num = next_line_num) {
next_line_num = line_num + START_CHUNK_SIZE;
chunk *c = new chunk;
chunks.push_back(c);
for(size_t i = 0; i < std::min(static_cast<unsigned int>(START_CHUNK_SIZE), static_cast<unsigned int>(num_lines - line_num) ); ++i) {
line *l = new line;
l->text = all_lines[line_num+i];
c->lines[i] = l;
}
}
return chunks;
}
Related
I'm trying to install the mongo-c-driver and mongo-cxx-driver in a Docker image, but when I run my C++ program it throws a Segmentation fault. Any ideas? Valgrind says it's mongo's fault.
I have some IOT devices and in my own computer they run just fine.
I'm using:
ubuntu:focal as base image
mongo-c-driver version 1.16.2 (also tried with 1.17 and 1.15)
mongo-cxx-driver version 3.5 (also tried with 3.6)
MongoDB server version 4.2.8
g++ version (Ubuntu 9.3.0-10ubuntu2) 9.3.0
Code:
std::string MongoDB::insertDocument(std::string database,
std::string collection, bsoncxx::document::view_or_value document)
{
try
{
mongocxx::uri uri(_connection_string);
mongocxx::client conn(uri); // seg fault occurs here
mongocxx::database db = conn[database];
mongocxx::collection coll = db[collection];
auto inserted = coll.insert_one(document.view());
bsoncxx::oid oid = inserted->inserted_id().get_oid().value;
return oid.to_string();
}
catch (const mongocxx::exception & e)
{
std::cerr << "WARNING: Unable to connect to MongoDB" << std::endl;
return "UNKNOWN";
}
}
Variable values:
_connection_string = "mongodb://burns"
database = "hopping"
collection = "executions"
document =
{
"created_at" : "2020.09.29 10:48:51",
"hostname" : "XXXXX",
"interface" : "wlp3s0mon",
"schedule" : [ 1 ],
"slot_size" : 200,
"type" : "MOCK_NODE"
}
Log:
==213== Invalid read of size 8
==213== at 0x5695C0A: mongoc_counter_clients_active_add (mongoc-counters.defs:37)
==213== by 0x5695C0A: mongoc_counter_clients_active_inc (mongoc-counters.defs:37)
==213== by 0x5695C0A: _mongoc_client_new_from_uri (mongoc-client.c:1101)
==213== by 0x5318074: mongocxx::v_noabi::client::client(mongocxx::v_noabi::uri const&, mongocxx::v_noabi::options::client const&) (in /usr/local/lib/libmongocxx.so.3.5.0)
==213== by 0x4B691D0: MongoDB::insertDocument(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bsoncxx::v_noabi::view_or_value<bsoncxx::v_noabi::document::view, bsoncxx::v_noabi::document::value>) (in /usr/local/lib/influx_logging/libinflux_logging.so)
==213== by 0x4B69714: MongoDB::insertJSONDocument(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> > >) (in /usr/local/lib/influx_logging/libinflux_logging.so)
==213== by 0x4B61AD0: DataLogger::setExecutionParameters(nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> > >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /usr/local/lib/influx_logging/libinflux_logging.so)
==213== by 0x1C232B: main (in /root/mock_node/build/mock_node)
==213== Address 0x38 is not stack'd, malloc'd or (recently) free'd
==213==
==213==
==213== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==213== Access not within mapped region at address 0x38
==213== at 0x5695C0A: mongoc_counter_clients_active_add (mongoc-counters.defs:37)
==213== by 0x5695C0A: mongoc_counter_clients_active_inc (mongoc-counters.defs:37)
==213== by 0x5695C0A: _mongoc_client_new_from_uri (mongoc-client.c:1101)
==213== by 0x5318074: mongocxx::v_noabi::client::client(mongocxx::v_noabi::uri const&, mongocxx::v_noabi::options::client const&) (in /usr/local/lib/libmongocxx.so.3.5.0)
==213== by 0x4B691D0: MongoDB::insertDocument(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bsoncxx::v_noabi::view_or_value<bsoncxx::v_noabi::document::view, bsoncxx::v_noabi::document::value>) (in /usr/local/lib/influx_logging/libinflux_logging.so)
==213== by 0x4B69714: MongoDB::insertJSONDocument(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> > >) (in /usr/local/lib/influx_logging/libinflux_logging.so)
==213== by 0x4B61AD0: DataLogger::setExecutionParameters(nlohmann::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> > >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (in /usr/local/lib/influx_logging/libinflux_logging.so)
==213== by 0x1C232B: main (in /root/mock_node/build/mock_node)
==213== If you believe this happened as a result of a stack
==213== overflow in your program's main thread (unlikely but
==213== possible), you can try to increase the size of the
==213== main thread stack using the --main-stacksize= flag.
==213== The main thread stack size used in this run was 8388608.
==213==
==213== HEAP SUMMARY:
==213== in use at exit: 123,339 bytes in 262 blocks
==213== total heap usage: 3,719 allocs, 3,457 frees, 367,254 bytes allocated
==213==
==213== LEAK SUMMARY:
==213== definitely lost: 400 bytes in 1 blocks
==213== indirectly lost: 6,752 bytes in 20 blocks
==213== possibly lost: 576 bytes in 2 blocks
==213== still reachable: 115,611 bytes in 239 blocks
==213== suppressed: 0 bytes in 0 blocks
==213== Rerun with --leak-check=full to see details of leaked memory
==213==
==213== For lists of detected and suppressed errors, rerun with: -s
==213== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
Ps: mock_node is my executable and influxdb-logging is a library of mine.
Thank you very much,
I have no idea what could be causing this...
From Tutorial for mongocxx:
IMPORTANT: Before making any connections, you need to create one and only one instance of mongocxx::instance. This instance must exist for the entirety of your program.
So, you can add this as a static member of your MongoDB class:
header
class MongoDB {
//...
private:
static mongocxx::instance inst;
};
impl
mongocxx::instance MongoDB::inst{};
Here's an example where I connect to the the default mongodb server (mongodb://localhost:27017), use the database dbted and the collection movie, both of which previously created using the mongo cli.
I added a method to get a mongocxx::cursor to all documents in the collection.
#include <bsoncxx/builder/stream/document.hpp>
#include <bsoncxx/json.hpp>
#include <mongocxx/client.hpp>
#include <mongocxx/exception/exception.hpp>
#include <mongocxx/instance.hpp>
#include <mongocxx/uri.hpp>
#include <iostream>
class MongoDB {
public:
MongoDB() :
client{mongocxx::uri{"mongodb://localhost:27017"}},
db{client["dbted"]},
coll{db["movie"]}
{}
mongocxx::cursor all() { return coll.find({}); }
private
mongocxx::client client;
mongocxx::database db;
mongocxx::collection coll;
static mongocxx::instance inst;
};
mongocxx::instance MongoDB::inst{};
int main() {
try {
MongoDB db;
std::cout << "Connected successfully\n";
for(auto doc : db.all()) {
std::cout << bsoncxx::to_json(doc) << '\n';
}
} catch(const std::exception& ex) {
std::cerr << "Exception: " << ex.what() << std::endl;
return 1;
}
}
I somehow fixed a memory issue in my code but am not quite sure what actually happens and I would like to see if anyone could possibly give me a reasonable explanation.
The code involves doing some computation with a class ANN_Force, initially when setting up parameter values_of_biased_nodes, I use following code:
values_of_biased_nodes = bias;
and that gives me following memory error:
Program received signal SIGSEGV, Segmentation fault.
__memmove_avx_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S:138
138 ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S: No such file
or directory.
#0 __memmove_avx_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S:138
#1 0x00007ffff7a0c903 in std::vector<double, std::allocator<double> >::operator=(std::vector<double, std::allocator<double> > const&) () from /home/kengyangyao/.openmm/lib/libOpenMM.so
#2 0x00007ffff7a5bdcf in std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >::operator=(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&) () from /home/kengyangyao/.openmm/lib/libOpenMM.so
#3 0x00007ffff76a3122 in OpenMM::ANN_Force::set_values_of_biased_nodes (this=0x6480e0, bias=...)
at /home/kengyangyao/Dropbox/temp_Linux/ANN_Force/openmmapi/src/ANN_Force.cpp:57
#4 0x000000000040cd4a in test_forward_and_backward_prop () at test_ANN_package.cpp:110
#5 0x000000000041468b in main (argc=1, argv=0x7fffffffdae8) at test_ANN_package.cpp:598
When I added a line:
values_of_biased_nodes.resize(bias.size());
values_of_biased_nodes = bias;
The problem disappeared but I have no idea why. My guess would be without resize, values_of_biased_nodes = bias; simply moves whatever in bias directly to values_of_biased_nodes without checking if the memory near values_of_biased_nodes is large enough to hold the values. I wonder if anyone could help me figure it out? Also I noticed that in some machines it works without resize, is it due to different memory management strategies, or simply because those machines have large enough memory?
Thank you!
UPDATED: I ran it with valgrind, here is output:
==13494== Memcheck, a memory error detector
==13494== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==13494== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==13494== Command: ./test_ANN_package
==13494==
/home/kengyangyao/.openmm/lib/plugins
running test_forward_and_backward_prop
==13494== Conditional jump or move depends on uninitialised value(s)
==13494== at 0x4F9689E: std::vector<double, std::allocator<double> >::operator=(std::vector<double, std::allocator<double> > const&) (in /home/kengyangyao/.openmm/lib/libOpenMM.so)
==13494== by 0x4FE5DCE: std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >::operator=(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&) (in /home/kengyangyao/.openmm/lib/libOpenMM.so)
==13494== by 0x5374121: OpenMM::ANN_Force::set_values_of_biased_nodes(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >) (ANN_Force.cpp:57)
==13494== by 0x40CD49: test_forward_and_backward_prop() (test_ANN_package.cpp:110)
==13494== by 0x41468A: main (test_ANN_package.cpp:598)
==13494== Uninitialised value was created by a heap allocation
==13494== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13494== by 0x41BACF: __gnu_cxx::new_allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::allocate(unsigned long, void const*) (new_allocator.h:104)
==13494== by 0x41ACA5: std::allocator_traits<std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::allocate(std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, unsigned long) (alloc_traits.h:491)
==13494== by 0x419809: std::_Vector_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::_M_allocate(unsigned long) (stl_vector.h:170)
==13494== by 0x41904A: std::_Vector_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::_M_create_storage(unsigned long) (stl_vector.h:185)
==13494== by 0x41728C: std::_Vector_base<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::_Vector_base(unsigned long, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&) (stl_vector.h:136)
==13494== by 0x4155AB: std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::vector(unsigned long, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&) (stl_vector.h:278)
==13494== by 0x415072: OpenMM::ANN_Force::ANN_Force() (in /home/kengyangyao/Dropbox/temp_Linux/ANN_Force/openmmapi/tests/test_ANN_package)
==13494== by 0x40C8AA: test_forward_and_backward_prop() (test_ANN_package.cpp:103)
==13494== by 0x41468A: main (test_ANN_package.cpp:598)
==13494==
==13494== Invalid write of size 1
==13494== at 0x4C3245C: memcpy#GLIBC_2.2.5 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13494== by 0x4F96902: std::vector<double, std::allocator<double> >::operator=(std::vector<double, std::allocator<double> > const&) (in /home/kengyangyao/.openmm/lib/libOpenMM.so)
==13494== by 0x4FE5DCE: std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >::operator=(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&) (in /home/kengyangyao/.openmm/lib/libOpenMM.so)
==13494== by 0x5374121: OpenMM::ANN_Force::set_values_of_biased_nodes(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >) (ANN_Force.cpp:57)
==13494== by 0x40CD49: test_forward_and_backward_prop() (test_ANN_package.cpp:110)
==13494== by 0x41468A: main (test_ANN_package.cpp:598)
==13494== Address 0x3f947ae147ae147b is not stack'd, malloc'd or (recently) free'd
==13494==
==13494==
==13494== Process terminating with default action of signal 11 (SIGSEGV)
==13494== General Protection Fault
==13494== at 0x4C3245C: memcpy#GLIBC_2.2.5 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13494== by 0x4F96902: std::vector<double, std::allocator<double> >::operator=(std::vector<double, std::allocator<double> > const&) (in /home/kengyangyao/.openmm/lib/libOpenMM.so)
==13494== by 0x4FE5DCE: std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >::operator=(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&) (in /home/kengyangyao/.openmm/lib/libOpenMM.so)
==13494== by 0x5374121: OpenMM::ANN_Force::set_values_of_biased_nodes(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >) (ANN_Force.cpp:57)
==13494== by 0x40CD49: test_forward_and_backward_prop() (test_ANN_package.cpp:110)
==13494== by 0x41468A: main (test_ANN_package.cpp:598)
==13494==
==13494== HEAP SUMMARY:
==13494== in use at exit: 2,016,954 bytes in 7,600 blocks
==13494== total heap usage: 9,419 allocs, 1,819 frees, 2,218,864 bytes allocated
==13494==
==13494== LEAK SUMMARY:
==13494== definitely lost: 0 bytes in 0 blocks
==13494== indirectly lost: 0 bytes in 0 blocks
==13494== possibly lost: 0 bytes in 0 blocks
==13494== still reachable: 2,016,954 bytes in 7,600 blocks
==13494== of which reachable via heuristic:
==13494== stdstring : 196 bytes in 6 blocks
==13494== suppressed: 0 bytes in 0 blocks
==13494== Reachable blocks (those to which a pointer was found) are not shown.
==13494== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==13494==
==13494== For counts of detected and suppressed errors, rerun with: -v
==13494== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
[1] 13494 segmentation fault (core dumped) valgrind --leak-check=yes --track-origins=yes ./test_ANN_package
seems that some memory is not correctly handled?
Assigning one vector to another does not require that you resize the target vector before performing the assignment; that would be a terrible design. I suspect you have other memory issues in play and this just reveals them. Have you tried running this under valgrind?
After looking at your valgrind output, it's clear that you have memory corruption but it's difficult to say exactly what's going on without seeing the offending lines of source code. I recommend running under gdb and breaking on the line that generates the first valgrind error. If you can figure the problem out on your own, then fix it and rerun it under valgrind, repeating as necessary until you fix all the errors. If you cannot figure out the problem, please post the offending lines +- 10 lines and I'll take a look.
I'm trying to track down some mysterious crashes that seem to be memory-related thus far. So, I've started using Valgrind to get it done. I've never used it before, but the first run gave me some good information. Today I had a chance to run it again (the circumstance in which we see a crash isn't reproducible) and the output was decidedly less useful.
==11831==
==11831== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==11831== Bad permissions for mapped region at address 0x75EAB8
==11831== at 0x75EAB8: ??? (in /usr/local/bin/test-app.V1.88)
==11831== by 0x75EAB7: ??? (in /usr/local/bin/test-app.V1.88)
==11831== by 0x75EAB7: ??? (in /usr/local/bin/test-app.V1.88)
==11831== by 0x75EAB7: ??? (in /usr/local/bin/test-app.V1.88)
==11831== by 0x75EAB7: ??? (in /usr/local/bin/test-app.V1.88)
==11831== by 0x75EAB7: ??? (in /usr/local/bin/test-app.V1.88)
==11831== by 0x75EAB7: ??? (in /usr/local/bin/test-app.V1.88)
==11831== by 0x75EAB7: ??? (in /usr/local/bin/test-app.V1.88)
==11831==
==11831== HEAP SUMMARY:
==11831== in use at exit: 3,611,867 bytes in 12,934 blocks
==11831== total heap usage: 15,871 allocs, 2,937 frees, 26,483,142 bytes allocated
==11831==
==11831== LEAK SUMMARY:
==11831== definitely lost: 0 bytes in 0 blocks
==11831== indirectly lost: 0 bytes in 0 blocks
==11831== possibly lost: 206,203 bytes in 7,146 blocks
==11831== still reachable: 3,405,664 bytes in 5,788 blocks
==11831== suppressed: 0 bytes in 0 blocks
==11831== Rerun with --leak-check=full to see details of leaked memory
==11831==
==11831== For counts of detected and suppressed errors, rerun with: -v
==11831== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
So, I ran it again with --leak-check=full and it did give me more:
==13764==
==13764== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==13764== Bad permissions for mapped region at address 0x75EAB8
==13764== at 0x75EAB8: ??? (in /usr/local/bin/test-app.V1.88)
==13764== by 0x75EAB7: ??? (in /usr/local/bin/test-app.V1.88)
==13764== by 0x75EAB7: ??? (in /usr/local/bin/test-app.V1.88)
==13764== by 0x75EAB7: ??? (in /usr/local/bin/test-app.V1.88)
==13764== by 0x75EAB7: ??? (in /usr/local/bin/test-app.V1.88)
==13764== by 0x75EAB7: ??? (in /usr/local/bin/test-app.V1.88)
==13764== by 0x75EAB7: ??? (in /usr/local/bin/test-app.V1.88)
==13764== by 0x75EAB7: ??? (in /usr/local/bin/test-app.V1.88)
==13764==
==13764== HEAP SUMMARY:
==13764== in use at exit: 3,611,867 bytes in 12,934 blocks
==13764== total heap usage: 15,871 allocs, 2,937 frees, 26,483,154 bytes allocated
==13764==
==13764== 26 bytes in 1 blocks are possibly lost in loss record 5 of 343
==13764== at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13764== by 0x4ED0A88: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4ED0C79: std::string::_M_mutate(unsigned long, unsigned long, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4ED0E1B: std::string::_M_replace_safe(unsigned long, unsigned long, char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4D48B3: abc::load_config_file(std::string) (abc_read_config_file.cpp:46)
==13764== by 0x4C0A3A: AppStartup(int, char**, char const*) (AppBase.cpp:58)
==13764== by 0x49BFC1: main (App.cpp:54)
==13764==
==13764== 28 bytes in 1 blocks are possibly lost in loss record 6 of 343
==13764== at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13764== by 0x4ED0A88: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4ED2494: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4ED25E2: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4FCB74: __static_initialization_and_destruction_0(int, int) (xyzLib.cc:46)
==13764== by 0x4FCD12: _GLOBAL__sub_I_xyzLib.cc (xyzLib.cc:2179)
==13764== by 0x52280C: __libc_csu_init (in /usr/local/bin/test-app.V1.88)
==13764== by 0x58826FF: (below main) (libc-start.c:185)
==13764==
==13764== 28 bytes in 1 blocks are possibly lost in loss record 7 of 343
==13764== at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13764== by 0x4ED0A88: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4ED22B4: char* std::string::_S_construct<char*>(char*, char*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4ED2414: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&, unsigned long, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4ED2441: std::string::substr(unsigned long, unsigned long) const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x500E27: XyzParameter::getField(std::string&, char const*, std::string const&, unsigned long&, bool) (xyzMessageCodec.hh:1186)
==13764== by 0x500FBB: XyzParameter::getFields(std::vector<std::string, std::allocator<std::string> >&, int, std::string const&, bool) (xyzMessageCodec.hh:1219)
==13764== by 0x5021F3: XyzParameter::getPositionsList(std::string const&) (xyzMessageCodec.hh:1414)
==13764== by 0x4FAF0B: Xyz::XyzLib::MessageHandler::handleOpenPositionsResponse(void*) (xyzLib.cc:1854)
==13764== by 0x4F8F08: Xyz::XyzLib::MessageHandler::handleXyzMsg(void*) (xyzLib.cc:1444)
==13764== by 0x4F7CCC: Xyz::XyzLib::MessageHandler::onMsg(Xyz::Xyz::XyzMessage*) (xyzLib.cc:1211)
==13764== by 0x51101D: Xyz::Xyz::XyzSession::processNextMsg() (xyzSession.cc:270)
==13764==
==13764== 29 bytes in 1 blocks are possibly lost in loss record 8 of 343
==13764== at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13764== by 0x4ED0A88: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4ED2494: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4ED25E2: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4A62CE: __static_initialization_and_destruction_0(int, int) (Distributor.h:190)
==13764== by 0x4A659F: _GLOBAL__sub_I_abc.cpp (abc.cpp:522)
==13764== by 0x52280C: __libc_csu_init (in /usr/local/bin/test-app.V1.88)
==13764== by 0x58826FF: (below main) (libc-start.c:185)
==13764==
==13764== 29 bytes in 1 blocks are possibly lost in loss record 9 of 343
==13764== at 0x4C2B1C7: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13764== by 0x4ED0A88: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4ED2494: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4ED25E2: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
==13764== by 0x4A6311: __static_initialization_and_destruction_0(int, int) (Distributor.h:190)
==13764== by 0x4A659F: _GLOBAL__sub_I_abc.cpp (abc.cpp:522)
==13764== by 0x52280C: __libc_csu_init (in /usr/local/bin/test-app.V1.88)
==13764== by 0x58826FF: (below main) (libc-start.c:185)
And on it goes for another 14,000 lines and a few PID's.
My question is: what exactly is this reporting? The last time I ran valgrind on an app crashing like this, I was pointed squarely at the destructor of a class, specifically of a std::string data member of that class. This time, however, valgrind only has question marks for me and a whole lot more dealing with the new operator from std::string. I'm genuinely unaware how one might proceed with this information to arrive at some sort of conclusion and fix a bug or four.
EDIT Here are the specific lines valgrind is suspicious of:
app_params.tracked_symbol="a";
const std::string XyzLib::LANGUAGE_ID = "C++";
The next two are a return statement and the closing brace of a class. It continues like that for quite a few instances of valgrind's concern (closing braces of the several classes).
I'm not sure if it's a bug or not, but when I use string-type members inside structures or classes, valgrind identifies memory leaks. I've tried to build a simple code based on my own application, I'm sorry if it is still big...
// ====================================================================
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
// ====================================================================
string int2str(const int &i) {
return static_cast<ostringstream*>(
&(ostringstream() << i))->str();
}
// ====================================================================
class P;
// ====================================================================
struct Node {
virtual char isType() const = 0;
};
// ====================================================================
struct X : Node {
string st;
int id;
X(const string &_st, const int &_id);
char isType() const { return 'x'; };
// Those member functions are after class P declaration:
P use_as_P();
P use_as_P(const P &arg0);
P use_as_P(const P &arg0, const P &arg1);
};
X::X(const string &_st, const int &_id) : st(_st), id(_id) { }
// ====================================================================
class P {
friend struct X;
private:
Node *node;
vector<P> children;
public:
P() : node(NULL) {};
P(const P &source);
void swap(P &other);
string print_this();
~P();
};
P::P(const P &source) {
this->children = source.children;
switch(source.node->isType()) {
case 'x':
this->node = new X(static_cast<X*>(source.node)->st,
static_cast<X*>(source.node)->id);
break;
}
}
void P::swap(P &other) {
std::swap(this->node, other.node);
std::swap(this->children, other.children);
}
string P::print_this() {
string msg = "( ";
msg += static_cast<X*>(this->node)->st;
msg += int2str(static_cast<X*>(this->node)->id);
msg += " ";
for(size_t i = 0; i < this->children.size(); i++)
msg += children.at(i).print_this();
msg += ") ";
return msg;
}
P::~P() {
if(this->node != NULL)
delete node;
this->children.clear();
}
// ====================================================================
P X::use_as_P() {
P ast_aux;
ast_aux.node = new X(this->st,this->id);
return ast_aux;
}
P X::use_as_P(const P &arg0) {
P ast_aux;
ast_aux.node = new X(this->st,this->id);
ast_aux.children.push_back(arg0);
return ast_aux;
}
P X::use_as_P(const P &arg0, const P &arg1) {
P ast_aux;
ast_aux.node = new X(this->st,this->id);
ast_aux.children.push_back(arg0);
ast_aux.children.push_back(arg1);
return ast_aux;
}
// ====================================================================
// ** MAIN **
// ====================================================================
int main(int argc, char **argv)
{
X a("how",0), b("what",1), c("why",2), d("when",3);
P testing = a.use_as_P(b.use_as_P(c.use_as_P()),d.use_as_P());
cout << testing.print_this() << endl;
return 0;
}
// ====================================================================
Compiling with:
nvcc -arch sm_20 -o LEAK_test_with_string LEAK_test_with_string.cu
And here goes the valgrind's analysis:
==5877== Memcheck, a memory error detector
==5877== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==5877== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==5877== Command: ./LEAK_test_with_string
==5877==
( how0 ( what1 ( why2 ) ) ( when3 ) )
==5877==
==5877== HEAP SUMMARY:
==5877== in use at exit: 114 bytes in 4 blocks
==5877== total heap usage: 47 allocs, 43 frees, 3,701 bytes allocated
==5877==
==5877== 28 bytes in 1 blocks are definitely lost in loss record 1 of 4
==5877== at 0x4C2A879: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5877== by 0x5516F38: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518640: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518A57: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x403691: main (in /home/igor/projects/system_modeling/LEAK_test_with_string)
==5877== : st(_st), id(_id) {}
==5877== 28 bytes in 1 blocks are definitely lost in loss record 2 of 4
==5877== at 0x4C2A879: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5877== by 0x5516F38: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518640: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518A57: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x40375A: main (in /home/igor/projects/system_modeling/LEAK_test_with_string)
==5877==
==5877== 29 bytes in 1 blocks are definitely lost in loss record 3 of 4
==5877== at 0x4C2A879: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5877== by 0x5516F38: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518640: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518A57: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x4036F7: main (in /home/igor/projects/system_modeling/LEAK_test_with_string)
==5877==
==5877== 29 bytes in 1 blocks are definitely lost in loss record 4 of 4
==5877== at 0x4C2A879: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5877== by 0x5516F38: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518640: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x5518A57: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.18)
==5877== by 0x4037BD: main (in /home/igor/projects/system_modeling/LEAK_test_with_string)
==5877==
==5877== LEAK SUMMARY:
==5877== definitely lost: 114 bytes in 4 blocks
==5877== indirectly lost: 0 bytes in 0 blocks
==5877== possibly lost: 0 bytes in 0 blocks
==5877== still reachable: 0 bytes in 0 blocks
==5877== suppressed: 0 bytes in 0 blocks
==5877==
==5877== For counts of detected and suppressed errors, rerun with: -v
==5877== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 2 from 2)
The "it's a bug" wondering comes when I change the C++ string member into a plain C char* member. One just need to change this part of the above written code:
// ====================================================================
struct X : Node {
char st[6]; // <=============== HERE!
int id;
X(const string &_st, const int &_id);
char isType() const { return 'x'; };
// Those member functions are after class P declaration:
P use_as_P();
P use_as_P(const P &arg0);
P use_as_P(const P &arg0, const P &arg1);
};
X::X(const string &_st, const int &_id) : id(_id) { // <=============== HERE!
strcpy(st, _st.c_str()); // <=============== HERE!
}
// ====================================================================
Note that I still use string in my code, but now there isn't any string member declared. This way, valgrind doesn't complain anymore:
==5977== Memcheck, a memory error detector
==5977== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==5977== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==5977== Command: ./LEAK_test_without_string
==5977==
( how0 ( what1 ( why2 ) ) ( when3 ) )
==5977==
==5977== HEAP SUMMARY:
==5977== in use at exit: 0 bytes in 0 blocks
==5977== total heap usage: 57 allocs, 57 frees, 3,986 bytes allocated
==5977==
==5977== All heap blocks were freed -- no leaks are possible
==5977==
==5977== For counts of detected and suppressed errors, rerun with: -v
==5977== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
Does anybody have an insight on this? I mean, is this a bug that should be reported or is there something that I'm actually missing in my string-version code?
Since no one's bitten the bullet I'll expand my comment: Your Node class does not have a virtual destructor, this makes the following line
delete node;
invoke undefined behaviour - this will only call the destructor for Node, the destructor for X is never called.
The solution is simple, provide a virtual destructor for Node:
struct Node {
virtual char isType() const = 0;
virtual ~Node() =default;
// or virtual ~Node(){} if your compiler does not support defaulted functions.
}
You can now safely delete base pointers of Node that point to inherited classes.
The reason for the memory leak when using a std::string is because when you delete the base pointer node, the destructor for X is not called, and so neither is the destructor for st. The char array version doesn't leak because node points to a simple block of memory, and X in this case doesn't have any complex members that require destruction, so delete node luckily releases all of the memory allocated for X and its members. Remember that this is undefined behaviour however and the compiler can legitimately do whatever it wants to.
If you have a base class with even a single virtual function, always add a virtual destructor. You can make a case for omitting a virtual destructor if you are absolutely sure you won't be deleting inherited classes using a pointer to the base class, but it's safer to just add one anyway just in case (the gcc compiler flag -Weffc++ will also tell you as much).
I am getting a segmentation fault on one of my programs and not sure why. I've ran a valgrind:
==7631== Memcheck, a memory error detector
==7631== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==7631== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==7631== Command: ./a.out wordsRMS.txt
==7631== Parent PID: 30431
==7631==
==7631== Use of uninitialised value of size 8
==7631== at 0x403C5C: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::begin() const (in /root/test/a.out)
==7631== by 0x403D04: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::size() const (in /root/test/a.out)
==7631== by 0x40328A: testNewWord(std::string const&, std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >*) (in /root/test/a.out)
==7631== by 0x4038FE: main (in /root/test/a.out)
==7631==
==7631== Use of uninitialised value of size 8
==7631== at 0x403C86: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::end() const (in /root/test/a.out)
==7631== by 0x403D11: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::size() const (in /root/test/a.out)
==7631== by 0x40328A: testNewWord(std::string const&, std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >*) (in /root/test/a.out)
==7631== by 0x4038FE: main (in /root/test/a.out)
==7631==
==7631== Use of uninitialised value of size 8
==7631== at 0x403C5C: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::begin() const (in /root/test/a.out)
==7631== by 0x403D04: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::size() const (in /root/test/a.out)
==7631== by 0x405E78: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::_M_range_check(unsigned long) const (in /root/test/a.out)
==7631== by 0x405EAC: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::at(unsigned long) (in /root/test/a.out)
==7631== by 0x402DD2: testNewWord(std::string const&, std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >*) (in /root/test/a.out)
==7631== by 0x4038FE: main (in /root/test/a.out)
==7631==
==7631== Use of uninitialised value of size 8
==7631== at 0x403C86: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::end() const (in /root/test/a.out)
==7631== by 0x403D11: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::size() const (in /root/test/a.out)
==7631== by 0x405E78: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::_M_range_check(unsigned long) const (in /root/test/a.out)
==7631== by 0x405EAC: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::at(unsigned long) (in /root/test/a.out)
==7631== by 0x402DD2: testNewWord(std::string const&, std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >*) (in /root/test/a.out)
==7631== by 0x4038FE: main (in /root/test/a.out)
==7631==
==7631== Use of uninitialised value of size 8
==7631== at 0x403D48: __gnu_cxx::__normal_iterator<PeekDeque<StringWrap>**, std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> > >::__normal_iterator(PeekDeque<StringWrap>** const&) (in /root/test/a.out)
==7631== by 0x403D6C: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::begin() (in /root/test/a.out)
==7631== by 0x403DD2: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::operator[](unsigned long) (in /root/test/a.out)
==7631== by 0x405EB9: std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >::at(unsigned long) (in /root/test/a.out)
==7631== by 0x402DD2: testNewWord(std::string const&, std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >*) (in /root/test/a.out)
==7631== by 0x4038FE: main (in /root/test/a.out)
==7631==
==7631== Invalid read of size 8
==7631== at 0x402DD3: testNewWord(std::string const&, std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >*) (in /root/test/a.out)
==7631== by 0x4038FE: main (in /root/test/a.out)
==7631== Address 0x6c894ce02464894c is not stack'd, malloc'd or (recently) free'd
==7631==
==7631==
==7631== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==7631== General Protection Fault
==7631== at 0x402DD3: testNewWord(std::string const&, std::vector<PeekDeque<StringWrap>*, std::allocator<PeekDeque<StringWrap>*> >*) (in /root/test/a.out)
==7631== by 0x4038FE: main (in /root/test/a.out)
==7631==
==7631== HEAP SUMMARY:
==7631== in use at exit: 9,344 bytes in 5 blocks
==7631== total heap usage: 5 allocs, 0 frees, 9,344 bytes allocated
==7631==
==7631== 27 bytes in 1 blocks are possibly lost in loss record 1 of 5
==7631== at 0x4A0695E: operator new(unsigned long) (vg_replace_malloc.c:220)
==7631== by 0x33A9A9B860: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.8)
==7631== by 0x33A9A9C23A: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned long) (in /usr/lib64/libstdc++.so.6.0.8)
==7631== by 0x33A9A9CB44: std::string::reserve(unsigned long) (in /usr/lib64/libstdc++.so.6.0.8)
==7631== by 0x33A9A9CD5E: std::string::append(char const*, unsigned long) (in /usr/lib64/libstdc++.so.6.0.8)
==7631== by 0x33A9A76203: 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/lib64/libstdc++.so.6.0.8)
==7631== by 0x40390B: main (in /root/test/a.out)
==7631==
==7631== 37 bytes in 1 blocks are possibly lost in loss record 2 of 5
==7631== at 0x4A0695E: operator new(unsigned long) (vg_replace_malloc.c:220)
==7631== by 0x33A9A9B860: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/libstdc++.so.6.0.8)
==7631== by 0x33A9A9C364: ??? (in /usr/lib64/libstdc++.so.6.0.8)
==7631== by 0x33A9A9C511: 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.8)
==7631== by 0x403873: main (in /root/test/a.out)
==7631==
==7631== LEAK SUMMARY:
==7631== definitely lost: 0 bytes in 0 blocks
==7631== indirectly lost: 0 bytes in 0 blocks
==7631== possibly lost: 64 bytes in 2 blocks
==7631== still reachable: 9,280 bytes in 3 blocks
==7631== suppressed: 0 bytes in 0 blocks
==7631== Reachable blocks (those to which a pointer was found) are not shown.
==7631== To see them, rerun with: --leak-check=full --show-reachable=yes
==7631==
==7631== For counts of detected and suppressed errors, rerun with: -v
==7631== Use --track-origins=yes to see where uninitialised values come from
==7631== ERROR SUMMARY: 8 errors from 8 contexts (suppressed: 4 from 4)
The line that seems to be of importance:
Address 0x6c894ce02464894c is not stack'd, malloc'd or (recently) free'd
However, I'm not quite sure what to make of this. Here is my code:
/** Add word to new or existing chain.
*/
void testNewWord(const string& word, vector<PeekDeque<StringWrap>* >* chains) {
bool foundChain = false;
// check to see if we can add word into EXISTING chain
for(std::vector<int>::size_type i = 0; i != chains->size(); i++) {
// check front of chain
if(ed1(StringWrap(word).str(), chains->at(i)->returnFront().str())) {
//cout << "The word has an edit distance 1 with the front item." << endl;
chains->at(i)->pushFront(StringWrap(word));
foundChain = true;
break;
}
// check rear of chain
if(ed1(StringWrap(word).str(), chains->at(i)->returnRear().str())) {
//cout << "The word has an edit distance 1 with the rear item." << endl;
chains->at(i)->pushRear(StringWrap(word));
foundChain = true;
break;
}
}
// otherwise create a NEW chain
if(!foundChain) {
PeekDeque<StringWrap>* newpd = new PeekDeque<StringWrap>(500);
newpd->pushFront(StringWrap(word));
chains->push_back(newpd);
}
}
int main(int argc, char* argv[]){
if(argc != 2){
cerr << "Please specify a SINGLE .txt file to generate word chains from." << '\n' << "Usage: ./PeekClientRMS /path/to/file.txt" << '\n';
return 1;
}
vector<PeekDeque<StringWrap>* >* chains;
string word;
string infileName = argv[1];
ifstream* INFILEp = new ifstream(infileName.c_str(), ios_base::in);
while ((*INFILEp) >> word) {
testNewWord(word, chains);
}
INFILEp->close();
/*for(std::vector<int>::size_type i = 0; i != chains->size(); i++) {
}*/
}
Interestingly enough, when I uncomment the for loop at the bottom of main(), my program runs?
/*for(std::vector<int>::size_type i = 0; i != chains->size(); i++) {
}*/
What could be going on here?
In the main function you declare a pointer to a vector, but you never make that pointer actually point anywhere. Uninitialized local variables have an indeterminate value (and it will seem to be random), and using those variables leads to undefined behavior.
In this case there's no need to use a pointer for the vector. Just declare it as a normal non-pointer variable, and pass it to the function as a reference.
Like
vector<PeekDeque<StringWrap>* > chains;
Then modify the function to take a reference:
void testNewWord(const string& word, vector<PeekDeque<StringWrap>* >& chains)
In fact, in C++ you should try to avoid pointers as much as possible, they are often not needed. I would actually urge you to not store pointers in the vector.
Your mistake is fundamental!
A pointer is no object, the chains is just holding an address to some memory, which is not the address of an object, not allocated and not initialized.
In C++ you should avoid needless allocations and prefer passing objects by value or reference:
vector< PeekDeque < StringWrap > >
void testNewWord(const string& word, vector< PeekDeque< StringWrap> >& chains);
If you allocate via new you should pair up with delete, too (or delegate to a smart pointer).
The ifstream* INFILEp = new ... is a memory leak and defeats proper destruction without a delete INFILEp - better (again): omit the pointer and just use ifstream INFILE(infileName.c_str());
The PeekDeque<StringWrap>* newpd = new PeekDeque is likely a memory leak, too.