Is there a way to properly run qmltestrunner against a test, that uses a custom qml module, that is compiled with address sanitizer flags (e.g. --fsanitize=address), and to be able to detect all leaks in this qmlmodule?
The problem is that qmltestrunner is not linked against the address sanitizer, thus it complains regarding the linkage order when importing custom qmlmodule.
> qmltestrunner -import ../../../../build/qmlmodules/ -platform offscreen
==393140==ASan runtime does not come first in the initial library list; you should either link runtime to your application or manually preload it with LD_PRELOAD.
When I am trying to run a qmltestrunner explicitly preloading sanitizer it detects qt internal leaks, but doesn't detect leaks in my qmlmodule:
> LD_PRELOAD=/lib/x86_64-linux-gnu/libasan.so.6 qmltestrunner -import ../../../../build/MyLib/qmlmodules/ -platform offscreen
is 0x12345********* Start testing of qmltestrunner *********
Config: Using QtTest library 5.15.2, Qt 5.15.2 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 10.2.1 20210110), debian 11
PASS : qmltestrunner::TestIoauExample::initTestCase()
PASS : qmltestrunner::TestIoauExample::test_ioau_example()
PASS : qmltestrunner::TestIoauExample::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 2ms
********* Finished testing of qmltestrunner *********
=================================================================
==447337==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 500 byte(s) in 1 object(s) allocated from:
#0 0x7f3f0f3417a7 in operator new[](unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:102
#1 0x7f3f06f6950a in ioau::IoauTester::HeightmapGenerator::HeightmapGenerator(QObject*) (/home/ifolbort/localstorage/workspace/ioau-testbed2/ioau/build/monolith/build/ioau/qmlmodules/IoauTester/libioautester-qmlplugin.so+0x1550a)
#2 0x7f3f06f62223 in void QQmlPrivate::createInto<ioau::IoauTester::HeightmapGenerator>(void*) (/home/ifolbort/localstorage/workspace/ioau-testbed2/ioau/build/monolith/build/ioau/qmlmodules/IoauTester/libioautester-qmlplugin.so+0xe223)
#3 0x7f3f0d4e2c89 in QQmlType::create(QObject**, void**, unsigned long) const (/lib/x86_64-linux-gnu/libQt5Qml.so.5+0x291c89)
#4 0x7f3f0d4c127c in QQmlComponent::QQmlComponent(QQmlEngine*, QObject*) (/lib/x86_64-linux-gnu/libQt5Qml.so.5+0x27027c)
Indirect leak of 168 byte(s) in 1 object(s) allocated from:
#0 0x7f3f0f341647 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
#1 0x7f3f0dd51b53 in QScreen::QScreen(QPlatformScreen*) (/lib/x86_64-linux-gnu/libQt5Gui.so.5+0x165b53)
Indirect leak of 88 byte(s) in 1 object(s) allocated from:
#0 0x7f3f0f341647 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
#1 0x7f3f0efb8d04 in QObject::QObject(QObject*) (/lib/x86_64-linux-gnu/libQt5Core.so.5+0x2e2d04)
Indirect leak of 40 byte(s) in 1 object(s) allocated from:
#0 0x7f3f0f341647 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
#1 0x7f3f076610a8 (/usr/lib/x86_64-linux-gnu/qt5/plugins/platforms/libqoffscreen.so+0x120a8)
Indirect leak of 24 byte(s) in 1 object(s) allocated from:
#0 0x7f3f0f341647 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
#1 0x7f3f07662167 (/usr/lib/x86_64-linux-gnu/qt5/plugins/platforms/libqoffscreen.so+0x13167)
Indirect leak of 16 byte(s) in 1 object(s) allocated from:
#0 0x7f3f0f341647 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
#1 0x7f3f0ede4bb0 in QtSharedPointer::ExternalRefCountData::getAndRef(QObject const*) (/lib/x86_64-linux-gnu/libQt5Core.so.5+0x10ebb0)
Indirect leak of 16 byte(s) in 1 object(s) allocated from:
#0 0x7f3f0f341647 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
#1 0x7f3f0dd01422 in QWindowSystemInterface::handleScreenAdded(QPlatformScreen*, bool) (/lib/x86_64-linux-gnu/libQt5Gui.so.5+0x115422)
#2 0x7773c9c2beee67ff (<unknown module>)
Indirect leak of 16 byte(s) in 1 object(s) allocated from:
#0 0x7f3f0f341647 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
#1 0x7f3f0dd0cadb in QPlatformScreen::QPlatformScreen() (/lib/x86_64-linux-gnu/libQt5Gui.so.5+0x120adb)
SUMMARY: AddressSanitizer: 868 byte(s) leaked in 8 allocation(s).
When I disable Asan linkage order verification test qmltestrunner passes tests, but my leak is not detected:
> ASAN_OPTIONS=verify_asan_link_order=false qmltestrunner -import ../../../../build/MyLib/qmlmodules/ -platform offscreen
is 0x12345********* Start testing of qmltestrunner *********
Config: Using QtTest library 5.15.2, Qt 5.15.2 (x86_64-little_endian-lp64 shared (dynamic) release build; by GCC 10.2.1 20210110), debian 11
PASS : qmltestrunner::TestIoauExample::initTestCase()
PASS : qmltestrunner::TestIoauExample::test_ioau_example()
PASS : qmltestrunner::TestIoauExample::cleanupTestCase()
Totals: 3 passed, 0 failed, 0 skipped, 0 blacklisted, 2ms
********* Finished testing of qmltestrunner *********
qml source file with TestCase i am trying to run:
import QtQuick 2.0
import QtTest 1.2
import MyLibTester 0.1
Item {
TestCase {
name: "TestMyLibExample"
when: heightmapGenerator.ready
function test_mylib_example() {
verify(heightmapGenerator.ready)
}
}
resources: HeightmapGenerator {
id: heightmapGenerator
property bool loaded: false
property bool ready: false
Component.onCompleted: {
ready = true
loaded = true
}
}
}
a leak that I am trying to introduce and which is not detected when running qmltestrunner
--- a/mylib/qmlmodules/MyLibTester/src/HeightmapGenerator.cpp
+++ b/mylib/qmlmodules/MyLibTester/src/HeightmapGenerator.cpp
## -9,6 +9,8 ##
+#include "../tests/leak_tst.h"
namespace mylib
{
namespace MyLibTester
## -35,10 +37,13 ## static float cubicSpline(float x)
}
-
HeightmapGenerator::HeightmapGenerator(QObject* parent)
: QObject(parent)
{
+ auto test_leak = leak_test(500);
+ std::cout << "is "
+ << (test_leak == reinterpret_cast<bool*>(0x12345) ? "NOT" : "")
+ << "0x12345";
}
However, when I compile a simple app with the same leak introduced sanitizer is able to detect the leak:
//leak_tst.h
#ifndef leak_tst
#define leak_tst
bool* leak_test(int n)
{
return new bool[n];
}
#endif
///leak_tst.cpp
#include "leak_tst.h"
#include <iostream>
int main()
{
auto test_leak = leak_test(500);
std::cout << "is "
<< (test_leak == reinterpret_cast<bool*>(0x12345) ? "NOT" : "")
<< "0x12345";
return 0;
}
> leak_tst
is 0x12345
=================================================================
==419360==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 500 byte(s) in 1 object(s) allocated from:
#0 0x7fb68db4b7a7 in operator new[](unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:102
#1 0x55b8687e3132 in main (/home/ifolbort/localstorage/workspace/ioau-testbed2/ioau/build/monolith/build/ioau/qmlmodules/IoauTester/tests/test-leak+0x1132)
#2 0x7fb68d734d09 in __libc_start_main ../csu/libc-start.c:308
SUMMARY: AddressSanitizer: 500 byte(s) leaked in 1 allocation(s).
Related
I'm trying to make a simple freeglut application. I have the following code:
#include "GL/freeglut.h"
#include "glm/glm.hpp"
// global and state variables
namespace globals {
const int screen_width = 720;
const int screen_height = 720;
const int window_position_x = 100;
const int window_position_y = 100;
const glm::vec4 clear_color (0.2f, 0.2f, 0.2f, 1.0f);
}
void display ();
int main (int argc, char** argv) {glutInit(&argc, argv);
// initialize GLUT window size, position, display mode
glutInitWindowSize(globals::screen_width, globals::screen_height);
glutInitWindowPosition(globals::window_position_x, globals::window_position_y);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
// continue execution after window is closed by user
glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
// create a window
glutCreateWindow("Simple GLUT Template");
// setup a display callback that GLUT calls for every render
glutDisplayFunc(display);
// start main loop
glutMainLoop();
return 0;
}
void display () {
using namespace globals;
glClearColor(clear_color.r, clear_color.g, clear_color.b, clear_color.a);
glClear(GL_COLOR_BUFFER_BIT);
glutSwapBuffers();
}
I initialise the program to work with GLUT and create a simple window. For compilation, I use this:
g++ -Wall -Wextra -pedantic -g -DDEBUG_MODE -D_GLIBCXX_DEBUG -fsanitize=address,undefined -lGL -lGLU -lglut simple-glut-template.cpp -o simple-glut-template
When I execute the program and close the window, the address sanitizer seems to pick up on a lot of memory leakage that I cannot seem to fix (output shared below). Any help on understanding what's happening is appreciated. Thanks!
Memory leak found by Address Sanitizer:
=================================================================
==24070==ERROR: LeakSanitizer: detected memory leaks
Indirect leak of 1264 byte(s) in 2 object(s) allocated from:
#0 0x7f299c8b83b7 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7f2998557701 (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xd57701)
#2 0x7f299855a86c (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xd5a86c)
Indirect leak of 632 byte(s) in 1 object(s) allocated from:
#0 0x7f299c8b83b7 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7f2998557701 (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xd57701)
#2 0x7f299855a1d7 (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xd5a1d7)
Indirect leak of 520 byte(s) in 1 object(s) allocated from:
#0 0x7f299c8b83b7 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7f29978b2317 (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xb2317)
Indirect leak of 416 byte(s) in 1 object(s) allocated from:
#0 0x7f299c8b83b7 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7f299ba65b04 (/lib/x86_64-linux-gnu/libGLX_mesa.so.0+0x42b04)
Indirect leak of 416 byte(s) in 2 object(s) allocated from:
#0 0x7f299c8b83b7 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7f299854729e (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xd4729e)
#2 0x7f2998549caf (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xd49caf)
#3 0x7f299855a8eb (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xd5a8eb)
Indirect leak of 120 byte(s) in 1 object(s) allocated from:
#0 0x7f299c8b83b7 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7f299ba7187f (/lib/x86_64-linux-gnu/libGLX_mesa.so.0+0x4e87f)
Indirect leak of 96 byte(s) in 2 object(s) allocated from:
#0 0x7f299c8b83b7 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7f299854e18c (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xd4e18c)
Indirect leak of 96 byte(s) in 2 object(s) allocated from:
#0 0x7f299c8b78d5 in __interceptor_realloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:85
#1 0x7f299855df80 (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xd5df80)
#2 0x7f299854cf16 (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xd4cf16)
Indirect leak of 88 byte(s) in 1 object(s) allocated from:
#0 0x7f299c8b83b7 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7f29978ad39d (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xad39d)
Indirect leak of 88 byte(s) in 1 object(s) allocated from:
#0 0x7f299c8b83b7 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7f299c3009ce in xcb_register_for_special_xge (/lib/x86_64-linux-gnu/libxcb.so.1+0xe9ce)
Indirect leak of 80 byte(s) in 2 object(s) allocated from:
#0 0x7f299c8b89cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x7f299c301872 (/lib/x86_64-linux-gnu/libxcb.so.1+0xf872)
Indirect leak of 56 byte(s) in 1 object(s) allocated from:
#0 0x7f299c8b89cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x7f29978b55fc (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xb55fc)
Indirect leak of 40 byte(s) in 1 object(s) allocated from:
#0 0x7f299c8b83b7 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:77
#1 0x7f299854cd45 (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xd4cd45)
Indirect leak of 32 byte(s) in 2 object(s) allocated from:
#0 0x7f299c8b89cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x7f299c301ab5 (/lib/x86_64-linux-gnu/libxcb.so.1+0xfab5)
Indirect leak of 8 byte(s) in 1 object(s) allocated from:
#0 0x7f299c8b89cf in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x7f299854d7aa (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xd4d7aa)
#2 0x7f299855d270 (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xd5d270)
#3 0x7f299854ca7f (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0xd4ca7f)
#4 0x7f2997985729 (/usr/lib/x86_64-linux-gnu/dri/iris_dri.so+0x185729)
SUMMARY: AddressSanitizer: 3952 byte(s) leaked in 21 allocation(s).
I am testing a class that takes multiple std::unique_ptr in initialisation. Raw pointers of mock objects are allocated with new, and then passed to an injected unique_ptr.
A test without any expectations passes fine. When I add an expectation, I get memory leaks.
The sources:
Tested class:
class TemperatureController : public IController
{
public:
TemperatureController(std::unique_ptr<IOutput> output,
std::unique_ptr<ISensor> sensor,
std::unique_ptr<IRegulator> regulator,
std::unique_ptr<ISetpoint> setpoint,
std::unique_ptr<IEnabler> enabler) :
output(std::move(output)),
sensor(std::move(sensor)),
regulator(std::move(regulator)),
setpoint(std::move(setpoint)),
enabler(std::move(enabler))
{ }
virtual ~TemperatureController(){}
virtual void setup() override;
virtual void controlLoop() override;
private:
std::unique_ptr<IOutput> output;
std::unique_ptr<ISensor> sensor;
std::unique_ptr<IRegulator> regulator;
std::unique_ptr<ISetpoint> setpoint;
std::unique_ptr<IEnabler> enabler;
};
void TemperatureController::controlLoop()
{
cout << "enabler address in sut = " << std::hex << *((int*)(enabler.get())) << endl;
cout << "regulator address in sut = 4" << std::hex << *((int*)(regulator.get())) << endl;
if(enabler->isEnabled())
{
regulator->controllOutput(*output,
*setpoint,
*sensor);
}
}
Test suite:
template <typename T>
auto injectMock(T* ptr)
{
return unique_ptr<T>(ptr);
}
struct TestTemperatureController : public Test
{
MockIEnabler* enabler = new MockIEnabler();
MockIOutput* output = new MockIOutput();
MockIRegulator* regulator = new MockIRegulator();
MockISensor* sensor = new MockISensor();
MockISetpoint* setpoint = new MockISetpoint();
TemperatureController sut{injectMock(output),
injectMock(sensor),
injectMock(regulator),
injectMock(setpoint),
injectMock(enabler)};
TestTemperatureController()
{
cout << "enabler address in test = "
<< std::hex << *((int*)(enabler)) << endl
<< "regulator address in test = "
<< std::hex << *((int*)(regulator)) << endl;
}
};
TEST_F(TestTemperatureController,
WhenEnabled_ShouldAct)
{
EXPECT_CALL(*enabler, isEnabled())
.WillOnce(Return(true));
//EXPECT_CALL(*regulator, controllOutput(_,_,_)) // commented out to make simpler logs
// .Times(AtLeast(1));
sut.controlLoop();
}
I ommited some noise code (includes, namespaces etc.).
When run with valgrind, I get the following output:
==10176== Memcheck, a memory error detector
==10176== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==10176== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==10176== Command: ./unit_tests
==10176==
Running main() from gmock_main.cc
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from TestTemperatureController
[ RUN ] TestTemperatureController.WhenEnabled_ShouldAct
enabler address in test = 54edc8
regulator address in test = 54eb90
enabler address in sut = 54edc8
regulator address in sut = 454eb90
GMOCK WARNING:
Uninteresting mock function call - returning directly.
Function call: controllOutput(#0x5cdf1b0 8-byte object <08-ED 54-00 00-00 00-00>, #0x5cdf430 8-byte object <C0-EA 54-00 00-00 00-00>, #0x5cdf390 8-byte object <D8-EA 54-00 00-00 00-00>)
NOTE: You can safely ignore the above warning unless this call should not happen. Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call. See https://github.com/google/googletest/blob/master/googlemock/docs/CookBook.md#knowing-when-to-expect for details.
[ OK ] TestTemperatureController.WhenEnabled_ShouldAct (282 ms)
[----------] 1 test from TestTemperatureController (297 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (369 ms total)
[ PASSED ] 1 test.
/home/lukasz/workspace/arduino-thermostat/ut/tests/TestTemperatureController/TestTemperatureController.cpp:52: ERROR: this mock object (used in test TestTemperatureController.WhenEnabled_ShouldAct) should be deleted but never is. Its address is #0x5cdf110.
ERROR: 1 leaked mock object found at program exit.
==10176==
==10176== HEAP SUMMARY:
==10176== in use at exit: 74,863 bytes in 37 blocks
==10176== total heap usage: 231 allocs, 194 frees, 124,341 bytes allocated
==10176==
==10176== 403 (16 direct, 387 indirect) bytes in 1 blocks are definitely lost in loss record 35 of 37
==10176== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10176== by 0x4DE485: __gnu_cxx::new_allocator<testing::internal::linked_ptr<testing::internal::ExpectationBase> >::allocate(unsigned long, void const*) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x4DE0F3: std::allocator_traits<std::allocator<testing::internal::linked_ptr<testing::internal::ExpectationBase> > >::allocate(std::allocator<testing::internal::linked_ptr<testing::internal::ExpectationBase> >&, unsigned long) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x4DDA47: std::_Vector_base<testing::internal::linked_ptr<testing::internal::ExpectationBase>, std::allocator<testing::internal::linked_ptr<testing::internal::ExpectationBase> > >::_M_allocate(unsigned long) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x4DD077: void std::vector<testing::internal::linked_ptr<testing::internal::ExpectationBase>, std::allocator<testing::internal::linked_ptr<testing::internal::ExpectationBase> > >::_M_emplace_back_aux<testing::internal::linked_ptr<testing::internal::ExpectationBase> const&>(testing::internal::linked_ptr<testing::internal::ExpectationBase> const&) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x4DC562: std::vector<testing::internal::linked_ptr<testing::internal::ExpectationBase>, std::allocator<testing::internal::linked_ptr<testing::internal::ExpectationBase> > >::push_back(testing::internal::linked_ptr<testing::internal::ExpectationBase> const&) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x4DB252: testing::internal::FunctionMockerBase<bool ()>::AddNewExpectation(char const*, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::tuple<> const&) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x4D9459: testing::internal::MockSpec<bool ()>::InternalExpectedAt(char const*, int, char const*, char const*) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x4D4862: TestTemperatureController_WhenEnabled_ShouldAct_Test::TestBody() (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x52DF4D: void testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x5281B6: void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176== by 0x50C9A9: testing::Test::Run() (in /home/lukasz/workspace/build-arduino-thermostat-Desktop-Domyślna/unit_tests)
==10176==
==10176== LEAK SUMMARY:
==10176== definitely lost: 16 bytes in 1 blocks
==10176== indirectly lost: 387 bytes in 7 blocks
==10176== possibly lost: 0 bytes in 0 blocks
==10176== still reachable: 74,460 bytes in 29 blocks
==10176== suppressed: 0 bytes in 0 blocks
==10176== Reachable blocks (those to which a pointer was found) are not shown.
==10176== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==10176==
==10176== For counts of detected and suppressed errors, rerun with: -v
==10176== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
I'm not really good at googlemock implementation, but for me i seems like there are some expectations allocated, which are not released later. Or is it a false positive?
The question is: How do I deal with that? I want to inject mocks with unique_ptr's. I don't want to change the tested object's interface, of course.
I need some advice how to identify the source of the segfault.
compiled with ASAN:
==21093==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7f09d744d882 bp 0x000000001000 sp 0x62100001c538 T0)
ASAN:DEADLYSIGNAL
AddressSanitizer: nested bug in the same thread, aborting.
started with gdb:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff5eeb882 in __memset_avx2_erms () from /usr/lib/libc.so.6
(gdb) bt
#0 0x00007ffff5eeb882 in __memset_avx2_erms () from /usr/lib/libc.so.6
#1 0xbebebebebebebebe in ?? ()
#2 0xbebebebebebebebe in ?? ()
...
1. Edit:
the output above was compiled for 64bit (x86_64), on 32bit following output is generated:
==8361==ERROR: AddressSanitizer failed to allocate 0x200000 (2097152) bytes of SizeClassAllocator32 (error code: 12)
==8361==Process memory map follows:
0x00200000-0x00300000
0x00400000-0x00500000
...
0xf7791000-0xf7792000 /lib32/ld-2.24.so
0xf7800000-0xffd00000
0xffe34000-0xffe55000 [stack]
==8361==End of process memory map.
==8361==AddressSanitizer CHECK failed: ../../../../../src/libsanitizer/sanitizer_common/sanitizer_common.cc:180 "((0 && "unable to mmap")) != (0)" (0x0, 0x0)
ERROR: Failed to mmap
2. EDIT:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff5eeb882 in __memset_avx2_erms () from /usr/lib/libc.so.6
(gdb) bt
#0 0x00007ffff5eeb882 in __memset_avx2_erms () from /usr/lib/libc.so.6
#1 0xbebebebebebebebe in ?? ()
#2 0xbebebebebebebebe in ?? ()
#3 0xbebebebebebebebe in ?? ()
#4 0xbebebebebebebebe in ?? ()
...
(gdb) record instruction-history
17798 0x00007ffff5eeb8b6 <__memset_avx2_unaligned_erms+22>: cmp $0x40,%rdx
17799 0x00007ffff5eeb8ba <__memset_avx2_unaligned_erms+26>: ja 0x7ffff5eeb8ca <__memset_avx2_unaligned_erms+42>
17800 0x00007ffff5eeb8ca <__memset_avx2_unaligned_erms+42>: cmp $0x800,%rdx
17801 0x00007ffff5eeb8d1 <__memset_avx2_unaligned_erms+49>: ja 0x7ffff5eeb870 <__memset_avx2_erms>
17802 0x00007ffff5eeb870 <__memset_avx2_erms+0>: vzeroupper
17803 0x00007ffff5eeb873 <__memset_avx2_erms+3>: mov %rdx,%rcx
17804 0x00007ffff5eeb876 <__memset_avx2_erms+6>: movzbl %sil,%eax
17805 0x00007ffff5eeb87a <__memset_avx2_erms+10>: mov %rdi,%rdx
17806 0x00007ffff5eeb87d <__memset_avx2_erms+13>: rep stos %al,%es:(%rdi)
17807 0x00007ffff5eeb87f <__memset_avx2_erms+15>: mov %rdx,%rax
not sure what that means/why this causes a segfault?
I need some advice how to identify the source of the segfault.
The GDB stack trace is typical of stack overflow similar to:
int main()
{
char buf[1];
memset(buf, 0xbe, 1<<20);
}
It is surprising that AddressSanitizer didn't catch that overflow.
I would try to debug it with the GDB branch trace support, as described here.
P.S. If you can construct a minimal example, Address Sanitizer developers will be interested in it.
Is it being built and run on different machines/environments?
I observe such segfaults for the executable compiled with asan when it is built and run on different environments/machines (don't observe if the lib versions are same). i.e. without asan the app runs fine on different machine.
In my case, when I run an app with address sanitizer on different machine:
./dummy_logger
ASAN:SIGSEGV
=================================================================
==18213==ERROR: AddressSanitizer: SEGV on unknown address 0x00000000 (pc 0xf7f45e60 bp 0x1ffff000 sp 0xffab0a4c T16777215)
#0 0xf7f45e5f in _dl_get_tls_static_info (/lib/ld-linux.so.2+0x11e5f)
#1 0xf7a59d1c (/usr/lib/i386-linux-gnu/libasan.so.2+0xacd1c)
#2 0xf7a4ddbd (/usr/lib/i386-linux-gnu/libasan.so.2+0xa0dbd)
#3 0xf7f438ea (/lib/ld-linux.so.2+0xf8ea)
#4 0xf7f34cb9 (/lib/ld-linux.so.2+0xcb9)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV ??:0 _dl_get_tls_static_info
==18213==ABORTING
And works fine on the machine where it was compiled.
I have a x86_64 multithreaded application where I try to emulate avr interrupts: when interrupt occurs application and all threads are suspended while interrupt handler execute defined actions.
I thought signals were the solution to do this so I'm trying to catch SIGUSR1 signal, but when I raise SIGUSR1 program exit with a segmentation fault error before executing apply function. (I have tried mutex in isr and signals but removed as actually they run in the main thread)
The code is within 5 files.
isr.h
#ifndef __ISR_H__
#define __ISR_H__
typedef void (*routine_t)(void);
class InterruptServiceRoutine
{
routine_t routine;
bool locked = true;
public:
InterruptServiceRoutine(routine_t isr);
void apply();
void unlock(){locked = false;};
};
typedef InterruptServiceRoutine ISR_t;
#endif // __ISR_H__
isr.cpp:
#include <ISR.h>
InterruptServiceRoutine::InterruptServiceRoutine(routine_t isr): routine(isr){}
void InterruptServiceRoutine::apply()
{
if (!locked) routine();
}
Signals.h:
#ifndef __SIGNALS_H__
#define __SIGNALS_H__
#include <vector>
#include <ISR.h>
#include <signal.h>
class Logger;
class Signals
{
private:
Logger& log;
std::vector<ISR_t*> isr_table;
public:
Signals(Logger&);
~Signals();
unsigned int count(void);
void clear(void);
void connect(ISR_t &isr);
void apply(int);
};
#endif // __SIGNALS_H__
Signals.cpp:
#include <signal.h>
#include <pthread.h>
#include <functional>
#include <ISR.h>
#include <Signals.h>
#include <Logger.h>
using namespace std;
void Signals::apply(int)
{
sigset_t sigs_to_block;
sigfillset(&sigs_to_block);
pthread_sigmask(SIG_BLOCK, &sigs_to_block, NULL);
unsigned int num_interrupts = count();
for (unsigned int i=0; i < num_interrupts; ++i)
{
isr_table[i]->apply();
}
pthread_sigmask(SIG_SETMASK, NULL, NULL);
}
Signals::Signals(Logger& _log): log(_log)
{
clear();
auto _apply = bind1st(mem_fun(&Signals::apply), this);
struct sigaction new_action;
new_action.sa_handler = (__sighandler_t) &_apply;
new_action.sa_flags = 0;
sigfillset(&new_action.sa_mask);
sigaction(SIGUSR1, &new_action, NULL);
pthread_sigmask(SIG_SETMASK, NULL, NULL);
}
Signals::~Signals() {
struct sigaction new_action;
new_action.sa_handler = SIG_DFL;
new_action.sa_flags = 0;
sigemptyset(&new_action.sa_mask);
sigaddset(&new_action.sa_mask, SIGUSR1);
sigaction(SIGUSR1, &new_action, NULL);
clear();
}
void Signals::clear(void)
{
isr_table.clear();
isr_table.reserve(20);
}
unsigned int Signals::count(void)
{
return isr_table.size();
}
void Signals::connect(ISR_t &isr)
{
isr_table.push_back(&isr);
}
SignalsTest.test:
#include <signal.h>
#include <pthread.h>
#include <cxxtest/TestSuite.h>
#include <ISR.h>
#include <Signals.h>
#include <Logger.h>
volatile sig_atomic_t isr_called_count;
void isr(void)
{
++isr_called_count;
}
class SignalsTestSuite: public CxxTest::TestSuite
{
Logger log;
Signals handler;
public:
SignalsTestSuite(void): handler(log){}
void setUp()
{
handler.clear();
isr_called_count = 0;
}
/* ... truncated for more visibility ... */
void testWhenRaiseSIGUSRItCallsAvailableRoutine(void)
{
ISR_t routine(&isr);
routine.unlock();
handler.connect(routine);
handler.connect(routine);
raise(SIGUSR1);
TS_ASSERT_EQUALS(isr_called_count, 2);
}
};
Debug informations:
GNU gdb (Gentoo 7.7.1 p1) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://bugs.gentoo.org/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./out/signals...done.
(gdb) r
Starting program: test/out/signals
warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Running 3 tests..
Program received signal SIGUSR1, User defined signal 1.
0x00007ffff7bd0beb in raise (sig=10) at ../sysdeps/unix/sysv/linux/pt-raise.c:36
36 return INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid),
(gdb) bt
#0 0x00007ffff7bd0beb in raise (sig=10) at ../sysdeps/unix/sysv/linux/pt-raise.c:36
#1 0x0000000000403f38 in SignalsTestSuite::testWhenRaiseSIGUSRItCallsAvailableRoutine (this=this#entry=0x631cc0 <suite_SignalsTestSuite>)
at test/SignalsTest.test:62
#2 0x0000000000403f92 in TestDescription_suite_SignalsTestSuite_testWhenRaiseSIGUSRItCallsAvailableRoutine::runTest (this=<optimized out>) at out/signals.cpp:38
#3 0x000000000040424e in CxxTest::RealTestDescription::run (this=<optimized out>) at /opt/cxxtest/cxxtest/RealDescriptions.cpp:109
#4 0x0000000000409afb in CxxTest::TestRunner::runTest (this=this#entry=0x7fffffffd29f, td=...) at /opt/cxxtest/cxxtest/TestRunner.h:85
#5 0x0000000000409c76 in CxxTest::TestRunner::runSuite (this=this#entry=0x7fffffffd29f, sd=...) at /opt/cxxtest/cxxtest/TestRunner.h:72
#6 0x0000000000409e15 in CxxTest::TestRunner::runWorld (this=this#entry=0x7fffffffd29f) at /opt/cxxtest/cxxtest/TestRunner.h:57
#7 0x0000000000409f52 in CxxTest::TestRunner::runAllTests (listener=...) at /opt/cxxtest/cxxtest/TestRunner.h:34
#8 0x0000000000409f93 in CxxTest::ErrorFormatter::run (this=this#entry=0x7fffffffd320) at /opt/cxxtest/cxxtest/ErrorFormatter.h:59
#9 0x000000000040aa89 in CxxTest::Main<CxxTest::ErrorPrinter> (tmp=..., argc=argc#entry=1, argv=argv#entry=0x7fffffffd448) at /opt/cxxtest/cxxtest/TestMain.h:109
#10 0x0000000000407f62 in main (argc=1, argv=0x7fffffffd448) at out/runner.cpp:18
(gdb) l
31 that. */
32 pid_t pid = THREAD_GETMEM (THREAD_SELF, pid);
33 if (__glibc_unlikely (pid < 0))
34 pid = -pid;
35
36 return INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid),
37 sig);
38 }
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
0x00007fffffffd210 in ?? ()
(gdb) bt
#0 0x00007fffffffd210 in ?? ()
#1 <signal handler called>
#2 0x00007ffff7bd0beb in raise (sig=10) at ../sysdeps/unix/sysv/linux/pt-raise.c:36
#3 0x0000000000403f38 in SignalsTestSuite::testWhenRaiseSIGUSRItCallsAvailableRoutine (this=this#entry=0x631cc0 <suite_SignalsTestSuite>)
at test/SignalsTest.test:62
#4 0x0000000000403f92 in TestDescription_suite_SignalsTestSuite_testWhenRaiseSIGUSRItCallsAvailableRoutine::runTest (this=<optimized out>) at out/signals.cpp:38
#5 0x000000000040424e in CxxTest::RealTestDescription::run (this=<optimized out>) at /opt/cxxtest/cxxtest/RealDescriptions.cpp:109
#6 0x0000000000409afb in CxxTest::TestRunner::runTest (this=this#entry=0x7fffffffd29f, td=...) at /opt/cxxtest/cxxtest/TestRunner.h:85
#7 0x0000000000409c76 in CxxTest::TestRunner::runSuite (this=this#entry=0x7fffffffd29f, sd=...) at /opt/cxxtest/cxxtest/TestRunner.h:72
#8 0x0000000000409e15 in CxxTest::TestRunner::runWorld (this=this#entry=0x7fffffffd29f) at /opt/cxxtest/cxxtest/TestRunner.h:57
#9 0x0000000000409f52 in CxxTest::TestRunner::runAllTests (listener=...) at /opt/cxxtest/cxxtest/TestRunner.h:34
#10 0x0000000000409f93 in CxxTest::ErrorFormatter::run (this=this#entry=0x7fffffffd320) at /opt/cxxtest/cxxtest/ErrorFormatter.h:59
#11 0x000000000040aa89 in CxxTest::Main<CxxTest::ErrorPrinter> (tmp=..., argc=argc#entry=1, argv=argv#entry=0x7fffffffd448) at /opt/cxxtest/cxxtest/TestMain.h:109
#12 0x0000000000407f62 in main (argc=1, argv=0x7fffffffd448) at out/runner.cpp:18
(gdb) l
Line number 39 out of range; ../sysdeps/unix/sysv/linux/pt-raise.c has 38 lines.
(gdb) s
Cannot find bounds of current function
(gdb) c
Continuing.
Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
Memory informations:
$ valgrind --leak-check=full --show-leak-kinds=all ./out/signals
==31715== Memcheck, a memory error detector
==31715== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==31715== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==31715== Command: ./out/signals
==31715==
Running 3 tests..==31715==
==31715== Process terminating with default action of signal 11 (SIGSEGV)
==31715== Bad permissions for mapped region at address 0xFFEFFF1F0
==31715== at 0xFFEFFF1F0: ???
==31715== by 0x409F92FF: ???
==31715== by 0xFFF: ???
==31715== by 0x40AA88FF: ???
==31715==
==31715== HEAP SUMMARY:
==31715== in use at exit: 176 bytes in 2 blocks
==31715== total heap usage: 2 allocs, 0 frees, 176 bytes allocated
==31715==
==31715== 16 bytes in 1 blocks are still reachable in loss record 1 of 2
==31715== at 0x4C294C0: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==31715== by 0x408AB1: CxxTest::ErrorPrinter::ErrorPrinter(std::ostream&, char const*, char const*) (ErrorPrinter.h:43)
==31715== by 0x407F4C: main (runner.cpp:17)
==31715==
==31715== 160 bytes in 1 blocks are still reachable in loss record 2 of 2
==31715== at 0x4C294C0: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==31715== by 0x40B2E3: __gnu_cxx::new_allocator<InterruptServiceRoutine*>::allocate(unsigned long, void const*) (new_allocator.h:104)
==31715== by 0x40B315: std::_Vector_base<InterruptServiceRoutine*, std::allocator<InterruptServiceRoutine*> >::_M_allocate(unsigned long) (in test/out/signals)
==31715== by 0x40B941: InterruptServiceRoutine** std::vector<InterruptServiceRoutine*, std::allocator<InterruptServiceRoutine*> >::_M_allocate_and_copy<std::move_iterator<InterruptServiceRoutine**> >(unsigned long, std::move_iterator<InterruptServiceRoutine**>, std::move_iterator<InterruptServiceRoutine**>) (stl_vector.h:1138)
==31715== by 0x40BA28: std::vector<InterruptServiceRoutine*, std::allocator<InterruptServiceRoutine*> >::reserve(unsigned long) (vector.tcc:75)
==31715== by 0x40AE7D: Signals::clear() (Signals.cpp:57)
==31715== by 0x40AF50: Signals::Signals(Logger&) (Signals.cpp:32)
==31715== by 0x403531: SignalsTestSuite::SignalsTestSuite() (in test/out/signals)
==31715== by 0x40302D: __static_initialization_and_destruction_0(int, int) (signals.cpp:18)
==31715== by 0x403144: _GLOBAL__sub_I_suite_SignalsTestSuite_init (signals.cpp:39)
==31715== by 0x4147EC: __libc_csu_init (elf-init.c:88)
==31715== by 0x5A8DA34: (below main) (libc-start.c:245)
==31715==
==31715== LEAK SUMMARY:
==31715== definitely lost: 0 bytes in 0 blocks
==31715== indirectly lost: 0 bytes in 0 blocks
==31715== possibly lost: 0 bytes in 0 blocks
==31715== still reachable: 176 bytes in 2 blocks
==31715== suppressed: 0 bytes in 0 blocks
==31715==
==31715== For counts of detected and suppressed errors, rerun with: -v
==31715== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Erreur de segmentation
I've tried to figure out why there are missing symbols (0x00007fffffffd210 in ?? () and at 0xFFEFFF1F0: ??? ...):
(gdb) info share
From To Syms Read Shared Object Library
0x00007ffff7ddca80 0x00007ffff7df5960 Yes /lib64/ld-linux-x86-64.so.2
No linux-vdso.so.1
0x00007ffff7bc6a40 0x00007ffff7bd2781 Yes /lib64/libpthread.so.0
0x00007ffff79bb360 0x00007ffff79be0dc Yes /lib64/librt.so.1
0x00007ffff770f5f0 0x00007ffff77733c3 Yes /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/libstdc++.so.6
0x00007ffff73c04f0 0x00007ffff7425266 Yes /lib64/libm.so.6
0x00007ffff71a7ac0 0x00007ffff71b6e45 Yes /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4/libgcc_s.so.1
0x00007ffff6e2c430 0x00007ffff6f53b44 Yes /lib64/libc.so.6
But can't find a way to get "linux-vdso.so.1" on gentoo.
I'm a beginner in C++ what I'm doing wrong with memory ?
Have you a tip to fix this ?
Edit1:
routine_t and __sighandler_t types are aliases for: void (*)(void)
I believe that you can safely ignore the error. A StackOverflow member with a reputation in the top 0.25% of members (!) says that this warning "Could not load shared library symbols for linux-vdso.so.1." is something you can safely ignore. To see the post, go here:
Could not load shared library symbols for linux-vdso.so.1. while debugging
Problem solved thanks to Igor Tandetnik.
Finally the following code function.
signals.h:
#ifndef __SIGNALS_H__
#define __SIGNALS_H__
#include <vector>
#include <ISR.h>
#include <signal.h>
using namespace std;
class Logger;
class Signals
{
private:
Logger& log;
static bool action_handled;
void reserve();
public:
static void start();
static void stop();
static std::vector<ISR_t*> isr_table;
Signals(Logger& _log);
~Signals();
unsigned int count(void);
void clear(void);
void connect(ISR_t&);
static void apply(int);
static void unmask_pthread_signals();
static void mask_pthread_signals();
};
#endif // __SIGNALS_H__
signals.cpp:
#include <functional>
#include <signal.h>
#include <pthread.h>
#include <ISR.h>
#include <Signals.h>
#include <Logger.h>
using namespace std;
vector<ISR_t*> Signals::isr_table={};
bool Signals::action_handled=false;
void Signals::apply(int)
{
mask_pthread_signals();
for (unsigned int i=0; i < isr_table.size(); ++i)
{
isr_table[i]->apply();
}
unmask_pthread_signals();
}
Signals::Signals(Logger& _log): log(_log){
clear();
start();
}
Signals::~Signals() {
clear();
stop();
}
void Signals::clear(void)
{
isr_table.clear();
isr_table.reserve(0);
}
unsigned int Signals::count(void)
{
return isr_table.size();
}
void Signals::start()
{
if (action_handled) return;
struct sigaction new_action;
new_action.sa_handler = (__sighandler_t) &Signals::apply;
new_action.sa_flags = 0;
sigemptyset(&new_action.sa_mask);
sigaction(SIGUSR1, &new_action, NULL);
unmask_pthread_signals();
action_handled = true;
}
void Signals::stop()
{
if (!action_handled) return;
struct sigaction new_action;
new_action.sa_handler = SIG_DFL;
sigemptyset(&new_action.sa_mask);
sigaction(SIGUSR1, &new_action, NULL);
mask_pthread_signals();
action_handled = false;
}
void Signals::unmask_pthread_signals()
{
sigset_t signals_mask;
sigemptyset(&signals_mask);
pthread_sigmask(SIG_SETMASK, &signals_mask, NULL);
}
void Signals::mask_pthread_signals()
{
sigset_t signals_mask;
sigfillset(&signals_mask);
pthread_sigmask(SIG_SETMASK, &signals_mask, NULL);
}
void Signals::reserve()
{
if (isr_table.capacity() <= isr_table.size()) {
isr_table.reserve(isr_table.capacity() + 20);
}
}
void Signals::connect(ISR_t &isr)
{
start();
reserve();
isr_table.push_back(&isr);
}
For a school project, we have to send big files across the network., we must use Poco::XML for our data.
After our files are send over the network, it appears that the memory does not free.
Here is an example for a file of ~9 Mb on the receiving part:
valgrind --leak-check=full --show-reachable=yes -v ourExecutable parms returns:
12,880,736 bytes in 37 blocks are definitely lost in loss record 101 of 101
at 0x4C2747E: operator new(unsigned long) (vg_replace_malloc.c:261)
by 0x5A3AC88: std::string::_Rep::_S_create(unsigned long, unsigned long, std::allocator<char> const&) (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6.0.13)
by 0x5A3BC4A: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned long) (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6.0.13)
by 0x5A3C1BB: std::string::reserve(unsigned long) (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6.0.13)
by 0x5A3C68E: std::string::append(std::string const&) (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.4.4/libstdc++.so.6.0.13)
by 0x5202359: Poco::XML::Element::innerText() const (in /home/tomwij/IGS/trunk/Project/external/lib/libPocoXML.so.8)
by 0x4145BF: NodeProtocol::getChildNodeStrValue(Poco::XML::Element*, std::string) (NodeProtocol.cpp:82)
by 0x41544F: NodeProtocol::deserialize(std::string const&) (NodeProtocol.cpp:200)
by 0x40B088: Node::handleClientPacket(PriorityElement*) (Node.cpp:760)
by 0x40A04C: Node::handlePackets() (Node.cpp:574)
by 0x4078EA: Node::run() (Node.cpp:162)
by 0x40772D: Node::activate() (Node.cpp:138)
LEAK SUMMARY:
definitely lost: 12,888,036 bytes in 190 blocks
indirectly lost: 644,979 bytes in 1,355 blocks
possibly lost: 10,089 bytes in 27 blocks
still reachable: 306,020 bytes in 43 blocks
suppressed: 0 bytes in 0 blocks
The function which is right before Poco is
const string NodeProtocol::getChildNodeStrValue(Element * elem, string child)
{
Element* tempNode = elem->getChildElement(child);
XMLString result(tempNode->innerText());
string ret = string(fromXMLString(result));
result.clear();
return ret;
}
which calls
XMLString Element::innerText() const
{
XMLString result;
Node* pChild = firstChild();
while (pChild)
{
result.append(pChild->innerText());
pChild = pChild->nextSibling();
}
return result;
}
(Note that XMLString is std::string)
Why is the append of STL string leaking memory?
If I just assign instead of using the copy constructors it gives the same problem.
EDIT:
I'm using the latest stable GNU GCC 4.4.4 on Gentoo x64 (linux-2.6.34-gentoo-r12).
More functions from the call stack (stripped irrelevant big chunks of code / if structures):
Command * NodeProtocol::deserialize(const string & msg)
{
DOMParser xmlParser;
// Get the root node.
AutoPtr<Document> doc = xmlParser.parseString(msg);
AutoPtr<Element> rootElement = doc->documentElement();
string root = fromXMLString(rootElement->nodeName());
string name = getChildNodeStrValue(rootElement, "name");
string data = getChildNodeStrValue(rootElement, "data");
return new PutCommand(name, data);
}
and
void Node::handleClientPacket(PriorityElement * prio)
{
Command * command = NodeProtocol::deserialize(prio->fPacket);
// CUT: Access some properties of command, let the command execute.
delete command;
}
and
void Node::handlePackets()
{
PriorityElement * prio = fQueue->top();
fQueue->pop();
if (prio->fSource == kCLIENT)
handleClientPacket(prio);
else if (prio->fSource == kNODE)
handleNodePacket(prio);
delete prio;
}
where fQueue is:
priority_queue< PriorityElement*, vector<PriorityElement*>, ComparisonFunction >
I would make this a comment, but apparently I don't have the rep. Have you remembered to make the destructor for Command virtual? If name or data are fields of PutCommand rather than Command and the Command destructor is not virtual, they may not be freed properly when you delete command in handleClientPacket.