C++ Poco MySQL Data wrapper segmentation fault error - c++

I am using Poco 1.8 Data library. I want to build a database wrapper to run multiple SQL queries concurrently.
I build a dbconn.h with the following.
std::string _dbConnString = "host=" + host + ";user=" + user + ";password=" + password + ";db="+db
+";compress=true;auto-reconnect=true";
std::string getkey(int userID, int exchangeID) {
Poco::Data::MySQL::Connector::registerConnector();
std::string key;
{
// 0. connect & create table
Session session(Poco::Data::MySQL::Connector::KEY,_dbConnString);
Statement selectn(session);
selectn << "SELECT key FROM API WHERE user_id=? ", into(key), use(userID), now;
}
catch (const Poco::Data::ConnectionFailedException &ce)
{
std::cout << ce.displayText() << std::endl;
}
catch (const Poco::Data::MySQL::StatementException &se)
{
std::cout << se.displayText() << std::endl;
}
Poco::Data::MySQL::Connector::unregisterConnector();
return key;
}
std::string getuser(int userID, int exchangeID) {
Poco::Data::MySQL::Connector::registerConnector();
std::string user;
try
{
// 0. connect & create table
Session session(Poco::Data::MySQL::Connector::KEY, _dbConnString);
Statement selectn(session);
selectn << "SELECT user FROM API WHERE user_id=? ", into(user), use(userID), now;
}
catch (const Poco::Data::ConnectionFailedException &ce)
{
std::cout << ce.displayText() << std::endl;
}
catch (const Poco::Data::MySQL::StatementException &se)
{
std::cout << se.displayText() << std::endl;
}
Poco::Data::MySQL::Connector::unregisterConnector();
return user;
}
The following will throw out segmental fault.
teset.cpp
int user_id = 100;
int exchange_id = 1;
std::string key = getkey(user_id,exchange_id); //no error
std::string user = getuser(user_id,exchange_id); //segmentation fault
If you reverse the order of the function call, same error:
std::string user = getuser(user_id,exchange_id); //no error
std::string key = getkey(user_id,exchange_id); //segmentation fault
I think something to do with the the part of creating the session. But there is not so many Poco data examples available on internet, any advice is appreciated.
Valgrind error:
==3316== Thread 2:
==3316== Invalid read of size 4
==3316== at 0x4E45FA0: pthread_mutex_lock (pthread_mutex_lock.c:65)
==3316== by 0x76332D9: ??? (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.20.3.12)
==3316== by 0x760AB40: ??? (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.20.3.12)
==3316== by 0x75DEB2A: mysql_real_connect (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.20.3.12)
==3316== by 0x5B43736: Poco::Data::MySQL::SessionHandle::connect(char const*, char const*, char const*, char const*, unsigned int) (in /usr/lib/libPocoDataMySQL.so.50)
==3316== by 0x5B4795A: Poco::Data::MySQL::SessionImpl::open(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/lib/libPocoDataMySQL.so.50)
==3316== by 0x5B48D86: Poco::Data::MySQL::SessionImpl::SessionImpl(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long) (in /usr/lib/libPocoDataMySQL.so.50)
==3316== by 0x5B3E51D: Poco::Data::MySQL::Connector::createSession(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long) (in /usr/lib/libPocoDataMySQL.so.50)
==3316== by 0x5498B83: Poco::Data::SessionFactory::create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long) (in /usr/lib/libPocoData.so.50)
==3316== by 0x115048: getAPIsecret[abi:cxx11](int, int) (dbconnector.h:85)
==3316== by 0x11561A: Trading::Binance::BUY::process(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (binance.cpp:36)
==3316== by 0x110F95: Trading::ExchangeRequest::run() (exchangeRequest.cpp:58)
==3316== Address 0x30 is not stack'd, malloc'd or (recently) free'd
==3316==
==3316==
==3316== Process terminating with default action of signal 11 (SIGSEGV)
==3316== Access not within mapped region at address 0x30
==3316== at 0x4E45FA0: pthread_mutex_lock (pthread_mutex_lock.c:65)
==3316== by 0x76332D9: ??? (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.20.3.12)
==3316== by 0x760AB40: ??? (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.20.3.12)
==3316== by 0x75DEB2A: mysql_real_connect (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.20.3.12)
==3316== by 0x5B43736: Poco::Data::MySQL::SessionHandle::connect(char const*, char const*, char const*, char const*, unsigned int) (in /usr/lib/libPocoDataMySQL.so.50)
==3316== by 0x5B4795A: Poco::Data::MySQL::SessionImpl::open(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/lib/libPocoDataMySQL.so.50)
==3316== by 0x5B48D86: Poco::Data::MySQL::SessionImpl::SessionImpl(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long) (in /usr/lib/libPocoDataMySQL.so.50)
==3316== by 0x5B3E51D: Poco::Data::MySQL::Connector::createSession(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long) (in /usr/lib/libPocoDataMySQL.so.50)
==3316== by 0x5498B83: Poco::Data::SessionFactory::create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned long) (in /usr/lib/libPocoData.so.50)
==3316== by 0x115048: getAPIsecret[abi:cxx11](int, int) (dbconnector.h:85)
==3316== by 0x11561A: Trading::Binance::BUY::process(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (binance.cpp:36)
==3316== by 0x110F95: Trading::ExchangeRequest::run() (exchangeRequest.cpp:58)
==3316== If you believe this happened as a result of a stack
==3316== overflow in your program's main thread (unlikely but
==3316== possible), you can try to increase the size of the
==3316== main thread stack using the --main-stacksize= flag.
==3316== The main thread stack size used in this run was 8388608.
==3316==
==3316== HEAP SUMMARY:
==3316== in use at exit: 266,548 bytes in 966 blocks
==3316== total heap usage: 2,241 allocs, 1,275 frees, 790,945 bytes allocated
==3316==
==3316== LEAK SUMMARY:
==3316== definitely lost: 0 bytes in 0 blocks
==3316== indirectly lost: 0 bytes in 0 blocks
==3316== possibly lost: 62,545 bytes in 63 blocks
==3316== still reachable: 204,003 bytes in 903 blocks
==3316== suppressed: 0 bytes in 0 blocks
==3316== Rerun with --leak-check=full to see details of leaked memory
==3316==
==3316== For counts of detected and suppressed errors, rerun with: -v
==3316== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

The Poco::Data::MySQL::Connector::registerConnector(); and Poco::Data::MySQL::Connector::unregisterConnector(); have non-local effects, you should move them out of the concurrently-called bits into some global setup/teardown. And it should be enough to call them once, you don't have to repeat them for every query.

Related

C++ Memory leak issue

I am trying to find a memory leak in my code but for the life of me, I cannot figure out or identify the reason for this leak. Which is why I am reaching out to your all. Thanks in advance.
The following code, creates a kerberos cache from keytab. The code is an extract of a bigger code, but this also has the same memory leak. The full code is as following
#include <iostream>
#include <cstring>
#include <krb5/krb5.h>
bool renew(krb5_context &_ctx, krb5_keytab &_keytab, krb5_ccache &_cache, std::string &_principal)
{
long int retval;
bool success = false;
krb5_principal principal;
krb5_creds *creds;
if ((retval = krb5_parse_name(_ctx, _principal.c_str(), &principal)))
throw "cannot parse principal string";
creds = (krb5_creds*) malloc(sizeof(*creds));
memset(creds, 0, sizeof(creds));
if ((retval = krb5_get_init_creds_keytab(_ctx, creds, principal, _keytab, 0, NULL, NULL)))
{
free(creds);
krb5_free_principal(_ctx, principal);
throw "cannot initialize keytab credentials - ";
}
if ((retval = krb5_cc_initialize(_ctx, _cache, principal)))
{
free(creds);
krb5_free_principal(_ctx, principal);
throw " cannot initialize cache - ";
}
if ((retval = krb5_cc_store_cred(_ctx, _cache, creds)))
{
free(creds);
krb5_free_principal(_ctx, principal);
throw "cannot store credentials - ";
}
free(creds);
krb5_free_principal(_ctx, principal);
return success;
}
int main()
{
long int retval;
std::string _keytab_file, _cache_file, _realm, _principal;
krb5_context _ctx = NULL;
krb5_keytab _keytab = NULL;
krb5_ccache _cache = NULL;
_keytab_file = "/location/to/the/keytab/file";
_cache_file = "/location/to/the/cache/file";
_principal = "user.name#DOMAIN.COM";
if ((retval = krb5_init_context(&_ctx)))
throw "cannot initialize context";
if ((retval = krb5_kt_resolve(_ctx, _keytab_file.c_str(), &_keytab)))
throw "cannot resolve keytab";
if ((retval = krb5_cc_resolve(_ctx, _cache_file.c_str(), &_cache)))
throw "cannot open/initialize kerberos cache";
try {
renew(_ctx, _keytab, _cache, _principal);
} catch (std::exception &e) {
std::cerr<<e.what()<<std::endl;
}
bailout:
if (_cache)
krb5_cc_close(_ctx, _cache);
if (_keytab)
krb5_kt_close(_ctx, _keytab);
if (_ctx)
krb5_free_context(_ctx);
return 0;
}
in a linux (or similar) box following used to compile and run with valgrind to check memory leak
g++ krb.cpp -o krb -lkrb5 -g
valgrind --leak-check=full ./krb
the valgrind report is as following-
==257623==
==257623== HEAP SUMMARY:
==257623== in use at exit: 4,964 bytes in 19 blocks
==257623== total heap usage: 9,165 allocs, 9,146 frees, 3,702,330 bytes allocated
==257623==
==257623== 16 bytes in 1 blocks are definitely lost in loss record 6 of 14
==257623== at 0x4C37135: malloc (vg_replace_malloc.c:381)
==257623== by 0x5E31F8D: krb5int_c_copy_keyblock_contents (in /usr/lib64/libk5crypto.so.3.1)
==257623== by 0x4E91146: ??? (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4E9C65B: ??? (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4E9C6F5: krb5_get_init_creds_keytab (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4012EF: renew(_krb5_context*&, _krb5_kt*&, _krb5_ccache*&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&) (krb.cpp:25)
==257623== by 0x401612: main (krb.cpp:76)
==257623==
==257623== 78 (40 direct, 38 indirect) bytes in 1 blocks are definitely lost in loss record 8 of 14
==257623== at 0x4C37135: malloc (vg_replace_malloc.c:381)
==257623== by 0x4E91574: krb5_copy_principal (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4E910EB: ??? (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4E9C65B: ??? (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4E9C6F5: krb5_get_init_creds_keytab (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4012EF: renew(_krb5_context*&, _krb5_kt*&, _krb5_ccache*&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&) (krb.cpp:25)
==257623== by 0x401612: main (krb.cpp:76)
==257623==
==257623== 97 (40 direct, 57 indirect) bytes in 1 blocks are definitely lost in loss record 9 of 14
==257623== at 0x4C37135: malloc (vg_replace_malloc.c:381)
==257623== by 0x4E91574: krb5_copy_principal (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4E9112F: ??? (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4E9C65B: ??? (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4E9C6F5: krb5_get_init_creds_keytab (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4012EF: renew(_krb5_context*&, _krb5_kt*&, _krb5_ccache*&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&) (krb.cpp:25)
==257623== by 0x401612: main (krb.cpp:76)
==257623==
==257623== 1,646 bytes in 1 blocks are definitely lost in loss record 13 of 14
==257623== at 0x4C37135: malloc (vg_replace_malloc.c:381)
==257623== by 0x4E91369: krb5int_copy_data_contents (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4E913EB: krb5_copy_data (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4E91198: ??? (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4E9C65B: ??? (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4E9C6F5: krb5_get_init_creds_keytab (in /usr/lib64/libkrb5.so.3.3)
==257623== by 0x4012EF: renew(_krb5_context*&, _krb5_kt*&, _krb5_ccache*&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&) (krb.cpp:25)
==257623== by 0x401612: main (krb.cpp:76)
==257623==
==257623== LEAK SUMMARY:
==257623== definitely lost: 1,742 bytes in 4 blocks
==257623== indirectly lost: 95 bytes in 7 blocks
==257623== possibly lost: 0 bytes in 0 blocks
==257623== still reachable: 3,127 bytes in 8 blocks
==257623== suppressed: 0 bytes in 0 blocks
==257623== Reachable blocks (those to which a pointer was found) are not shown.
==257623== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==257623==
==257623== For lists of detected and suppressed errors, rerun with: -s
==257623== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)
looking forward to your input :)

BST Invalid read size

I am making a BST for a class assignment, where the Insert function and NodeData class are given. No matter what, when running with Valgrind, I am constantly running into memory leak errors with my DestructorHelper and most of the time my Insert.
Insert - inserting a node into the tree
bool BinTree::insert(NodeData* dataptr) {
Node* ptr = new Node; // exception is thrown if memory is not allocated
ptr->data = dataptr;
ptr->left = ptr->right = nullptr;
if (isEmpty()) {
root = ptr;
} else {
Node* current = root;
bool inserted = false;
// if item is less than current item, insert in left subtree,
// otherwise insert in right subtree
while (!inserted) {
if(*ptr->data == *current->data) {
delete ptr;
return false;
}
if (*ptr->data < *current->data) {
if (current->left == nullptr) { // at leaf, insert left
current->left = ptr;
inserted = true;
}
else
current = current->left; // one step left
}
else {
if (current->right == nullptr) { // at leaf, insert right
current->right = ptr;
inserted = true;
}
else
current = current->right; // one step right
}
}
}
return true;
}
DestructorHelper - called to delete the tree recursively
void BinTree::DestructorHelper(Node*& n) {
if(n) {
DestructorHelper(n->left);
DestructorHelper(n->right);
if(n->data) {
delete n->data;
}
delete n;
}
}
Valgrind Error
==20913== Invalid read of size 8
==20913== at 0x10AA4E: BinTree::insert(NodeData*) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x10A972: BinTree::TreeHelper(NodeData**, int, int) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x10A4CB: BinTree::arrayToBSTree(NodeData**) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x109C8A: main (in /home/UDRIVE/user/prog/a.out)
==20913== Address 0x5a883d0 is 0 bytes inside a block of size 24 free'd
==20913== at 0x4C2D2DB: operator delete(void*) (vg_replace_malloc.c:576)
==20913== by 0x10A70B: BinTree::DestructorHelper(BinTree::Node*&) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x10A268: BinTree::makeEmpty() (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x10A45F: BinTree::bstreeToArray(NodeData**) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x109C71: main (in /home/UDRIVE/user/prog/a.out)
==20913== Block was alloc'd at
==20913== at 0x4C2C21F: operator new(unsigned long) (vg_replace_malloc.c:334)
==20913== by 0x10A9E5: BinTree::insert(NodeData*) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x10A085: buildTree(BinTree&, std::basic_ifstream<char, std::char_traits<char> >&) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x109812: main (in /home/UDRIVE/user/prog/a.out)
==20913==
==20913== Invalid read of size 8
==20913== at 0x4F55F00: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::size() const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22)
==20913== by 0x10AF99: __gnu_cxx::__enable_if<std::__is_char<char>::__value, bool>::__type std::operator==<char>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x10ADA0: NodeData::operator==(NodeData const&) const (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x10AA62: BinTree::insert(NodeData*) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x10A972: BinTree::TreeHelper(NodeData**, int, int) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x10A4CB: BinTree::arrayToBSTree(NodeData**) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x109C8A: main (in /home/UDRIVE/user/prog/a.out)
==20913== Address 0x8 is not stack'd, malloc'd or (recently) free'd
==20913==
==20913==
==20913== Process terminating with default action of signal 11 (SIGSEGV)
==20913== Access not within mapped region at address 0x8
==20913== at 0x4F55F00: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::size() const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.22)
==20913== by 0x10AF99: __gnu_cxx::__enable_if<std::__is_char<char>::__value, bool>::__type std::operator==<char>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x10ADA0: NodeData::operator==(NodeData const&) const (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x10AA62: BinTree::insert(NodeData*) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x10A972: BinTree::TreeHelper(NodeData**, int, int) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x10A4CB: BinTree::arrayToBSTree(NodeData**) (in /home/UDRIVE/user/prog/a.out)
==20913== by 0x109C8A: main (in /home/UDRIVE/user/prog/a.out)
==20913== If you believe this happened as a result of a stack
==20913== overflow in your program's main thread (unlikely but
==20913== possible), you can try to increase the size of the
==20913== main thread stack using the --main-stacksize= flag.
==20913== The main thread stack size used in this run was 8388608.
==20913==
==20913== HEAP SUMMARY:
==20913== in use at exit: 10,928 bytes in 88 blocks
==20913== total heap usage: 120 allocs, 32 frees, 85,440 bytes allocated
==20913==
==20913== LEAK SUMMARY:
==20913== definitely lost: 48 bytes in 2 blocks
==20913== indirectly lost: 624 bytes in 26 blocks
==20913== possibly lost: 0 bytes in 0 blocks
==20913== still reachable: 10,256 bytes in 60 blocks
==20913== suppressed: 0 bytes in 0 blocks
==20913== Rerun with --leak-check=full to see details of leaked memory
==20913==
==20913== For counts of detected and suppressed errors, rerun with: -v
==20913== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault
I have gone about looking online at other pieces of code but I can't seem to find anything that would hint at what I am missing.

Memory leaks when Union was allocated memory using memset

For C++11 and above:
ad_tree_node refers to a Union data structure designed to hold an object of type ad_node or vary_node which are of type struct.
The code compiles but memory leaks are detected when used with valgrind.
Following is the code:
struct ad_node {
std::string tag_;
int count_;
std::vector<int> index_;
bool leaf_;
};
struct vary_node {
std::string tag_;
int index_;
int mcv_;
};
union ad_tree_node {
ad_node ad;
vary_node vy;
ad_tree_node () { std::memset(this, 0, sizeof(ad_node)); }
~ad_tree_node() {}
};
std::string print_ad_tree_node(const ad_tree_node& nd, bool is_ad_node) {
std::string st = "";
if (is_ad_node) {
st += "ad_node: " + nd.ad.tag_+ ", " + std::to_string(nd.ad.count_) + ", ";
if (nd.ad.leaf_) { st += " leaf, "; }
else { st += "non-leaf, "; }
st += "index: ";
std::cout << nd.ad.index_.size();
for (auto x : nd.ad.index_) { st += std::to_string(x) + ", "; }
}
else {
st += "vy_node: " + nd.vy.tag_ + ", mcv_: " + std::to_string(nd.vy.mcv_) + ", ";
st += "index: ";
std::cout << nd.vy.index_;
}
return st;
}
int main () {
ad_node t1;
for (int i = 0; i < 10; ++i) t1.index_.push_back(i);
t1.tag_ = "A";
t1.leaf_ = true;
t1.count_ = 9;
ad_tree_node nd;
nd.ad.tag_ = t1.tag_;
nd.ad.leaf_ = t1.leaf_;
nd.ad.count_ = t1.count_;
nd.ad.index_ = std::move(t1.index_);
std::cout << print_ad_tree_node(nd, true) << std::endl;
return 0;
}
Compiled with following flags:
g++ -std=c++11 -g3 code.cpp
valgrind --leak-check=full ./a.out
Reported leak by valgrind:
==6625== Memcheck, a memory error detector
==6625== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==6625== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==6625== Command: ./a.out
==6625==
10ad_node: A, 9, leaf, index: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
==6625==
==6625== HEAP SUMMARY:
==6625== in use at exit: 72,770 bytes in 3 blocks
==6625== total heap usage: 10 allocs, 7 frees, 73,946 bytes allocated
==6625==
==6625== 2 bytes in 1 blocks are definitely lost in loss record 1 of 3
==6625== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6625== by 0x4F593DE: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_assign(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==6625== by 0x4F596E8: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator=(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==6625== by 0x4022EA: main (code.cpp:56)
==6625==
==6625== 64 bytes in 1 blocks are definitely lost in loss record 2 of 3
==6625== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6625== by 0x40386D: __gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*) (new_allocator.h:104)
==6625== by 0x403518: std::allocator_traits<std::allocator<int> >::allocate(std::allocator<int>&, unsigned long) (alloc_traits.h:491)
==6625== by 0x403257: std::_Vector_base<int, std::allocator<int> >::_M_allocate(unsigned long) (stl_vector.h:170)
==6625== by 0x402D79: void std::vector<int, std::allocator<int> >::_M_emplace_back_aux<int const&>(int const&) (vector.tcc:412)
==6625== by 0x402B24: std::vector<int, std::allocator<int> >::push_back(int const&) (stl_vector.h:923)
==6625== by 0x402295: main (code.cpp:49)
==6625==
==6625== LEAK SUMMARY:
==6625== definitely lost: 66 bytes in 2 blocks
==6625== indirectly lost: 0 bytes in 0 blocks
==6625== possibly lost: 0 bytes in 0 blocks
==6625== still reachable: 72,704 bytes in 1 blocks
==6625== suppressed: 0 bytes in 0 blocks
==6625== Reachable blocks (those to which a pointer was found) are not shown.
==6625== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==6625==
==6625== For counts of detected and suppressed errors, rerun with: -v
==6625== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Your destructor for ad_tree_node is just {}. Unlike normal class types, whose destructors will automatically invoke the destructors for each base class and each member object, for unions you have to do everything yourself. In this case, ~ad_tree_node() does not invoke ~ad_node(), and so all the memory allocated by the std::string and std::vector members is leaked. This is precisely what valgrind is complaining about.
You also have the problem of memset - which doesn't play nicely with non-standard-layout types. memset-ing a string or a vector is UB.
What you really want is a variant:
using ad_tree_node = variant<ad_node, vary_node>;
A variant, in C++ parlance, is like a union - except it knows which type it contains, manages its storage correctly per C++ object semantics, and cleans up after itself. For C++11, a good implementation is Boost.Variant.

C++ - segmentation fault on second binary search

I have a class ledger, whose instances are supposed to store instances of a member class company in two vectors combyID and combyname, sorted by two different criteria - ID and name (both are strings). The vectors start out empty, so instead of sorting them after each new addition of an instance of the member class, a customized binary search methods binsID and binsName search the vectors for the element to be added and if the element isn't found, it is inserted in the vectors. The insert() position is defined by the idx value, modified by the binary search method.
The problem lies within the method NewCo, which calls both binary search methods and eventually inserts the element to the vectors. When the program is run with more than just one NewCo call in the main function, Segmentation fault (core dumped) error is given. The error doesn't appear either if the binsID method isn't called or the insert() isn't called on combyID (omitting the insertion to that vector). I am posting both the code and the valgrind analysis.
The code:
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class ledger
{
public:
bool NewCo (string name, string ID)
{
unsigned int idx_id = 0, idx_name = 0;
bool found1 = binsID(combyID, idx_id, ID); //line 14
bool found2 = binsName(combyname, idx_name, name);
if (found1 == false && found2 == false)
{
company co;
co.co_name = name;
co.co_id = ID;
combyID.insert(combyID.begin() + idx_id, co);
combyname.insert(combyname.begin() + idx_name, co);
return 1;
}
return 0;
}
private:
class company
{
public:
string co_name;
string co_id;
};
vector <company> combyID;
vector <company> combyname;
bool binsName(vector <company> vek, unsigned int & idx, string val)
{
if (vek.size() == 0) return false;
unsigned int begin = 0, end = vek.size() - 1, mid;
while(begin <= end)
{
mid = (begin + end) / 2;
idx = mid;
if (vek[mid].co_name == val)
{
idx = mid;
return true;
}
else if (val < vek[mid].co_name)
end = mid - 1;
else
begin = mid + 1;
}
if (vek[idx].co_name < val) idx++;
return false;
}
bool binsID(vector <company> vek, unsigned int & idx, string val)
{
if (vek.size() == 0) return false;
unsigned int begin = 0, end = vek.size() - 1, mid;
while(begin <= end)
{
mid = (begin + end) / 2;
idx = mid;
if (vek[mid].co_id == val) //line 66
{
idx = mid;
return true;
}
else if (val < vek[mid].co_id)
end = mid - 1;
else
begin = mid + 1;
}
if (vek[idx].co_id < val) idx++;
return false;
}
};
int main ( void )
{
ledger b1;
b1.NewCo( "ABC", "123.456.789" );
b1.NewCo( "DEF", "123.456" ); //line 85
return 0;
}
Valgrind:
==6775== Command: ./a.out -g
==6775==
==6775== Invalid read of size 8
==6775== at 0x4F597B0: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::size() const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==6775== by 0x401C2A: __gnu_cxx::__enable_if<std::__is_char<char>::__value, bool>::__type std::operator==<char>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.h:4913)
==6775== by 0x40177B: ledger::binsID(std::vector<ledger::company, std::allocator<ledger::company> >, unsigned int&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (main.cpp:66)
==6775== by 0x40138B: ledger::NewCo(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (main.cpp:14)
==6775== by 0x40109E: main (main.cpp:85)
==6775== Address 0x2005ab5d68 is not stack'd, malloc'd or (recently) free'd
==6775==
==6775==
==6775== Process terminating with default action of signal 11 (SIGSEGV)
==6775== Access not within mapped region at address 0x2005AB5D68
==6775== at 0x4F597B0: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::size() const (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==6775== by 0x401C2A: __gnu_cxx::__enable_if<std::__is_char<char>::__value, bool>::__type std::operator==<char>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (basic_string.h:4913)
==6775== by 0x40177B: ledger::binsID(std::vector<ledger::company, std::allocator<ledger::company> >, unsigned int&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (main.cpp:66)
==6775== by 0x40138B: ledger::NewCo(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (main.cpp:14)
==6775== by 0x40109E: main (main.cpp:85)
==6775== If you believe this happened as a result of a stack
==6775== overflow in your program's main thread (unlikely but
==6775== possible), you can try to increase the size of the
==6775== main thread stack using the --main-stacksize= flag.
==6775== The main thread stack size used in this run was 8388608.
==6775==
==6775== HEAP SUMMARY:
==6775== in use at exit: 72,896 bytes in 4 blocks
==6775== total heap usage: 4 allocs, 0 frees, 72,896 bytes allocated
==6775==
==6775== LEAK SUMMARY:
==6775== definitely lost: 0 bytes in 0 blocks
==6775== indirectly lost: 0 bytes in 0 blocks
==6775== possibly lost: 0 bytes in 0 blocks
==6775== still reachable: 72,896 bytes in 4 blocks
==6775== suppressed: 0 bytes in 0 blocks
==6775== Rerun with --leak-check=full to see details of leaked memory
==6775==
==6775== For counts of detected and suppressed errors, rerun with: -v
==6775== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
You'll want to review your algorithms in both binsName() and binsID() methods.
For your second pass, the statement:
end = mid - 1;
is producing an end value of -1 (or in this case, UINT_MAX since you're using unsigned integers) as the value of mid is 0.

Why am I getting a segmentation fault? Valgrind?

I have written a program to determine the longest common subsequence between two strings. I have tested my function LCSLength() with a small hard coded test case and it returns the correct value.
Now, I am reading strings from a file to compare, and my program gives me a segmentation fault. Here is the code:
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
using namespace std;
int LCSLength(string X,string Y);
int main()
{
ifstream inData("sequences.dat");
vector<string> lines(1);
string line;
int LCS;
while (getline(inData,line))
{
if (line.empty())
lines.push_back("");
else
lines.back() += line;
}
LCS = LCSLength(lines[0],lines[1]);
cout << "The LCS is: " << LCS << endl;
return 0;
}
int LCSLength(string X,string Y)
{
int m = X.size();
int n = Y.size();
int L[m+1][n+1];
for(int i=0; i<=m; i++)
{
for(int j=0; j<=n; j++)
{
if(i==0 || j==0)
L[i][j] = 0;
else if(X[i-1]==Y[j-1])
L[i][j] = L[i-1][j-1]+1;
else
L[i][j] = max(L[i-1][j],L[i][j-1]);
}
}
return L[m][n];
}
When I compile using -pedantic -ansi, I get the following error: In function LCSLength(std::string, std::string): ISO C++ forbids variable size array 'L'.
I compiled using Valgrind, and here are the errors it produced:
==15183== LEAK SUMMARY:
==15183== definitely lost: 8,624 bytes in 14 blocks
==15183== indirectly lost: 1,168 bytes in 5 blocks
==15183== possibly lost: 5,518 bytes in 58 blocks
==15183== still reachable: 44,925 bytes in 278 blocks
==15183== suppressed: 0 bytes in 0 blocks
==15183== Reachable blocks (those to which a pointer was found) are not shown.
==15183== To see them, rerun with: --leak-check=full --show-reachable=yes
==15183==
==15183== ERROR SUMMARY: 23 errors from 23 contexts (suppressed: 0 from 0)
==15183==
==15183== 1 errors in context 1 of 23:
==15183== Invalid read of size 4
==15183== at 0x38326: std::string::_Rep::_M_grab(std::allocator<char> const&, std::allocator<char> const&) (in /usr/lib/libstdc++.6.0.9.dylib)
==15183== by 0x388EF: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) (in /usr/lib/libstdc++.6.0.9.dylib)
==15183== by 0x100001AAE: main (firstt.cpp:23)
==15183== Address 0xfffffffffffffff8 is not stack'd, malloc'd or (recently) free'd
==15183==
==15183==
==15183== 1 errors in context 2 of 23:
==15183== Invalid read of size 8
==15183== at 0x388DC: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) (in /usr/lib/libstdc++.6.0.9.dylib)
==15183== by 0x100001AAE: main (firstt.cpp:23)
==15183== Address 0x100023d28 is 0 bytes after a block of size 8 alloc'd
==15183== at 0x5237: malloc (in /usr/local/Cellar/valgrind/3.8.1/lib/valgrind/vgpreload_memcheck-amd64-darwin.so)
==15183== by 0x4B346: operator new(unsigned long) (in /usr/lib/libstdc++.6.0.9.dylib)
==15183== by 0x100002DFE: __gnu_cxx::new_allocator<std::string>::allocate(unsigned long, void const*) (new_allocator.h:91)
==15183== by 0x100002E42: std::_Vector_base<std::string, std::allocator<std::string> >::_M_allocate(unsigned long) (stl_vector.h:131)
==15183== by 0x100002E9D: std::_Vector_base<std::string, std::allocator<std::string> >::_Vector_base(unsigned long, std::allocator<std::string> const&) (stl_vector.h:116)
==15183== by 0x1000030E4: std::vector<std::string, std::allocator<std::string> >::vector(unsigned long, std::string const&, std::allocator<std::string> const&) (stl_vector.h:215)
==15183== by 0x1000017D9: main (firstt.cpp:11)
==15183==
==15183== ERROR SUMMARY: 23 errors from 23 contexts (suppressed: 0 from 0)
Segmentation fault: 11
My test file has two lines of sequences. I check lines.size() and it returns 2. I also cout << lines[0] and cout << lines[1] and the correct strings are printed.
Can anyone help me figure this out? Thanks.
your lines vector always contains one element, therefore accesing it by index 1 causes UB
LCS = LCSLength(lines[0],lines[1]);
here ^
Did you confirm that after exiting the while loop, both lines[0] and lines[1] exist? This will happen only if you have at least one empty line in your input file (and recognized as such).
According to Valgrind (do read its output!) - you are doing something wrong from within main (lines 11 or 23) and not from LCSLength.