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.
Related
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 :)
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.
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.
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.
Thats the Store Credit problem on Google code jam.
https://code.google.com/codejam/contest/351101/dashboard#s=p0
My code gives out a SIGSEGV after running the large test. But the answer is correct!
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
int ps[1000]={0};
vector<int> indice[1000];
int main() {
int cases; scanf("%d", &cases);
for(int j=1;j<=cases;j++) {
printf("Case #%d: ", j);
int c, is; scanf("%d%d", &c, &is);
for(int i=0;i<=c;i++) ps[i]=0;
for(int i=0;i<=c;i++) indice[i].clear();
for (int i = 0; i < is; i++) {
int it; scanf("%d", &it);
indice[it].push_back(i+1);
ps[it]=1;
if (c-it>0&&ps[c-it]) {
int a, b;
a = indice[it][0];
b = indice[c-it][0];
if(c==2*it&&indice[it].size()>1) {
b=indice[it][1];
}
if (a!=b) {
printf("%d %d\n", min(a,b),max(a,b));
}
}
}
}
return 0;
}
So I use valgrind to find out what's going on .. but it seems that it's not my problem.
==17599== Invalid free() / delete / delete[] / realloc()
==17599== at 0x4C2A4BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==17599== by 0x401669: __gnu_cxx::new_allocator<int>::deallocate(int*, unsigned long) (new_allocator.h:98)
==17599== by 0x4013CD: std::_Vector_base<int, std::allocator<int> >::_M_deallocate(int*, unsigned long) (stl_vector.h:156)
==17599== by 0x400F60: std::_Vector_base<int, std::allocator<int> >::~_Vector_base() (stl_vector.h:142)
==17599== by 0x400D8D: std::vector<int, std::allocator<int> >::~vector() (stl_vector.h:351)
==17599== by 0x400C48: __tcf_0 (a.cpp:6)
==17599== by 0x5383900: __run_exit_handlers (exit.c:78)
==17599== by 0x5383984: exit (exit.c:100)
==17599== by 0x5369773: (below main) (libc-start.c:258)
==17599== Address 0x1 is not stack'd, malloc'd or (recently) free'd
==17599==
==17599==
==17599== HEAP SUMMARY:
==17599== in use at exit: 128 bytes in 1 blocks
==17599== total heap usage: 4,527 allocs, 4,527 frees, 113,664 bytes allocated
==17599==
==17599== LEAK SUMMARY:
==17599== definitely lost: 0 bytes in 0 blocks
==17599== indirectly lost: 0 bytes in 0 blocks
==17599== possibly lost: 0 bytes in 0 blocks
==17599== still reachable: 128 bytes in 1 blocks
==17599== suppressed: 0 bytes in 0 blocks
==17599== Rerun with --leak-check=full to see details of leaked memory
==17599==
==17599== For counts of detected and suppressed errors, rerun with: -v
==17599== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)
I'm so confused... Could anybody tell me what's going on? I'm a newbie of C++ ..
Thank you very much.
As I understand valgrind, it can't detect that you are writing outside of the bounds of arrays that are staticly allocated. So let's allocate them on the heap.
vector<int> *indice = new vector<int>[1000];
int *ps = new int[1000];
Then, you will see errors come out of valgrind. Including:
==7168== Invalid read of size 8
==7168== at 0x4008D6: main (stl_vector.h:735)
==7168== Address 0x4c39e10 is 8 bytes after a block of size 24,008 alloc'd
==7168== at 0x4A07152: operator new[](unsigned long) (vg_replace_malloc.c:363)
==7168== by 0x400791: global constructors keyed to indice (foo.cc:6)
==7168== by 0x400C35: ??? (in /tmp/foo)
==7168== by 0x4005F2: ??? (in /tmp/foo)
==7168==
==7168== Invalid read of size 8
==7168== at 0x4008DA: main (stl_vector.h:735)
==7168== Address 0x4c39e18 is 16 bytes after a block of size 24,008 alloc'd
==7168== at 0x4A07152: operator new[](unsigned long) (vg_replace_malloc.c:363)
==7168== by 0x400791: global constructors keyed to indice (foo.cc:6)
==7168== by 0x400C35: ??? (in /tmp/foo)
==7168== by 0x4005F2: ??? (in /tmp/foo)
==7168==
And using gdb, I can see that the SIGSEGV occurs when you access indice[1433], which is outside of the bounds of indice.
I also imagine that your actual issue is that for the large dataset, the variables bounds are listed as:
N = 50
3 ≤ I ≤ 2000
Are you sure you shouldn't be allocating 2001 elements, instead of 1000?