Calling derived class method from base class destructor - c++

I have the following snippet of destructor code in base class "SceneNode" that is trying to clear its member vector and delete vector's objects that are derived from SceneNode, but getting an error at Deleting child->toString line, can you please point at the right direction:
SceneNode::~SceneNode() {
LOG(DEBUG)<< "Node children size: " + to_string(children.size()) + " [" + toString() + "]";
// clean children nodes
for (SceneNode* child : children) {
LOG(DEBUG) << "Deleting ";
LOG(DEBUG) << "Deleting " + child->toString();
delete child;
LOG(DEBUG) << "Deleted " + child->toString();
}
When I debug, it shows me a correct derived object there:
Name : child
Details:0x3204b40
Default:0x3204b40
Decimal:52448064
Hex:0x3204b40
Binary:11001000000100101101000000
Octal:0310045500
Name : lib::SceneNode
Details:{_vptr.SceneNode = 0x4e3430 <vtable for lib::ImageSceneNode+16>, id = {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x3204c08 "New Node"}}, position = {x = 0, y = 0}, size = {x = 1920, y = 1080}, center = {x = 960, y = 540}, rotation = 0, alpha = 255, enabled = true, visible = true, deleted = false, parent = 0x22fca0, children = {<std::_Vector_base<lib::SceneNode*, std::allocator<lib::SceneNode*> >> = {_M_impl = {<std::allocator<lib::SceneNode*>> = {<__gnu_cxx::new_allocator<lib::SceneNode*>> = {<No data fields>}, <No data fields>}, _M_start = 0x0, _M_finish = 0x0, _M_end_of_storage = 0x0}}, <No data fields>}, animators = {<std::_Vector_base<lib::NodeAnimator*, std::allocator<lib::NodeAnimator*> >> = {_M_impl = {<std::allocator<lib::NodeAnimator*>> = {<__gnu_cxx::new_allocator<lib::NodeAnimator*>> = {<No data fields>}, <No data fields>}, _M_start = 0x0, _M_finish = 0x0, _M_end_of_storage = 0x0}}, <No data fields>}, sceneManager = 0x22fc98}
Default:{...}
Decimal:{...}
Hex:{...}
Binary:{...}
Octal:{...}
Log:
2015-03-09 15:33:39,685 DEBUG [default] [] [virtual lib::SceneNode::~SceneNode()] [..\src\lib\scene\node\SceneNode.cpp:30] Node children size: 1 [SceneNode]
2015-03-09 15:33:39,685 DEBUG [default] [] [virtual lib::SceneNode::~SceneNode()] [..\src\lib\scene\node\SceneNode.cpp:34] Deleting
2015-03-09 15:33:39,685 FATAL [default] CRASH HANDLED; Application has crashed due to [SIGSEGV] signal
Thank you!

First change this:
LOG(DEBUG) << "Deleting " + child->toString();
to this:
LOG(DEBUG) << "Deleting " << child->toString();
Then remove this line, as at this point that variable has been destroyed and you cannot access it (this is the cause of the crash):
LOG(DEBUG) << "Deleted " + child->toString();

Related

std::string class member corrupted with string literal logged by third party macro

Summary:
I have a class implementing shared memory using Boost Interprocess. A segmentation fault occurs from a method read() which accesses the named_condition. When I look at the values of nearby std::string class members in GDB they are corrupted too. One contains the value of a string literal I only log via a third party macro.
I am going to describe the problem, show you the code which sets the intended string values and then ask whether I am causing the problem, or is it the third party logger?
I am using Clang (not GCC).
This problem is incredibly difficult to reproduce. It occurs once every 300+ runs.
Details:
This is my object containing the Boost Interprocess named_condition and nearby std::strings which I noticed had corrupted values:
char a[1000];
std::shared_ptr<bip::named_mutex> mutex{nullptr};
char b[1000];
MyVector* vec{nullptr};
std::shared_ptr<bip::managed_shared_memory> segment{nullptr};
std::shared_ptr<bip::named_condition> cond_empty; // Seg fault
bool destroy_memory{false};
std::string shared_vector_name; // Weird value
std::string shared_mutex_name; // Weird value
std::string shared_cv_name; // Weird value
std::string shared_memory_name; // Weird value
std::string tag_name;
The two char arrays were added weeks ago to detect (probably this same) segmentation fault.
The segmentation fault occurs when I try to access the named_condition when attempting to read the shared memory:
std::vector<T> read(const bool clearAfterReading, const bool readImmediately = false)
{
checkMemory(); // Loops over 'a' and checks for corruption
std::vector<T> readItems;
std::cout << "Reader trying to obtain mutex" << std::endl;
bip::scoped_lock<bip::named_mutex> lock(*sdc.mutex);
if(sdc.vec->empty() && readImmediately == false)
{
std::cout << "Reader waiting. vec size: " << sdc.vec->size() << std::endl;
sdc.cond_empty->wait(lock); //SEG FAULT OCCURS HERE
When I look at the state of sdc.cond_empty in GDB I notice m_base = 0x0:
(gdb) p *(sdc.cond_empty._M_ptr)
$12 = {m_cond = {m_shmem = {<boost::interprocess::ipcdetail::managed_open_or_create_impl_device_holder<false, boost::interprocess::shared_memory_object>> = {<No data fields>}, static ManagedOpenOrCreateUserOffset = 16,
m_mapped_region = {m_base = 0x0, m_size = 104, m_page_offset = 0, m_mode = boost::interprocess::read_write, m_is_xsi = false}}}}
so I assume I am correct that this named_condition has been corrupted?
I then decided to check the values of surrounding std::string class members (scroll right to end):
(gdb) p sdc.shared_vector_name
$22 = {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fff80a0d438 "HandleRunRequest()"}}
(gdb) p sdc.shared_mutex_name
$23 = {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fff80a0d468 "File exists"}}
(gdb) p sdc.shared_cv_name
$24 = {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fff80a0d498 "/abc_shared_memory"}}
(gdb) p sdc.shared_memory_name
$25 = {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fff80a0d408 ""}}
(gdb) p sdc.tag_name
$26 = {static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>}, _M_p = 0x7fffc021d598 "abc"}}
and I notice their values are completely wrong. The values appear to be coming from string literals I log via a third party macro.
The intended std::string values are set via the following code:
This const:
extern "C"
{
const std::string ABC_SH_MEM_NAME = "abc";
}
is passed through the shared memory reader constructor:
sharedMemReader(CONSTS::ABC_SH_MEM_NAME, CONSTS::ABC_SH_MEM_SIZE, true),
via the tag argument:
SharedDataReader(const std::string& tag, const int numBytes, const bool destroyMemory)
{
sdc.initialise(tag, numBytes, destroyMemory);
so hard-coded strings can be appended to tag and assigned to the aforementioned string class members:
void initialise(const std::string& tag, const int numBytes, const bool ownMemory)
{
std::cout << std::endl << "Started initialisation..." << std::endl;
const std::string sharedMemoryName = tag + "_shared_memory";
const std::string sharedVectorName = tag + "_shared_vector";
const std::string sharedMutexName = tag + "_shared_mutex";
const std::string sharedCVName = tag + "_shared_cv";
tag_name = tag;
shared_memory_name = sharedMemoryName;
shared_mutex_name = sharedMutexName;
shared_vector_name = sharedVectorName;
shared_cv_name = sharedCVName;
destroy_memory = ownMemory;
As mentioned previously, shared_vector_name is corrupted with the value "HandleRunRequest()".
My only ever usage of this string/value is calling a third party logging macro:
void MyClass::HandleRunRequest()
{
THIRD_PARTY_LOG_MACRO("HandleRunRequest()");
but this method is not called immediately-near read(), where the seg fault occurs. This method calls a few other methods, before spawning a new thread, which then calls read().
Is there absolutely anything I could be doing to cause this corruption? Or, is the third party logging storing values in random pointer addresses?
I still have the core dump and library, but please be aware this problem is incredibly difficult to reproduce.

Using C++ with boost program options result in a segmentation fault

I wrote a small app which was compiled on a Raspberry Pi2. The program used program option from boost. The Pi died, so I want to run the the app on a new Pi 3. The compiling/linking works without problems. Starting the application result in a segmentation fault.
Some parts of the code:
v_AppName = boost::filesystem::basename(argv[0]);
po::options_description desc("Opties");
ProgramOptions(desc);
po::variables_map vm;
try
{
po::store(po::parse_command_line(argc, argv, desc), vm);
....
Program options function (the part which causes the problem):
void Client::ProgramOptions(boost::program_options::options_description & l_Desc)
{
l_Desc.add_options()
("help,h", "Show help")
("view,v", "View something")
("TEST", po::value<int>(), "TEST");
}
The last line with po::value() in it causes the crash. If i remove this line the program runs.
Stacktrace:
#0 0x76f17f24 in
boost::program_options::value_semantic_codecvt_helper<char>::parse(boost::any&, std::vector<std::string, std::allocator<std::string> > const&, bool) const () from /usr/lib/arm-linux-gnueabihf/libboost_program_options.so.1.55.0
No symbol table info available.
#1 0x76f13220 in boost::program_options::store(boost::program_options::basic_parsed_options<char> const&, boost::program_options::variables_map&, bool) ()
from /usr/lib/arm-linux-gnueabihf/libboost_program_options.so.1.55.0
No symbol table info available.
#2 0x0003cae0 in warmte::Client::Client (this=0x7efff618, argc=1, argv=0x7efff794) at src/client.cpp:38
timeout = {<boost::date_time::base_time<boost::posix_time::ptime, boost::date_time::counted_time_system<boost::date_time::counted_time_rep<boost::posix_time::millisec_posix_time_system_config> > >> = {<boost::operators_impl::less_than_comparable<boost::posix_time::ptime, boost::operators_impl::equality_comparable<boost::posix_time::ptime, boost::posix_time::ptime, boost::operators_impl::operators_detail::empty_base<boost::posix_time::ptime>, boost::operators_impl::operators_detail::false_t>, boost::operators_impl::operators_detail::empty_base<boost::posix_time::ptime>, boost::operators_impl::operators_detail::true_t>> = {<boost::operators_impl::less_than_comparable1<boost::posix_time::ptime, boost::operators_impl::equality_comparable<boost::posix_time::ptime, boost::posix_time::ptime, boost::operators_impl::operators_detail::empty_base<boost::posix_time::ptime>, boost::operators_impl::operators_detail::false_t> >> = {<boost::operators_impl::equality_comparable<boost::posix_time::ptime, boost::posix_time::ptime, boost::operators_impl::operators_detail::empty_base<boost::posix_time::ptime>, boost::operators_impl::operators_detail::false_t>> = {<boost::operators_impl::equality_comparable1<boost::posix_time::ptime, boost::operators_impl::operators_detail::empty_base<boost::posix_time::ptime> >> = {<boost::operators_impl::operators_detail::empty_base<boost::posix_time::ptime>> = {<No data fields>}, <No data fields>}, <No data fields>}, <No data fields>}, <No data fields>}, time_ = {time_count_ = {
value_ = 8569444509916594175}}}, <No data fields>}
desc = {static m_default_line_length = 80, m_caption = "Opties", m_line_length = 80, m_min_description_length = 40,
m_options = std::vector of length 3, capacity 4 = {{px = 0x6d168, pn = {pi_ = 0x6d980}}, {px = 0x6d188, pn = {pi_ = 0x6f588}}, {px = 0x6f628,
pn = {pi_ = 0x6f690}}}, belong_to_group = std::vector<bool> of length 3, capacity 32 = {0, 0, 0},
groups = std::vector of length 0, capacity 0}
vm = <incomplete type>
#3 0x0003c92c in main (argc=1, argv=0x7efff794) at src/client.cpp:17
client = {_vptr.Client = 0x57418 <vtable for warmte::Client+8>, vp_Shm = 0x0, vp_Region = 0x0, v_AppName = "warmteclient", l_Index = 0,
l_Result = 1}
Ok, I linked with the wrong libraries....
The installed boost libraries on a Raspberry will end up in /usr/local/lib
So I added -L/usr/local/lib/ to the linker and changed extend LD_LIBRARY_PATH with /usr/local/lib/. It still remains unclear why this path is not added by default

Reopening mysql connection causes segfault

Simple application causes segfault when I try to connect to the same database twice. It works fine with local database but crashes on second call to open() with any remote tunnel. What could be the cause? Am I doing something I should not be doing?
Obviously this is made up example but in reality I'm trying to manage db connections for a bigger app and manager does similar open/close cycle when requested.
QT version is 5.7.0. Compiled from sources to get better stack trace but not sure if it helped.
Remote MySQL is 5.6.27 (Amazon RDS actually), local is 5.7.17.
It's not eactly happening because I use tunnels. I can create a tunnel to my local database and the app works fine, no crashes.
If I tunnel local database to remote machine and then tunnel back from it to local, app still works. So it's not the latency either.
Code:
#include <QCoreApplication>
#include <QSqlDatabase>
void initDb(QSqlDatabase db) {
QString connectionHost = "127.0.0.1";
int port = 3311; // local tunnel
QString user = "mydbuser";
QString password = "mydbpassword";
QString database = "mydbname";
db.setHostName(connectionHost);
db.setPort(port);
db.setUserName(user);
db.setPassword(password);
db.setDatabaseName(database);
}
int main(int argc, char *argv[]) {
QString name1 = "db1", name2 = "db2";
{
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", name1);
initDb(db);
db.open();
db.close();
}
QSqlDatabase::removeDatabase(name1);
{
QSqlDatabase db1 = QSqlDatabase::addDatabase("QMYSQL", name2);
initDb(db1);
db1.open();
db1.close();
}
QSqlDatabase::removeDatabase(name2);
return 0;
}
Trace:
Thread 1 (Thread 0x7f7603ee3740 (LWP 3505)):
#0 __GI___pthread_mutex_lock (mutex=0x20) at ../nptl/pthread_mutex_lock.c:67
__PRETTY_FUNCTION__ = "__pthread_mutex_lock"
type = <optimized out>
id = <optimized out>
#1 0x00007f75ff228d79 in ?? () from /usr/lib/x86_64-linux-gnu/libmysqlclient.so.20
No symbol table info available.
#2 0x00007f75ff1ff660 in ?? () from /usr/lib/x86_64-linux-gnu/libmysqlclient.so.20
No symbol table info available.
#3 0x00007f75ff1d65e5 in mysql_real_connect () from /usr/lib/x86_64-linux-gnu/libmysqlclient.so.20
No symbol table info available.
#4 0x00007f7603f06a54 in QMYSQLDriver::open (this=0xbd4c90, db=..., user=..., password=..., host=..., port=3311, connOpts=...) at ../../../sql/drivers/mysql/qsql_mysql.cpp:1393
d = 0xbd5ea0
optionFlags = 65536
opts = {<QList<QString>> = {<QListSpecialMethods<QString>> = {<No data fields>}, {p = {static shared_null = {ref = {atomic = {_q_value = {<std::__atomic_base<int>> = {static _S_alignment = 4, _M_i = -1}, <No data fields>}}}, alloc = 0, begin = 0, end = 0, array = {0x0}}, d = 0x7f7603b0ffb0 <QListData::shared_null>}, d = 0x7f7603b0ffb0 <QListData::shared_null>}}, <No data fields>}
unixSocket = {static null = {<No data fields>}, d = 0x7f7603b0c140 <QArrayData::shared_null>}
sslCert = {static null = {<No data fields>}, d = 0x7f7603b0c140 <QArrayData::shared_null>}
sslCA = {static null = {<No data fields>}, d = 0x7f7603b0c140 <QArrayData::shared_null>}
sslKey = {static null = {<No data fields>}, d = 0x7f7603b0c140 <QArrayData::shared_null>}
sslCAPath = {static null = {<No data fields>}, d = 0x7f7603b0c140 <QArrayData::shared_null>}
sslCipher = {static null = {<No data fields>}, d = 0x7f7603b0c140 <QArrayData::shared_null>}
reconnect = 0 '\000'
connectTimeout = 0
readTimeout = 0
writeTimeout = 0
__PRETTY_FUNCTION__ = "virtual bool QMYSQLDriver::open(const QString&, const QString&, const QString&, const QString&, int, const QString&)"
mysql = 0x7ffe4d0aee80
#5 0x00007f7603f2d4b9 in QSqlDatabase::open (this=0x7ffe4d0aef70) at kernel/qsqldatabase.cpp:835
No locals.
#6 0x00000000004010d0 in main (argc=1, argv=0x7ffe4d0af098) at ../main.cpp:31
db1 = {static defaultConnection = 0x7f7603f52bf5 "qt_sql_default_connection", d = 0xbbdee0}
name1 = {static null = {<No data fields>}, d = 0xbbde50}
name2 = {static null = {<No data fields>}, d = 0xbbde80}

How to change std::map in running program from gdb?

I have program which use some 'Log' class for logging. There is static variable inside it where log levels is.
class Log
{
private:
static LogFilter filter;
....
LogFilter has std::map inside where specific log levels are stored
class LogFilter
{
public:
LogFilter();
void setLevel(LogEntryClass::EntryClass e, int level);
int getLevel(LogEntryClass::EntryClass e);
private:
std::map<LogEntryClass::EntryClass, int> filter;
};
And LogEntryClass is class with EntryClass enum inside.
class LogEntryClass
{
public:
enum EntryClass
{
UndefinedLog = 0,
ErrorLog,
WarningLog,
EventLog,
InfoLog,
DebugLog,
UserLog,
CoreInfoLog,
CoreErrorLog,
CoreDebugLog
};
static std::string toString(const EntryClass& e);
};
Log levels is setting at program start up time from config file. But now I want to change log level while program is running. I can attach to it from gdb and print log levels, but I have no idea how to change values in that map
(gdb) print Log::filter.filter
$46 = std::map with 9 elements = {[LogEntryClass::ErrorLog] = 15, [LogEntryClass::WarningLog] = 15,
[LogEntryClass::EventLog] = 15, [LogEntryClass::InfoLog] = 15, [LogEntryClass::DebugLog] = 15, [LogEntryClass::UserLog] = 15,
[LogEntryClass::CoreInfoLog] = 0, [LogEntryClass::CoreErrorLog] = 0, [LogEntryClass::CoreDebugLog] = 0}
even if I take _M_t member of map, I can't see where is its data:
(gdb) print Log::filter.filter._M_t
$47 = {
_M_impl = {<std::allocator<std::_Rb_tree_node<std::pair<LogEntryClass::EntryClass const, int> > >> = {<__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<LogEntryClass::EntryClass const, int> > >> = {<No data fields>}, <No data fields>},
_M_key_compare = {<std::binary_function<LogEntryClass::EntryClass, LogEntryClass::EntryClass, bool>> = {<No data fields>}, <No data fields>}, _M_header = {_M_color = std::_S_red, _M_parent = 0xa04b70, _M_left = 0xa04cf0, _M_right = 0xa04c00},
_M_node_count = 9}}
(gdb) print Log::filter.filter._M_t._M_impl
$48 = {<std::allocator<std::_Rb_tree_node<std::pair<LogEntryClass::EntryClass const, int> > >> = {<__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<LogEntryClass::EntryClass const, int> > >> = {<No data fields>}, <No data fields>},
_M_key_compare = {<std::binary_function<LogEntryClass::EntryClass, LogEntryClass::EntryClass, bool>> = {<No data fields>}, <No data fields>}, _M_header = {_M_color = std::_S_red, _M_parent = 0xa04b70, _M_left = 0xa04cf0, _M_right = 0xa04c00}, _M_node_count = 9}
I can't call any map methods
(gdb) print Log::filter.filter.begin()
One of the arguments you tried to pass to begin could not be converted to what the function wants.
(gdb) print Log::filter.filter.at(1)
One of the arguments you tried to pass to at could not be converted to what the function wants.
What I need is just update one integer value inside map. Is it any way to do it, even any ugly hack?

Gdb debugging c++, object printing

For example I can print this chunk of code with command:
print *hostx
and I get the result:
$22 = (Adaptation::Ecap::XactionRep) {<Adaptation::Initiate> = {<AsyncJob> = {_vptr.AsyncJob = 0x8beac8, stopReason = 0x0,
typeName = 0x662553 "Adaptation::Ecap::XactionRep", inCall = {p_ = 0xc8a440}, id = {static Prefix = 0x65800f "job", value = 50, static Last = 50}},
_vptr.Initiate = 0x8be858, theInitiator = {cbc = 0xc712a0, lock = 0xc71288}}, <libecap::host::Xaction> = {<libecap::Callable> = {
_vptr.Callable = 0x8be958}, <No data fields>}, <BodyConsumer> = {_vptr.BodyConsumer = 0x8bea18}, <BodyProducer> = {_vptr.BodyProducer = 0x8bea58},
theMaster = {<std::tr1::__shared_ptr<libecap::adapter::Xaction, (__gnu_cxx::_Lock_policy)2>> = {_M_ptr = 0xc93c00, _M_refcount = {
_M_pi = 0xc7d520}}, <No data fields>}, theService = {p_ = 0xc56b70}, theVirginRep = {<libecap::Message> = {_vptr.Message = 0x8befd0}, theMessage = {
header = 0xc8be10, body_pipe = {p_ = 0x0}}, theFirstLineRep = 0xca4880, theHeaderRep = 0xcac1f0, theBodyRep = 0x0}, theCauseRep = 0x0,
theAnswerRep = {<std::tr1::__shared_ptr<libecap::Message, (__gnu_cxx::_Lock_policy)2>> = {_M_ptr = 0x0, _M_refcount = {_M_pi = 0x0}}, <No data fields>},
makingVb = Adaptation::Ecap::XactionRep::opNever, proxyingAb = Adaptation::Ecap::XactionRep::opUndecided, adaptHistoryId = -1, vbProductionFinished = false,
abProductionFinished = false, abProductionAtEnd = false, static CBDATA_XactionRep = 22}
Question is how can I print these objects values inside hostx in gdb?
Using standard C/C++ syntax, e.g. print hostx->id