I'm getting a very weird bug when defining a test suite with boost like this:
BOOST_AUTO_TEST_SUITE(zerocoin_implementation_tests)
The error looks like this:
terminate called after throwing an instance of 'std::length_error'
what(): basic_string::_M_create
Here's the relevant backtrace:
#5 0x00007ffff5ce6fe8 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6 0x00007ffff5ce2875 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7 0x00007ffff5d7c949 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_create(unsigned long&, unsigned long) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#8 0x00007ffff70afe15 in boost::unit_test::test_unit::test_unit(boost::unit_test::basic_cstring<char const>, boost::unit_test::basic_cstring<char const>, unsigned long, boost::unit_test::test_unit_type) () from /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.65.1
#9 0x00007ffff70b0456 in boost::unit_test::test_suite::test_suite(boost::unit_test::basic_cstring<char const>, boost::unit_test::basic_cstring<char const>, unsigned long) () from /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.65.1
#10 0x00007ffff70b0612 in boost::unit_test::ut_detail::auto_test_unit_registrar::auto_test_unit_registrar(boost::unit_test::basic_cstring<char const>, boost::unit_test::basic_cstring<char const>, unsigned long, boost::unit_test::decorator::collector&) ()
from /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.65.1
From what I can tell, this has to do with Boost trying to create a max length string. I'd like to see exactly what it is doing. What's the best way of expanding boost macros to see the pre-compiled version?
Side Note
Weirdly, if I change the line very slightly to:
BOOST_AUTO_TEST_SUITE(zerocsoin_implementation_tests)
I get the following error:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
And backtrace:
#6 0x00007ffff5ce7594 in operator new(unsigned long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7 0x00007ffff70afe15 in boost::unit_test::test_unit::test_unit(boost::unit_test::basic_cstring<char const>, boost::unit_test::basic_cstring<char const>, unsigned long, boost::unit_test::test_unit_type) () from /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.65.1
#8 0x00007ffff70b0456 in boost::unit_test::test_suite::test_suite(boost::unit_test::basic_cstring<char const>, boost::unit_test::basic_cstring<char const>, unsigned long) () from /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.65.1
#9 0x00007ffff70b0612 in boost::unit_test::ut_detail::auto_test_unit_registrar::auto_test_unit_registrar(boost::unit_test::basic_cstring<char const>, boost::unit_test::basic_cstring<char const>, unsigned long, boost::unit_test::decorator::collector&) ()
from /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.65.1
The source code for the file (and the rest of the project) can be found here: https://github.com/phoreproject/Phore/blob/segwit/src/test/zerocoin_implementation_tests.cpp
Diff that probably caused the bug: https://github.com/phoreproject/phore/compare/master...segwit#diff-bb4f094cc636d668944ed6af9b72c0d9
Two approaches:
Exception Breakpoints
Just start the test in the debugger and catch the exception.
In gdb you could do
(gdb) catch throw
Catchpoint 2 (throw)
which act like a general breakpoint. Visual Studio has a Manage Exeptions dialog.¹
Boost Test Breakpoints
For debugging Boost Test I like to set a break at the test_method member of the specific test case class I want to break at. E.g. with a test_runner that has a few nested suites like:
./test_runner --list_content
import*
utility*
xml*
xml_utilities*
child_text_test*
loggable_xml_path_test*
And we run these 3 tests like:
./test_runner -t import/utility/xml
Running 3 test cases...
*** No errors detected
To debug them with gdb I'd do
gdb ./test_runner
start -t import/utility/xml
Which stops at main, then I type:
break import::utility::xml
Auto completion helps, so to get the exact names, you can just pick from the completions:
xml
xml::as_element(xmlpp::Node const&)
xml::attr_value(xmlpp::Element const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
xml::attr_value(xmlpp::Node const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
xml::child_text[abi:cxx11](xmlpp::Element const&, char const*)
xml::child_text_test
xml::child_text_test::test_method()
xml::child_text_test_invoker()
xml::child_text_test_registrar62
xml::end_suite94_registrar94
xml::first_child(xmlpp::Element const&, char const*)
xml::get_content[abi:cxx11](xmlpp::Element const&)
xml::get_content[abi:cxx11](xmlpp::Node const*)
xml::is_attr_value(xmlpp::Node const&, 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&)
xml::loggable_xml_path[abi:cxx11](xmlpp::Node const&)
xml::loggable_xml_path_test
xml::loggable_xml_path_test::test_method()
xml::loggable_xml_path_test_invoker()
xml::loggable_xml_path_test_registrar77
xml::trace_xml(xmlpp::Element const&, LogSource::LogTx)
xml::trace_xml_formatted(xmlpp::Element const&, LogSource::LogTx)
xml::xml_registrar20
xml::xml_utilities
xml::xml_utilities::test_method()
xml::xml_utilities_invoker()
xml::xml_utilities_registrar22
Pick the ones named test_method(), e.g.
break import::utility::xml::child_text_test::test_method()
Breakpoint 2 at 0x730762: file /path/src/import/utility/xml_tests.cpp, line 62.
Now you can continue execution and the debugger will automatic pause execution at the start of your unit test.
¹ see also
Make Visual Studio break on User (std::exception) Exceptions?
How do I make VC++'s debugger break on exceptions?
Related
Mock class:
class MockManagerForClient {
public:
MOCK_CONST_METHOD0(GetEngine, std::shared_ptr<engine::Engine>());
MOCK_METHOD1(RemoveClient, void(std::string const& clientId));
virtual ~MockManagerForClient() = default;
};
Test case:
TEST(ClientTest, Login) {
NiceMock<MockManagerForClient> manager;
EXPECT_CALL(manager, RemoveClient(_)).Times(1);
manager.RemoveClient("1");
}
stack capture in gdb:
Catchpoint 1 (signal SIGSEGV), 0x00005555557266f6 in testing::Cardinality::ConservativeUpperBound() const ()
(gdb) bt
#0 0x00005555557266f6 in testing::Cardinality::ConservativeUpperBound() const ()
#1 0x00005555557216c9 in testing::internal::ExpectationBase::CheckActionCountIfNotDone() const ()
#2 0x00005555556ba810 in testing::internal::TypedExpectation<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)>::ShouldHandleArguments(std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&> const&) const (this=0x555555a2c8a0, args=std::tuple containing = {...})
at /home/phillip/.conan/data/googletest/1.8.1/phillip/stable/package/efbe354690ef83824a1e98c7a6076b7ab63bc1b3/include/gmock/gmock-spec-builders.h:1111
#3 0x00005555556b9749 in testing::internal::FunctionMockerBase<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)>::FindMatchingExpectationLocked(std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&> const&) const (this=0x7fffffffda00, args=std::tuple containing = {...})
at /home/phillip/.conan/data/googletest/1.8.1/phillip/stable/package/efbe354690ef83824a1e98c7a6076b7ab63bc1b3/include/gmock/gmock-spec-builders.h:1739
#4 0x00005555556b8b56 in testing::internal::FunctionMockerBase<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)>::UntypedFindMatchingExpectation(void const*, void const**, bool*, std::ostream*, std::ostream*) (this=0x7fffffffda00, untyped_args=0x7fffffffd8f0, untyped_action=0x7fffffffd340, is_excessive=0x7fffffffd337, what=0x7fffffffd3d0, why=0x7fffffffd560)
at /home/phillip/.conan/data/googletest/1.8.1/phillip/stable/package/efbe354690ef83824a1e98c7a6076b7ab63bc1b3/include/gmock/gmock-spec-builders.h:1701
#5 0x000055555572235d in testing::internal::UntypedFunctionMockerBase::UntypedInvokeWith(void*) ()
#6 0x00005555556b56c0 in testing::internal::FunctionMockerBase<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)>::InvokeWith(std::tuple<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>&&) (this=0x7fffffffda00, args=...) at /home/phillip/.conan/data/googletest/1.8.1/phillip/stable/package/efbe354690ef83824a1e98c7a6076b7ab63bc1b3/include/gmock/gmock-spec-builders.h:1602
#7 0x00005555556b4b75 in testing::internal::FunctionMocker<void (std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)>::Invoke(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (this=0x7fffffffda00, a1="1") at /home/phillip/.conan/data/googletest/1.8.1/phillip/stable/package/efbe354690ef83824a1e98c7a6076b7ab63bc1b3/include/gmock/gmock-generated-function-mockers.h:101
#8 0x00005555556b46f0 in MockManagerForClient::RemoveClient (this=0x7fffffffd9b0, gmock_a1=...) at /home/phillip/projects/spiral-front/front/engine-test/src/client-impl/./mocks.hpp:33
#9 0x00005555556b3480 in ClientTest_Login_Test::TestBody (this=0x555555a2c1c0) at /home/phillip/projects/spiral-front/front/engine-test/src/client-impl/client-impl-test.cpp:43
#10 0x000055555575f371 in void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) ()
#11 0x000055555575957b in void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) ()
#12 0x0000555555739298 in testing::Test::Run() ()
#13 0x0000555555739bf5 in testing::TestInfo::Run() ()
#14 0x000055555573a278 in testing::TestCase::Run() ()
#15 0x0000555555745064 in testing::internal::UnitTestImpl::RunAllTests() ()
#16 0x0000555555760519 in bool testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) ()
#17 0x000055555575a35f in bool testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char const*) ()
#18 0x0000555555743aec in testing::UnitTest::Run() ()
#19 0x00005555556fe830 in RUN_ALL_TESTS () at /home/phillip/.conan/data/googletest/1.8.1/phillip/stable/package/efbe354690ef83824a1e98c7a6076b7ab63bc1b3/include/gtest/gtest.h:2341
#20 0x00005555556fe23c in main (argc=1, argv=0x7fffffffe148) at /home/phillip/projects/spiral-front/front/engine-test/src/main.cpp:7
I have tried several hours and no idea why. I have several others mock class, all works find. The most different of this MockManagerForClient is RemoveClient is return void.
I finally fixed the problem after 2 days. Just like other peoples crash situation, it is due project's compile flags not same as googletest.
My environment is Ubuntu 18.04 with g++ 7.4.0.
To make googletest works with c++11 standard, I use master branch of https://github.com/google/googletest. Build googletest with cmake and check cmake generation file: flags.make
googletest use -std=c++11, will my project use -std=gun++11. So adding following cmake definitions:
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
Fixing compile errors due to using c++14 features. Well then the crash issue still there.
Extra compile flags not in my project is: -g -Wall -Wshadow -Werror -Wno-error=dangling-else -DGTEST_HAS_PTHREAD=1 -fexceptions -Wextra -Wno-unused-parameter -Wno-missing-field-initializers
After adding them to my project's CMakeLists.txt and fixing compile errors. googletest crash issue finally gone.
I've recently updated my Gentoo Linux PC with GCC 5.4.0.
I also recompiled all packages depending on gcc (it was mentioned in gcc upgrade guide for gentoo).
Most of programs works well, however my tests, using cppunit, throw std::bad_alloc before starting.
At first I thought there might be a problem with updated version of cppunit, so I downgraded it to previous version, but the problem still exists.
Whenever I start any test, the application immediately throws:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
I started the application in gdb and printed debug backtrace:
#0 0x00007ffff545d218 in raise () from /lib64/libc.so.6
#1 0x00007ffff545e69a in abort () from /lib64/libc.so.6
#2 0x00007ffff5d8f18d in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/libstdc++.so.6
#3 0x00007ffff5d8d046 in ?? () from /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/libstdc++.so.6
#4 0x00007ffff5d8d091 in std::terminate() () from /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/libstdc++.so.6
#5 0x00007ffff5d8d297 in __cxa_throw () from /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/libstdc++.so.6
#6 0x00007ffff5db5f52 in std::__throw_bad_alloc() () from /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/libstdc++.so.6
#7 0x0000000000b2b3ae in __gnu_cxx::new_allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::allocate
(this=0x7fffffffda58, __n=18446741874689290911) at /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/include/g++-v5/ext/new_allocator.h:102
#8 0x0000000000b2b1e2 in std::allocator_traits<std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::allocate (__a=..., __n=18446741874689290911) at /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/include/g++-v5/bits/alloc_traits.h:491
#9 0x0000000000b2b09e in std::__cxx1998::_Vector_base<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_allocate (this=0x7fffffffda58,
__n=18446741874689290911) at /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/include/g++-v5/bits/stl_vector.h:170
#10 0x0000000000b2af71 in std::__cxx1998::_Vector_base<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_M_create_storage (this=0x7fffffffda58,
__n=18446741874689290911) at /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/include/g++-v5/bits/stl_vector.h:185
#11 0x0000000000b2acf1 in std::__cxx1998::_Vector_base<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::_Vector_base (this=0x7fffffffda58,
__n=18446741874689290911, __a=...) at /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/include/g++-v5/bits/stl_vector.h:136
#12 0x0000000000b29c9c in std::__cxx1998::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::vector (this=0x7fffffffda58,
__x=std::__cxx1998::vector of length -2199020260704, capacity -2199020259433 = {...}) at /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/include/g++-v5/bits/stl_vector.h:320
#13 0x0000000000b29449 in std::__debug::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::vector (this=0x7fffffffda40)
at /usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/include/g++-v5/debug/vector:193
#14 0x0000000000b294ef in CppUnit::TestSuiteBuilderContextBase::TestSuiteBuilderContextBase (this=0x7fffffffda20) at /usr/include/cppunit/extensions/TestSuiteBuilderContext.h:29
#15 0x0000000000b29515 in CppUnit::TestSuiteBuilderContext<Types_Decimal>::TestSuiteBuilderContext (this=0x7fffffffda20, contextBase=...) at /usr/include/cppunit/extensions/TestSuiteBuilderContext.h:106
#16 0x0000000000b28a16 in Types_Decimal::addTestsToSuite (baseContext=...) at ./Tests/../../pCpp/CppUnitTests/Types_Decimal.hpp:10
#17 0x0000000000b28caa in Types_Decimal::suite () at ./Tests/../../pCpp/CppUnitTests/Types_Decimal.hpp:12
#18 0x0000000000b2871f in main () at Types_Decimal.cpp:8
There is no problem with test file itself, because I made no changes to it, and lots of test were working for long time.
After looking into stack trace, I'm pretty curious what happened on frame #12: __x=std::**__cxx1998**::vector of length **-2199020260704**, capacity **-2199020259433** = {...}
Why there is cxx1998? Both length and capacity looks pretty insane (uninitialized?).
TestSuiteBuilderContext.h:29:
void
TestSuiteBuilderContextBase::addTest( Test *test )
{
m_suite.addTest( test ); //line 29
}
TestSuite.cpp:
/// Adds a test to the suite.
void
TestSuite::addTest( Test *test )
{
m_tests.push_back( test );
}
I came up with partial solution.
It looks like the compile option:
-D_GLIBCXX_DEBUG
Was causing the problem. After removing it - tests run succesfully.
So I am trying to debug a segfault in a C++ project for school. The project uses a makefile to compile. When I run the program under gdb (using cygwin) I get the segfault but when I try to use the "l" command to show the code I get different code than expected, and when I use "frame", gdb only prints the name of the function instead of the code that last executed.
Program received signal SIGSEGV, Segmentation fault.
0x000000010041570b in NodeCorrectness::eval(Alignment const&) ()
(gdb) l
1 /* advapi32.cc: Win32 replacement functions.
2
3 This file is part of Cygwin.
4
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
8
9 #include "winsup.h"
10 #include <winioctl.h>
(gdb) frame
#0 0x000000010041570b in NodeCorrectness::eval(Alignment const&) ()
(gdb)
Using backtrace I get the following:
(gdb) bt
#0 0x000000000042781b in NodeCorrectness::eval(Alignment const&) ()
#1 0x0000000000421a2f in MeasureCombination::printMeasures(Alignment const&, std::ostream&) const ()
#2 0x00000000004fbedf in makeReport(Graph const&, Graph&, Alignment const&, MeasureCombination const&, Method*, std::basic_ofstream<char, std::char_traits<char> >&)
()
#3 0x00000000004fe6cd in saveReport(Graph const&, Graph&, Alignment const&, MeasureCombination const&, Method*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) ()
#4 0x00000000004d06a7 in NormalMode::run(ArgumentParser&) ()
#5 0x000000000040a655 in main ()
(gdb)
So gdb does not let me see where exactly the segfault occurred. Any reason for this?
I am learning debugging with GDB and I am not sure what to do.
I run a program inside GDB, that I need to get working, and it crashes with SEGFAULT. When I do backtrace inside GDB, I see this.
(gdb) backtrace
#0 0x08200100 in boost::shared_ptr<boost::re_detail::basic_regex_implementation<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > > >::get (this=0x2) at /usr/include/boost/smart_ptr/shared_ptr.hpp:668
#1 0x081f94c3 in boost::basic_regex<char, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::get_traits (this=0x2) at /usr/include/boost/regex/v4/basic_regex.hpp:619
#2 0x081ef769 in boost::re_detail::perl_matcher<__gnu_cxx::__normal_iterator<char const*, std::string>, std::allocator<boost::sub_match<__gnu_cxx::__normal_iterator<char const*, std::string> > >, boost::regex_traits<char, boost::cpp_regex_traits<char> > >::perl_matcher (this=0xb60d3eb4, first=..., end=..., what=..., e=...,
f=boost::regex_constants::match_any, l_base=...) at /usr/include/boost/regex/v4/perl_matcher.hpp:372
#3 0x081e2214 in boost::regex_match<__gnu_cxx::__normal_iterator<char const*, std::string>, std::allocator<boost::sub_match<__gnu_cxx::__normal_iterator<char const*, std::string> > >, char, boost::regex_traits<char, boost::cpp_regex_traits<char> > > (first=..., last=..., m=..., e=..., flags=boost::regex_constants::match_any)
at /usr/include/boost/regex/v4/regex_match.hpp:49
#4 0x081d43bf in boost::regex_match<std::char_traits<char>, std::allocator<char>, char, boost::regex_traits<char, boost::cpp_regex_traits<char> > > (s=..., e=..., flags=boost::regex_constants::match_default)
at /usr/include/boost/regex/v4/regex_match.hpp:100
#5 0x081ca3c1 in [my project] (this=0x2, request=0xb5706630)
at [source of my project]:127
[more calls here]
Now I want to examine what was inside request at #5, on the line 127. Request is a C-style pointer to C++ object of class request_data, which is defined in my project. The definition of my function is bool match_request(request_data *request) const.
What should I write in gdb to actually get to the content of request as it was before the program segfaulted?
Well, your this pointer at #5 does not look too healthy, but aside from that, I think you need a GDB tutorial:
How to change stack frames
How to examine variables
This does it.
(gdb) frame 5
(gdb) print *request
This question already has answers here:
Segfaults in malloc() and malloc_consolidate()
(2 answers)
Closed 7 years ago.
My program goes in segmentation faults, and I cannot find the cause.
The worst part is, the function in question does not always lead to segfault.
GDB confirms the bug and yields this backtrace:
Program received signal SIGSEGV, Segmentation fault.
0xb7da6d6e in malloc_consolidate (av=<value optimized out>) at malloc.c:5169
5169 malloc.c: No such file or directory.
in malloc.c
(gdb) bt
#0 0xb7da6d6e in malloc_consolidate (av=<value optimized out>) at malloc.c:5169
#1 0xb7da9035 in _int_malloc (av=<value optimized out>, bytes=<value optimized out>) at malloc.c:4373
#2 0xb7dab4ac in __libc_malloc (bytes=525) at malloc.c:3660
#3 0xb7f8dc15 in operator new(unsigned int) () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#4 0xb7f72db5 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&) ()
from /usr/lib/i386-linux-gnu/libstdc++.so.6
#5 0xb7f740bf in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::_Rep::_M_clone(std::allocator<char> const&, unsigned int) ()
from /usr/lib/i386-linux-gnu/libstdc++.so.6
#6 0xb7f741f1 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::reserve(unsigned int) () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#7 0xb7f6bfec in std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::overflow(int) () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#8 0xb7f70e1c in std::basic_streambuf<char, std::char_traits<char> >::xsputn(char const*, int) () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#9 0xb7f5b498 in std::ostreambuf_iterator<char, std::char_traits<char> > std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::_M_insert_int<unsigned long>(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, unsigned long) const () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#10 0xb7f5b753 in std::num_put<char, std::ostreambuf_iterator<char, std::char_traits<char> > >::do_put(std::ostreambuf_iterator<char, std::char_traits<char> >, std::ios_base&, char, unsigned long) const () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#11 0xb7f676ac in std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<unsigned long>(unsigned long) ()
from /usr/lib/i386-linux-gnu/libstdc++.so.6
#12 0xb7f67833 in std::basic_ostream<char, std::char_traits<char> >::operator<<(unsigned int) () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#13 0x08049c42 in sim::Address::GetS (this=0xbfffec40) at address.cc:27
#14 0x0806a499 in sim::UserGenerator::ProcessEvent (this=0x80a1af0, e=...) at user-generator.cc:59
#15 0x0806694b in sim::Simulator::CommunicateEvent (this=0x809f970, e=...) at simulator.cc:144
#16 0x0806685d in sim::Simulator::ProcessNextEvent (this=0x809f970) at simulator.cc:133
#17 0x08065d76 in sim::Simulator::Run (seed=0) at simulator.cc:53
#18 0x0807ce85 in main (argc=1, argv=0xbffff454) at main.cc:75
(gdb) f 13
#13 0x08049c42 in sim::Address::GetS (this=0xbfffec40) at address.cc:27
27 oss << m_address;
(gdb) p this->m_address
$1 = 1
Method GetS of class Address translates a number (uint32_t m_address) into a string and returns it. The code (very simple) is the following:
std::string
Address::GetS () const
{
std::ostringstream oss;
oss << m_address;
return oss.str ();
}
Besides, as can be seen in the backtrace, m_address is properly defined.
Now, I have tried to run my program using valgrind.
The program doesn't crash, likely due to the fact that valgrind replaces malloc () among other functions.
The error summary shows no memory leaking:
LEAK SUMMARY:
definitely lost: 0 bytes in 0 blocks
indirectly lost: 0 bytes in 0 blocks
possibly lost: 4,367 bytes in 196 blocks
still reachable: 9,160 bytes in 198 blocks
suppressed: 0 bytes in 0 blocks
All possibly lost refer to backtraces like this:
80 bytes in 5 blocks are possibly lost in loss record 3 of 26
at 0x4024B64: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
by 0x40DBDB4: std::string::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16)
by 0x40DE077: char* std::string::_S_construct<char const*>(char const*, char const*, std::allocator<char> const&, std::forward_iterator_tag) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16)
by 0x40DE1E5: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&) (in /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16)
by 0x806AF62: sim::UserGenerator::CreateUser(unsigned int) (user-generator.cc:152)
I don't think this is related to the bug. However, the code in question can be found following this link.
I am thinking of a bug in libstdc++. However, how likely would that be?
I have also upgraded such library. Here's the versions currently installed on my system.
$ dpkg -l | grep libstdc
ii libstdc++5 1:3.3.6-23 The GNU Standard C++ Library v3
ii libstdc++6 4.6.1-1 GNU Standard C++ Library v3
ii libstdc++6-4.1-dev 4.1.2-27 The GNU Standard C++ Library v3 (development files)
ii libstdc++6-4.3-dev 4.3.5-4 The GNU Standard C++ Library v3 (development files)
ii libstdc++6-4.4-dev 4.4.6-6 GNU Standard C++ Library v3 (development files)
ii libstdc++6-4.5-dev 4.5.3-3 The GNU Standard C++ Library v3 (development files)
ii libstdc++6-4.6-dev 4.6.1-1 GNU Standard C++ Library v3 (development files)
Now the thing is, I am not sure which version g++ uses, and whether there's some means to enforce the use of a particular version.
What I am pondering is to modify GetS. But this is the only method I know. Do you suggest any alternative?
Eventually, I am even considering to replace std::string with simpler char*.
Maybe a little drastic, but I wouldn't set it aside.
Any thought in merit?
Thank you all in advance.
Best,
Jir
Ok. This is NOT the problem:
I am thinking of a bug in libstdc++
The problem is that you overwrote some memory buffer and corrupted one of the structures used by the memory manager. The hard part is going to be finding it. Does not valgrind give you information about writting past the end of an allocated piece of memory.
Don't do this:
Eventually, I am even considering to replace std::string with simpler char*. Maybe a little drastic, but I wouldn't set it aside.
You already have enough problems with memory management. This will just add more problems. There is absolutely NOTHING wrong with std::string or the memory management routines. They are heavily tested and used. If there was something wrong people all over the world would start screaming (it would be big news).
Reading your code at http://mercurial.intuxication.org/hg/lte_sim/file/c2ef6e0b6d41/src/ it seems like you are still stuck in a C style of writting code (C with Classes). So you have the power of C++ to automate (the blowing up of your code) but still have all the problems associated with C.
You need to re-look at your code in terms of ownership. You pass things around by pointer way too much. As a result it is hard to follow the ownership of the pointer (and thus who is responsible for deleting it).
I think you best bet at finding the bug is to write unit tests for each class. Then run the unit tests through val-grind. I know its a pain (but you should have done it to start with now you have the pain all in one go).