This is my first experience with Cairo. I create the surface using this function:
//This function should give us a new x11 surface to draw on.
cairo_surface_t *create_x11_surface(Display *d, int *x, int *y) {
Drawable da;
int screen;
cairo_surface_t *sfc;
Screen *scr;
screen = DefaultScreen(d);
scr = DefaultScreenOfDisplay(d);
if (!*x || !*y) {
*x = WidthOfScreen(scr) / 2;
*y = HeightOfScreen(scr) / 2;
da =
XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, *x, *y, 0, 0, 0);
} else
da =
XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, *x, *y, 0, 0, 0);
XSelectInput(d, da, ButtonPressMask | ButtonReleaseMask | KeyPressMask |
ButtonMotionMask | StructureNotifyMask);
// http://www.lemoda.net/c/xlib-wmclose/index.html
/* "wm_delete_window" is the Atom which corresponds to the delete
window message sent by the window manager. */
Atom wm_delete_window;
wm_delete_window = XInternAtom(d, "WM_DELETE_WINDOW", False);
/* Set up the window manager protocols. The third argument here is
meant to be an array, and the fourth argument is the size of
the array. */
XSetWMProtocols(d, da, &wm_delete_window, 1);
XMapWindow(d, da);
sfc = cairo_xlib_surface_create(d, da, DefaultVisual(d, screen), *x, *y);
return sfc;
}
My main() consists of creating a Drawer object and calling its run method. Drawer is defined as follows (slightly simplified, the unused template parameter is not shown):
struct Drawer {
Drawer() {
d = XOpenDisplay(NULL);
if (d == NULL) {
fprintf(stderr, "Failed to open display\n");
exit(-1);
}
// create a new cairo surface in an x11 window as well as a cairo_t* to
// draw on the x11 window with.
int x=500, y=500;
surface = create_x11_surface(d, &x, &y);
cr = cairo_create(surface);
}
// https://stackoverflow.com/a/19308254/2725810
~Drawer() {
cairo_destroy(cr);
cairo_surface_destroy(surface);
XCloseDisplay(d);
}
// Returns true if need to continue or false if quiting
bool processEvents() {
XEvent e;
if (XPending(cairo_xlib_surface_get_display(surface))) {
XNextEvent(cairo_xlib_surface_get_display(surface), &e);
switch (e.type) {
case ButtonPress:
drag_start_x = e.xbutton.x;
drag_start_y = e.xbutton.y;
break;
case ButtonRelease:
last_delta_x = 0;
last_delta_y = 0;
break;
case MotionNotify:
// http://cairographics.org/manual/cairo-Transformations.html#cairo-translate
cairo_translate(cr, e.xmotion.x - drag_start_x - last_delta_x,
e.xmotion.y - drag_start_y - last_delta_y);
last_delta_x = e.xmotion.x - drag_start_x;
last_delta_y = e.xmotion.y - drag_start_y;
break;
case ConfigureNotify:
cairo_xlib_surface_set_size(surface, e.xconfigure.width,
e.xconfigure.height);
break;
case ClientMessage:
return false;
default:
fprintf(stderr, "Dropping unhandled XEevent.type = %d.\n",
e.type);
}
}
return true;
}
void draw() {
cairo_push_group(cr);
// Clear the background
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_paint(cr);
cairo_set_source_rgb(cr, 0, 1, 0);
cairo_move_to(cr, 0, 0);
cairo_line_to(cr, 256, 256);
cairo_move_to(cr, 256, 0);
cairo_line_to(cr, 0, 256);
cairo_set_line_width(cr, 10.0);
cairo_stroke(cr);
cairo_pop_group_to_source(cr);
cairo_paint(cr);
cairo_surface_flush(surface);
XFlush(d);
}
void run() {
while (1) {
if (!processEvents()) break;
draw();
sleep(0.1);
}
}
private:
Display *d;
cairo_surface_t* surface;
cairo_t* cr;
int last_delta_x = 0, last_delta_y = 0;
int drag_start_x, drag_start_y;
};
The program is compiled with gcc version 4.8.2.
valgrind reports memory leaks and points to calls to cairo_stroke and other Cairo functions as the leak causes. It also says that some memory remains not freed when the program finishes despite the fact that Drawer's destructor gets called. Here is the output of valgrind:
==6897== Memcheck, a memory error detector
==6897== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==6897== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==6897== Command: ./Test
==6897==
Dropping unhandled XEevent.type = 21.
Dropping unhandled XEevent.type = 19.
Dropping unhandled XEevent.type = 65.
==6897==
==6897== HEAP SUMMARY:
==6897== in use at exit: 12,696 bytes in 12 blocks
==6897== total heap usage: 19,039 allocs, 19,027 frees, 8,088,426 bytes allocated
==6897==
==6897== 72 bytes in 1 blocks are still reachable in loss record 1 of 11
==6897== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897== by 0x4E59F7C: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E5B5B9: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E5BAE5: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E5CAB0: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E5D87D: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4EA2050: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4EA3142: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E5FECF: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E57F01: cairo_push_group_with_content (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x40590D: Drawer<NoGraph<StateNeighbor<Pancake, true> > >::draw() (Drawer.h:115)
==6897== by 0x403A7A: Drawer<NoGraph<StateNeighbor<Pancake, true> > >::run() (Drawer.h:138)
==6897==
==6897== 72 bytes in 1 blocks are still reachable in loss record 2 of 11
==6897== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897== by 0x4E59F7C: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E5B5B9: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E5BAE5: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E5CDB2: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4EB4DE3: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E5DA63: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4ECEA3C: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4EA2411: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E651E1: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E5F168: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E58994: cairo_stroke (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==
==6897== 160 bytes in 1 blocks are still reachable in loss record 3 of 11
==6897== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897== by 0x4E850BC: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E851BC: cairo_pattern_create_rgba (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E6028A: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E57FC9: cairo_set_source_rgb (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x405959: Drawer<NoGraph<StateNeighbor<Pancake, true> > >::draw() (Drawer.h:121)
==6897== by 0x403A7A: Drawer<NoGraph<StateNeighbor<Pancake, true> > >::run() (Drawer.h:138)
==6897== by 0x402269: main (Test.cpp:48)
==6897==
==6897== 256 bytes in 2 blocks are still reachable in loss record 4 of 11
==6897== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897== by 0x4E8529A: cairo_pattern_create_for_surface (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E5FD7F: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E57F48: cairo_pop_group (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E5809D: cairo_pop_group_to_source (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x405A38: Drawer<NoGraph<StateNeighbor<Pancake, true> > >::draw() (Drawer.h:129)
==6897== by 0x403A7A: Drawer<NoGraph<StateNeighbor<Pancake, true> > >::run() (Drawer.h:138)
==6897== by 0x402269: main (Test.cpp:48)
==6897==
==6897== 352 bytes in 1 blocks are definitely lost in loss record 5 of 11
==6897== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897== by 0x4ECC831: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4ECC933: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4ECD497: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4EB3922: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4EB4E32: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E5DA63: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4ECEA3C: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4EA2411: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E651E1: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E5F168: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x4E58994: cairo_stroke (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897==
==6897== 1,424 bytes in 1 blocks are still reachable in loss record 6 of 11
==6897== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897== by 0x4E604E7: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==6897== by 0x403A04: Drawer<NoGraph<StateNeighbor<Pancake, true> > >::Drawer(NoGraph<StateNeighbor<Pancake, true> > const&) (Drawer.h:66)
==6897== by 0x40225D: main (Test.cpp:47)
==6897==
==6897== 2,072 bytes in 1 blocks are still reachable in loss record 7 of 11
==6897== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897== by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x5FCBACE: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x5FCD585: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x4010139: call_init.part.0 (dl-init.c:78)
==6897== by 0x4010222: _dl_init (dl-init.c:36)
==6897== by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==6897==
==6897== 2,072 bytes in 1 blocks are still reachable in loss record 8 of 11
==6897== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897== by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x5FCA61F: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x5FCD5A0: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x4010139: call_init.part.0 (dl-init.c:78)
==6897== by 0x4010222: _dl_init (dl-init.c:36)
==6897== by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==6897==
==6897== 2,072 bytes in 1 blocks are still reachable in loss record 9 of 11
==6897== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897== by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x5FE5A8F: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x5FBC1A5: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x5FCD5AB: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x4010139: call_init.part.0 (dl-init.c:78)
==6897== by 0x4010222: _dl_init (dl-init.c:36)
==6897== by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==6897==
==6897== 2,072 bytes in 1 blocks are still reachable in loss record 10 of 11
==6897== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897== by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x60053CF: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x5FCD5AB: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x4010139: call_init.part.0 (dl-init.c:78)
==6897== by 0x4010222: _dl_init (dl-init.c:36)
==6897== by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==6897==
==6897== 2,072 bytes in 1 blocks are still reachable in loss record 11 of 11
==6897== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==6897== by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x5FCFCBF: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==6897== by 0x4010139: call_init.part.0 (dl-init.c:78)
==6897== by 0x4010222: _dl_init (dl-init.c:36)
==6897== by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==6897==
==6897== LEAK SUMMARY:
==6897== definitely lost: 352 bytes in 1 blocks
==6897== indirectly lost: 0 bytes in 0 blocks
==6897== possibly lost: 0 bytes in 0 blocks
==6897== still reachable: 12,344 bytes in 11 blocks
==6897== suppressed: 0 bytes in 0 blocks
==6897==
==6897== For counts of detected and suppressed errors, rerun with: -v
==6897== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
What am I not doing right?
UPDATE: After inserting a call to cairo_debug_reset_static_data() from the destructor as suggested here, the output of valgrind became somewhat shorter:
==7310== Memcheck, a memory error detector
==7310== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7310== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==7310== Command: ./Test
==7310==
Dropping unhandled XEevent.type = 21.
Dropping unhandled XEevent.type = 19.
Dropping unhandled XEevent.type = 65.
==7310==
==7310== HEAP SUMMARY:
==7310== in use at exit: 10,712 bytes in 6 blocks
==7310== total heap usage: 29,352 allocs, 29,346 frees, 12,459,938 bytes allocated
==7310==
==7310== 352 bytes in 1 blocks are definitely lost in loss record 1 of 6
==7310== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7310== by 0x4ECC831: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310== by 0x4ECC933: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310== by 0x4ECD497: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310== by 0x4EB3922: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310== by 0x4EB4E32: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310== by 0x4E5DA63: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310== by 0x4ECEA3C: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310== by 0x4EA2411: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310== by 0x4E651E1: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310== by 0x4E5F168: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310== by 0x4E58994: cairo_stroke (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11301.0)
==7310==
==7310== 2,072 bytes in 1 blocks are still reachable in loss record 2 of 6
==7310== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7310== by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x5FCBACE: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x5FCD585: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x4010139: call_init.part.0 (dl-init.c:78)
==7310== by 0x4010222: _dl_init (dl-init.c:36)
==7310== by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==7310==
==7310== 2,072 bytes in 1 blocks are still reachable in loss record 3 of 6
==7310== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7310== by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x5FCA61F: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x5FCD5A0: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x4010139: call_init.part.0 (dl-init.c:78)
==7310== by 0x4010222: _dl_init (dl-init.c:36)
==7310== by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==7310==
==7310== 2,072 bytes in 1 blocks are still reachable in loss record 4 of 6
==7310== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7310== by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x5FE5A8F: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x5FBC1A5: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x5FCD5AB: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x4010139: call_init.part.0 (dl-init.c:78)
==7310== by 0x4010222: _dl_init (dl-init.c:36)
==7310== by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==7310==
==7310== 2,072 bytes in 1 blocks are still reachable in loss record 5 of 6
==7310== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7310== by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x60053CF: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x5FCD5AB: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x4010139: call_init.part.0 (dl-init.c:78)
==7310== by 0x4010222: _dl_init (dl-init.c:36)
==7310== by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==7310==
==7310== 2,072 bytes in 1 blocks are still reachable in loss record 6 of 6
==7310== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7310== by 0x5FCCE9A: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x5FCFCBF: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x5F7F508: ??? (in /usr/lib/x86_64-linux-gnu/libpixman-1.so.0.30.2)
==7310== by 0x4010139: call_init.part.0 (dl-init.c:78)
==7310== by 0x4010222: _dl_init (dl-init.c:36)
==7310== by 0x4001309: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==7310==
==7310== LEAK SUMMARY:
==7310== definitely lost: 352 bytes in 1 blocks
==7310== indirectly lost: 0 bytes in 0 blocks
==7310== possibly lost: 0 bytes in 0 blocks
==7310== still reachable: 10,360 bytes in 5 blocks
==7310== suppressed: 0 bytes in 0 blocks
==7310==
==7310== For counts of detected and suppressed errors, rerun with: -v
==7310== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
BTW, why doesn't valgrind show the full callstack for the lost record and stops at cairo_stroke instead? My program is compiled with gcc with the -g flag...
UPDATE: As requested in the comments, here is the whole working example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <cairo-xlib.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <unistd.h>
//This function should give us a new x11 surface to draw on.
cairo_surface_t *create_x11_surface(Display *d, int *x, int *y) {
Drawable da;
int screen;
cairo_surface_t *sfc;
Screen *scr;
screen = DefaultScreen(d);
scr = DefaultScreenOfDisplay(d);
if (!*x || !*y) {
*x = WidthOfScreen(scr) / 2;
*y = HeightOfScreen(scr) / 2;
da =
XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, *x, *y, 0, 0, 0);
} else
da =
XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, *x, *y, 0, 0, 0);
XSelectInput(d, da, ButtonPressMask | ButtonReleaseMask | KeyPressMask |
ButtonMotionMask | StructureNotifyMask);
// http://www.lemoda.net/c/xlib-wmclose/index.html
/* "wm_delete_window" is the Atom which corresponds to the delete
window message sent by the window manager. */
Atom wm_delete_window;
wm_delete_window = XInternAtom(d, "WM_DELETE_WINDOW", False);
/* Set up the window manager protocols. The third argument here is
meant to be an array, and the fourth argument is the size of
the array. */
XSetWMProtocols(d, da, &wm_delete_window, 1);
XMapWindow(d, da);
sfc = cairo_xlib_surface_create(d, da, DefaultVisual(d, screen), *x, *y);
return sfc;
}
struct Drawer {
Drawer() {
d = XOpenDisplay(NULL);
if (d == NULL) {
fprintf(stderr, "Failed to open display\n");
exit(-1);
}
// create a new cairo surface in an x11 window as well as a cairo_t* to
// draw on the x11 window with.
int x=500, y=500;
surface = create_x11_surface(d, &x, &y);
cr = cairo_create(surface);
}
// https://stackoverflow.com/a/19308254/2725810
~Drawer() {
cairo_destroy(cr);
cairo_surface_destroy(surface);
XCloseDisplay(d);
}
// Returns true if need to continue or false if quiting
bool processEvents() {
XEvent e;
if (XPending(cairo_xlib_surface_get_display(surface))) {
XNextEvent(cairo_xlib_surface_get_display(surface), &e);
switch (e.type) {
case ButtonPress:
drag_start_x = e.xbutton.x;
drag_start_y = e.xbutton.y;
break;
case ButtonRelease:
last_delta_x = 0;
last_delta_y = 0;
break;
case MotionNotify:
// http://cairographics.org/manual/cairo-Transformations.html#cairo-translate
cairo_translate(cr, e.xmotion.x - drag_start_x - last_delta_x,
e.xmotion.y - drag_start_y - last_delta_y);
last_delta_x = e.xmotion.x - drag_start_x;
last_delta_y = e.xmotion.y - drag_start_y;
break;
case ConfigureNotify:
cairo_xlib_surface_set_size(surface, e.xconfigure.width,
e.xconfigure.height);
break;
case ClientMessage:
return false;
default:
fprintf(stderr, "Dropping unhandled XEevent.type = %d.\n",
e.type);
}
}
return true;
}
void draw() {
cairo_push_group(cr);
// Clear the background
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_paint(cr);
cairo_set_source_rgb(cr, 0, 1, 0);
cairo_move_to(cr, 0, 0);
cairo_line_to(cr, 256, 256);
cairo_move_to(cr, 256, 0);
cairo_line_to(cr, 0, 256);
cairo_set_line_width(cr, 10.0);
cairo_stroke(cr);
cairo_pop_group_to_source(cr);
cairo_paint(cr);
cairo_surface_flush(surface);
XFlush(d);
}
void run() {
while (1) {
if (!processEvents()) break;
draw();
sleep(0.1);
}
}
private:
Display *d;
cairo_surface_t* surface;
cairo_t* cr;
int last_delta_x = 0, last_delta_y = 0;
int drag_start_x, drag_start_y;
};
int main() {
Drawer d;
d.run();
return 0;
}
TL;DR: I don't see any leak.
Here is my version of the valgrind output (with a debug version of cairo and pixman (which means "with symbols"); (Oh and I also added a call to cairo_debug_reset_static_data()):
==4035== HEAP SUMMARY:
==4035== in use at exit: 86,640 bytes in 9 blocks
==4035== total heap usage: 6,736 allocs, 6,727 frees, 6,728,014 bytes allocated
==4035==
==4035== 128 bytes in 1 blocks are still reachable in loss record 1 of 9
==4035== at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035== by 0x4EA6044: cairo_pattern_create_for_surface (cairo-pattern.c:739)
==4035== by 0x4E6507F: _cairo_default_context_pop_group (cairo-default-context.c:238)
==4035== by 0x4E59E10: cairo_pop_group (cairo.c:554)
==4035== by 0x4E59E10: cairo_pop_group_to_source (cairo.c:594)
==4035== by 0x4017E0: Drawer::draw() (test.cpp:120)
==4035== by 0x40183E: Drawer::run() (test.cpp:129)
==4035== by 0x4013C6: main (test.cpp:144)
==4035==
==4035== 1,424 bytes in 1 blocks are still reachable in loss record 2 of 9
==4035== at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035== by 0x4E65D0B: _cairo_default_context_create (cairo-default-context.c:1463)
==4035== by 0x4014B8: Drawer::Drawer() (test.cpp:59)
==4035== by 0x4013BA: main (test.cpp:143)
==4035==
==4035== 2,064 bytes in 1 blocks are still reachable in loss record 3 of 9
==4035== at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035== by 0x636E8AA: _pixman_implementation_create (pixman-implementation.c:38)
==4035== by 0x636D3EE: _pixman_implementation_create_general (pixman-general.c:250)
==4035== by 0x636EF45: _pixman_choose_implementation (pixman-implementation.c:388)
==4035== by 0x63262C8: pixman_constructor (pixman.c:39)
==4035== by 0x400EA09: call_init.part.0 (dl-init.c:78)
==4035== by 0x400EAF2: call_init (dl-init.c:36)
==4035== by 0x400EAF2: _dl_init (dl-init.c:126)
==4035== by 0x40011C9: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==4035==
==4035== 2,064 bytes in 1 blocks are still reachable in loss record 4 of 9
==4035== at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035== by 0x636E8AA: _pixman_implementation_create (pixman-implementation.c:38)
==4035== by 0x636BF3F: _pixman_implementation_create_fast_path (pixman-fast-path.c:3286)
==4035== by 0x636EF60: _pixman_choose_implementation (pixman-implementation.c:391)
==4035== by 0x63262C8: pixman_constructor (pixman.c:39)
==4035== by 0x400EA09: call_init.part.0 (dl-init.c:78)
==4035== by 0x400EAF2: call_init (dl-init.c:36)
==4035== by 0x400EAF2: _dl_init (dl-init.c:126)
==4035== by 0x40011C9: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==4035==
==4035== 2,064 bytes in 1 blocks are still reachable in loss record 5 of 9
==4035== at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035== by 0x636E8AA: _pixman_implementation_create (pixman-implementation.c:38)
==4035== by 0x63871DF: _pixman_implementation_create_mmx (pixman-mmx.c:4021)
==4035== by 0x63543C5: _pixman_x86_get_implementations (pixman-x86.c:234)
==4035== by 0x636EF6B: _pixman_choose_implementation (pixman-implementation.c:393)
==4035== by 0x63262C8: pixman_constructor (pixman.c:39)
==4035== by 0x400EA09: call_init.part.0 (dl-init.c:78)
==4035== by 0x400EAF2: call_init (dl-init.c:36)
==4035== by 0x400EAF2: _dl_init (dl-init.c:126)
==4035== by 0x40011C9: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==4035==
==4035== 2,064 bytes in 1 blocks are still reachable in loss record 6 of 9
==4035== at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035== by 0x636E8AA: _pixman_implementation_create (pixman-implementation.c:38)
==4035== by 0x63A82BF: _pixman_implementation_create_sse2 (pixman-sse2.c:6487)
==4035== by 0x63543A5: _pixman_x86_get_implementations (pixman-x86.c:239)
==4035== by 0x636EF6B: _pixman_choose_implementation (pixman-implementation.c:393)
==4035== by 0x63262C8: pixman_constructor (pixman.c:39)
==4035== by 0x400EA09: call_init.part.0 (dl-init.c:78)
==4035== by 0x400EAF2: call_init (dl-init.c:36)
==4035== by 0x400EAF2: _dl_init (dl-init.c:126)
==4035== by 0x40011C9: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==4035==
==4035== 2,064 bytes in 1 blocks are still reachable in loss record 7 of 9
==4035== at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035== by 0x636E8AA: _pixman_implementation_create (pixman-implementation.c:38)
==4035== by 0x63A895F: _pixman_implementation_create_ssse3 (pixman-ssse3.c:345)
==4035== by 0x636EF6B: _pixman_choose_implementation (pixman-implementation.c:393)
==4035== by 0x63262C8: pixman_constructor (pixman.c:39)
==4035== by 0x400EA09: call_init.part.0 (dl-init.c:78)
==4035== by 0x400EAF2: call_init (dl-init.c:36)
==4035== by 0x400EAF2: _dl_init (dl-init.c:126)
==4035== by 0x40011C9: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==4035==
==4035== 2,064 bytes in 1 blocks are still reachable in loss record 8 of 9
==4035== at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035== by 0x636E8AA: _pixman_implementation_create (pixman-implementation.c:38)
==4035== by 0x63714CF: _pixman_implementation_create_noop (pixman-noop.c:155)
==4035== by 0x63262C8: pixman_constructor (pixman.c:39)
==4035== by 0x400EA09: call_init.part.0 (dl-init.c:78)
==4035== by 0x400EAF2: call_init (dl-init.c:36)
==4035== by 0x400EAF2: _dl_init (dl-init.c:126)
==4035== by 0x40011C9: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==4035==
==4035== 72,704 bytes in 1 blocks are still reachable in loss record 9 of 9
==4035== at 0x4C28C4F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4035== by 0x554E11F: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==4035== by 0x400EA09: call_init.part.0 (dl-init.c:78)
==4035== by 0x400EAF2: call_init (dl-init.c:36)
==4035== by 0x400EAF2: _dl_init (dl-init.c:126)
==4035== by 0x40011C9: ??? (in /lib/x86_64-linux-gnu/ld-2.19.so)
==4035==
==4035== LEAK SUMMARY:
==4035== definitely lost: 0 bytes in 0 blocks
==4035== indirectly lost: 0 bytes in 0 blocks
==4035== possibly lost: 0 bytes in 0 blocks
==4035== still reachable: 86,640 bytes in 9 blocks
==4035== suppressed: 0 bytes in 0 blocks
==4035==
==4035== For counts of detected and suppressed errors, rerun with: -v
==4035== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
No idea about the leaks in libstdc++, but since this in _dl_init, it should be harmless (one-time "leak" during startup).
The same holds for pixman_constructor: Pixman uses optimized code paths based on the CPU on which it runs. This is a one-time initialization that allocates memory that cannot be freed. It's harmless.
That leaves only two leaks. The pattern that is internally allocated in cairo_pop_group_to_source() isn't freed, but so is the cairo context created by cairo_create(). These leaks occurred because I mis-placed the call to cairo_debug_reset_static_data(). I was calling this in main which is before the destructor runs. Moving it to the destructor makes this leak disappear... Sorry for not noticing this earlier and sorry for being too lazy to update the above.
So for me there is an expected leak from pixman and an unexpected leak from libstdc++. Neither is related to cairo. I used cairo version 1.14.2-95-g98d01cd for this.
Related
I was getting reports of memory leaks from valgrind in my production code. So, naturally, I narrowed it down to a minimal compilable example. Strange thins is, I had to "minimize it", so much, that there is nothing left except instantiation of a Qt Window!
Is Qt bugged? Did I not invoke valgrind properly?
My tools and versions, from Centos 7:
cmake3 3.17.2
gcc 8.3.1
Qt 5.14
valgrind 3.14.0
It is currently checked it into my github at https://github.com/ChristopherPisz/QMainWindowLeaks However, I will list it here for the future when it isn't there any longer.
mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Qt MainWindow Leaks</string>
</property>
<widget class="QWidget" name="centralwidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout"/>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>25</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionExit">
<property name="text">
<string>Exit</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>
mainwindow.hpp
#ifndef QTPROBLEMS_MAINWINDOW_HPP
#define QTPROBLEMS_MAINWINDOW_HPP
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui
{
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow final : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget* parent = nullptr);
~MainWindow() override;
private:
Ui::MainWindow* m_ui; ///< Qt generated object that is the main window
};
#endif
mainwindow.cpp
#include "mainwindow.hpp"
#include "./ui_mainwindow.h"
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent)
, m_ui(new Ui::MainWindow)
{
m_ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete m_ui;
}
main.cpp
#include "mainwindow.hpp"
#include <iostream>
#include <QtWidgets/QApplication>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
MainWindow window;
window.show();
int returnCode = 1;
try
{
returnCode = QApplication::exec();
}
catch(std::exception& e)
{
std::cerr << "An unhandled std::exception has escaped the main event loop: {}", e.what();
}
catch(...)
{
std::cerr << "An unhandled exception, of unknown type, has escaped the main event loop";
}
return returnCode;
}
CmakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(qtproblems)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
find_package(Qt5 5.14 REQUIRED COMPONENTS Core Widgets)
set(MOC_HEADERS
mainwindow.hpp
)
set(UI_FORMS
mainwindow.ui
)
add_executable(qtproblems
${MOC_HEADERS}
${UI_FORMS}
mainwindow.cpp
main.cpp
)
target_link_libraries(qtproblems PRIVATE
Qt5::Core
Qt5::Widgets
)
Output:
==26444== Memcheck, a memory error detector
==26444== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==26444== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==26444== Command: /home/cpisz/git-workspace/QMainWindowLeaks/cmake-build-debug/qtproblems
==26444== Parent PID: 31394
==26444==
==26444==
==26444== HEAP SUMMARY:
==26444== in use at exit: 305,230 bytes in 6,852 blocks
==26444== total heap usage: 107,812 allocs, 100,960 frees, 232,668,695 bytes allocated
==26444==
==26444== 38 bytes in 1 blocks are definitely lost in loss record 73 of 284
==26444== at 0x4C29E63: malloc (vg_replace_malloc.c:309)
==26444== by 0x1664CF1E: ???
==26444== by 0x1662FC54: ???
==26444== by 0x1327FC80: q_dbus_bus_get_private(DBusBusType, DBusError*) (qdbus_symbols_p.h:198)
==26444== by 0x13280818: QDBusConnectionManager::executeConnectionRequest(QDBusConnectionManager::ConnectionRequestData*) (qdbusconnection.cpp:263)
==26444== by 0x13286D27: QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void, void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*)>::call(void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QDBusConnectionManager*, void**) (qobjectdefs_impl.h:152)
==26444== by 0x13286ABC: void QtPrivate::FunctionPointer<void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*)>::call<QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void>(void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QDBusConnectionManager*, void**) (qobjectdefs_impl.h:185)
==26444== by 0x13285FF3: QtPrivate::QSlotObject<void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (qobjectdefs_impl.h:414)
==26444== by 0x670D63C: QtPrivate::QSlotObjectBase::call(QObject*, void**) (qobjectdefs_impl.h:394)
==26444== by 0x673DB2E: QMetaCallEvent::placeMetaCall(QObject*) (qobject.cpp:619)
==26444== by 0x673EAF3: QObject::event(QEvent*) (qobject.cpp:1339)
==26444== by 0x649CA55: QThread::event(QEvent*) (qthread.cpp:980)
==26444==
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
obj:*
obj:*
fun:_ZL22q_dbus_bus_get_private11DBusBusTypeP9DBusError
fun:_ZN22QDBusConnectionManager24executeConnectionRequestEPNS_21ConnectionRequestDataE
fun:_ZN9QtPrivate11FunctorCallINS_11IndexesListIJLi0EEEENS_4ListIJPN22QDBusConnectionManager21ConnectionRequestDataEEEEvMS4_FvS6_EE4callES9_PS4_PPv
fun:_ZN9QtPrivate15FunctionPointerIM22QDBusConnectionManagerFvPNS1_21ConnectionRequestDataEEE4callINS_4ListIJS3_EEEvEEvS5_PS1_PPv
fun:_ZN9QtPrivate11QSlotObjectIM22QDBusConnectionManagerFvPNS1_21ConnectionRequestDataEENS_4ListIJS3_EEEvE4implEiPNS_15QSlotObjectBaseEP7QObjectPPvPb
fun:_ZN9QtPrivate15QSlotObjectBase4callEP7QObjectPPv
fun:_ZN14QMetaCallEvent13placeMetaCallEP7QObject
fun:_ZN7QObject5eventEP6QEvent
fun:_ZN7QThread5eventEP6QEvent
}
==26444== 72 (24 direct, 48 indirect) bytes in 1 blocks are definitely lost in loss record 141 of 284
==26444== at 0x4C29E63: malloc (vg_replace_malloc.c:309)
==26444== by 0x1664ED05: ???
==26444== by 0x1664ED66: ???
==26444== by 0x1662F97D: ???
==26444== by 0x1327FC80: q_dbus_bus_get_private(DBusBusType, DBusError*) (qdbus_symbols_p.h:198)
==26444== by 0x13280818: QDBusConnectionManager::executeConnectionRequest(QDBusConnectionManager::ConnectionRequestData*) (qdbusconnection.cpp:263)
==26444== by 0x13286D27: QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void, void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*)>::call(void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QDBusConnectionManager*, void**) (qobjectdefs_impl.h:152)
==26444== by 0x13286ABC: void QtPrivate::FunctionPointer<void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*)>::call<QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void>(void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QDBusConnectionManager*, void**) (qobjectdefs_impl.h:185)
==26444== by 0x13285FF3: QtPrivate::QSlotObject<void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (qobjectdefs_impl.h:414)
==26444== by 0x670D63C: QtPrivate::QSlotObjectBase::call(QObject*, void**) (qobjectdefs_impl.h:394)
==26444== by 0x673DB2E: QMetaCallEvent::placeMetaCall(QObject*) (qobject.cpp:619)
==26444== by 0x673EAF3: QObject::event(QEvent*) (qobject.cpp:1339)
==26444==
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
obj:*
obj:*
obj:*
fun:_ZL22q_dbus_bus_get_private11DBusBusTypeP9DBusError
fun:_ZN22QDBusConnectionManager24executeConnectionRequestEPNS_21ConnectionRequestDataE
fun:_ZN9QtPrivate11FunctorCallINS_11IndexesListIJLi0EEEENS_4ListIJPN22QDBusConnectionManager21ConnectionRequestDataEEEEvMS4_FvS6_EE4callES9_PS4_PPv
fun:_ZN9QtPrivate15FunctionPointerIM22QDBusConnectionManagerFvPNS1_21ConnectionRequestDataEEE4callINS_4ListIJS3_EEEvEEvS5_PS1_PPv
fun:_ZN9QtPrivate11QSlotObjectIM22QDBusConnectionManagerFvPNS1_21ConnectionRequestDataEENS_4ListIJS3_EEEvE4implEiPNS_15QSlotObjectBaseEP7QObjectPPvPb
fun:_ZN9QtPrivate15QSlotObjectBase4callEP7QObjectPPv
fun:_ZN14QMetaCallEvent13placeMetaCallEP7QObject
fun:_ZN7QObject5eventEP6QEvent
}
==26444== 73 bytes in 1 blocks are definitely lost in loss record 142 of 284
==26444== at 0x4C29E63: malloc (vg_replace_malloc.c:309)
==26444== by 0x1664CF1E: ???
==26444== by 0x1662F3B4: ???
==26444== by 0x1662FAC2: ???
==26444== by 0x1327FC80: q_dbus_bus_get_private(DBusBusType, DBusError*) (qdbus_symbols_p.h:198)
==26444== by 0x13280818: QDBusConnectionManager::executeConnectionRequest(QDBusConnectionManager::ConnectionRequestData*) (qdbusconnection.cpp:263)
==26444== by 0x13286D27: QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void, void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*)>::call(void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QDBusConnectionManager*, void**) (qobjectdefs_impl.h:152)
==26444== by 0x13286ABC: void QtPrivate::FunctionPointer<void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*)>::call<QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void>(void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QDBusConnectionManager*, void**) (qobjectdefs_impl.h:185)
==26444== by 0x13285FF3: QtPrivate::QSlotObject<void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (qobjectdefs_impl.h:414)
==26444== by 0x670D63C: QtPrivate::QSlotObjectBase::call(QObject*, void**) (qobjectdefs_impl.h:394)
==26444== by 0x673DB2E: QMetaCallEvent::placeMetaCall(QObject*) (qobject.cpp:619)
==26444== by 0x673EAF3: QObject::event(QEvent*) (qobject.cpp:1339)
==26444==
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
obj:*
obj:*
obj:*
fun:_ZL22q_dbus_bus_get_private11DBusBusTypeP9DBusError
fun:_ZN22QDBusConnectionManager24executeConnectionRequestEPNS_21ConnectionRequestDataE
fun:_ZN9QtPrivate11FunctorCallINS_11IndexesListIJLi0EEEENS_4ListIJPN22QDBusConnectionManager21ConnectionRequestDataEEEEvMS4_FvS6_EE4callES9_PS4_PPv
fun:_ZN9QtPrivate15FunctionPointerIM22QDBusConnectionManagerFvPNS1_21ConnectionRequestDataEEE4callINS_4ListIJS3_EEEvEEvS5_PS1_PPv
fun:_ZN9QtPrivate11QSlotObjectIM22QDBusConnectionManagerFvPNS1_21ConnectionRequestDataEENS_4ListIJS3_EEEvE4implEiPNS_15QSlotObjectBaseEP7QObjectPPvPb
fun:_ZN9QtPrivate15QSlotObjectBase4callEP7QObjectPPv
fun:_ZN14QMetaCallEvent13placeMetaCallEP7QObject
fun:_ZN7QObject5eventEP6QEvent
}
==26444== 73 bytes in 1 blocks are definitely lost in loss record 143 of 284
==26444== at 0x4C29E63: malloc (vg_replace_malloc.c:309)
==26444== by 0x1664CF1E: ???
==26444== by 0x1662FCAD: ???
==26444== by 0x1327FC80: q_dbus_bus_get_private(DBusBusType, DBusError*) (qdbus_symbols_p.h:198)
==26444== by 0x13280818: QDBusConnectionManager::executeConnectionRequest(QDBusConnectionManager::ConnectionRequestData*) (qdbusconnection.cpp:263)
==26444== by 0x13286D27: QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void, void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*)>::call(void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QDBusConnectionManager*, void**) (qobjectdefs_impl.h:152)
==26444== by 0x13286ABC: void QtPrivate::FunctionPointer<void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*)>::call<QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void>(void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QDBusConnectionManager*, void**) (qobjectdefs_impl.h:185)
==26444== by 0x13285FF3: QtPrivate::QSlotObject<void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (qobjectdefs_impl.h:414)
==26444== by 0x670D63C: QtPrivate::QSlotObjectBase::call(QObject*, void**) (qobjectdefs_impl.h:394)
==26444== by 0x673DB2E: QMetaCallEvent::placeMetaCall(QObject*) (qobject.cpp:619)
==26444== by 0x673EAF3: QObject::event(QEvent*) (qobject.cpp:1339)
==26444== by 0x649CA55: QThread::event(QEvent*) (qthread.cpp:980)
==26444==
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
obj:*
obj:*
fun:_ZL22q_dbus_bus_get_private11DBusBusTypeP9DBusError
fun:_ZN22QDBusConnectionManager24executeConnectionRequestEPNS_21ConnectionRequestDataE
fun:_ZN9QtPrivate11FunctorCallINS_11IndexesListIJLi0EEEENS_4ListIJPN22QDBusConnectionManager21ConnectionRequestDataEEEEvMS4_FvS6_EE4callES9_PS4_PPv
fun:_ZN9QtPrivate15FunctionPointerIM22QDBusConnectionManagerFvPNS1_21ConnectionRequestDataEEE4callINS_4ListIJS3_EEEvEEvS5_PS1_PPv
fun:_ZN9QtPrivate11QSlotObjectIM22QDBusConnectionManagerFvPNS1_21ConnectionRequestDataEENS_4ListIJS3_EEEvE4implEiPNS_15QSlotObjectBaseEP7QObjectPPvPb
fun:_ZN9QtPrivate15QSlotObjectBase4callEP7QObjectPPv
fun:_ZN14QMetaCallEvent13placeMetaCallEP7QObject
fun:_ZN7QObject5eventEP6QEvent
fun:_ZN7QThread5eventEP6QEvent
}
==26444== 520 bytes in 13 blocks are definitely lost in loss record 198 of 284
==26444== at 0x4C29E63: malloc (vg_replace_malloc.c:309)
==26444== by 0x16655141: ???
==26444== by 0x16648EF4: ???
==26444== by 0x16649068: ???
==26444== by 0x1664D509: ???
==26444== by 0x16641F8A: ???
==26444== by 0x1327FDED: q_dbus_get_local_machine_id() (qdbus_symbols_p.h:435)
==26444== by 0x13282716: QDBusConnection::localMachineId() (qdbusconnection.cpp:1251)
==26444== by 0x163F7054: QIBusPlatformInputContextPrivate::getSocketPath() (qibusplatforminputcontext.cpp:733)
==26444== by 0x163F72B0: QIBusPlatformInputContextPrivate::createConnection() (qibusplatforminputcontext.cpp:741)
==26444== by 0x163F675F: QIBusPlatformInputContextPrivate::initBus() (qibusplatforminputcontext.cpp:648)
==26444== by 0x163F669E: QIBusPlatformInputContextPrivate::QIBusPlatformInputContextPrivate() (qibusplatforminputcontext.cpp:638)
==26444==
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
obj:*
obj:*
obj:*
obj:*
obj:*
fun:_ZL27q_dbus_get_local_machine_idv
fun:_ZN15QDBusConnection14localMachineIdEv
fun:_ZN32QIBusPlatformInputContextPrivate13getSocketPathEv
fun:_ZN32QIBusPlatformInputContextPrivate16createConnectionEv
fun:_ZN32QIBusPlatformInputContextPrivate7initBusEv
fun:_ZN32QIBusPlatformInputContextPrivateC1Ev
}
==26444== 545 (184 direct, 361 indirect) bytes in 1 blocks are definitely lost in loss record 199 of 284
==26444== at 0x4C2BF79: calloc (vg_replace_malloc.c:762)
==26444== by 0x1663CA74: ???
==26444== by 0x166414AE: ???
==26444== by 0x16649CB7: ???
==26444== by 0x16649DD2: ???
==26444== by 0x1664A87E: ???
==26444== by 0x1664B0F0: ???
==26444== by 0x16649A77: ???
==26444== by 0x16632FCC: ???
==26444== by 0x1328AB07: q_dbus_watch_handle(DBusWatch*, unsigned int) (qdbus_symbols_p.h:275)
==26444== by 0x13290700: QDBusConnectionPrivate::socketRead(int) (qdbusintegrator.cpp:1213)
==26444== by 0x132A6513: QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<int>, void, void (QDBusConnectionPrivate::*)(int)>::call(void (QDBusConnectionPrivate::*)(int), QDBusConnectionPrivate*, void**) (qobjectdefs_impl.h:152)
==26444==
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: definite
fun:calloc
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
fun:_ZL19q_dbus_watch_handleP9DBusWatchj
fun:_ZN22QDBusConnectionPrivate10socketReadEi
fun:_ZN9QtPrivate11FunctorCallINS_11IndexesListIJLi0EEEENS_4ListIJiEEEvM22QDBusConnectionPrivateFviEE4callES7_PS5_PPv
}
==26444== 727 (184 direct, 543 indirect) bytes in 1 blocks are definitely lost in loss record 208 of 284
==26444== at 0x4C2BF79: calloc (vg_replace_malloc.c:762)
==26444== by 0x1663CA74: ???
==26444== by 0x1663D871: ???
==26444== by 0x1662F774: ???
==26444== by 0x1327FC3B: q_dbus_bus_register(DBusConnection*, DBusError*) (qdbus_symbols_p.h:195)
==26444== by 0x132808BE: QDBusConnectionManager::executeConnectionRequest(QDBusConnectionManager::ConnectionRequestData*) (qdbusconnection.cpp:276)
==26444== by 0x13286D27: QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void, void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*)>::call(void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QDBusConnectionManager*, void**) (qobjectdefs_impl.h:152)
==26444== by 0x13286ABC: void QtPrivate::FunctionPointer<void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*)>::call<QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void>(void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QDBusConnectionManager*, void**) (qobjectdefs_impl.h:185)
==26444== by 0x13285FF3: QtPrivate::QSlotObject<void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (qobjectdefs_impl.h:414)
==26444== by 0x670D63C: QtPrivate::QSlotObjectBase::call(QObject*, void**) (qobjectdefs_impl.h:394)
==26444== by 0x673DB2E: QMetaCallEvent::placeMetaCall(QObject*) (qobject.cpp:619)
==26444== by 0x673EAF3: QObject::event(QEvent*) (qobject.cpp:1339)
==26444==
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: definite
fun:calloc
obj:*
obj:*
obj:*
fun:_ZL19q_dbus_bus_registerP14DBusConnectionP9DBusError
fun:_ZN22QDBusConnectionManager24executeConnectionRequestEPNS_21ConnectionRequestDataE
fun:_ZN9QtPrivate11FunctorCallINS_11IndexesListIJLi0EEEENS_4ListIJPN22QDBusConnectionManager21ConnectionRequestDataEEEEvMS4_FvS6_EE4callES9_PS4_PPv
fun:_ZN9QtPrivate15FunctionPointerIM22QDBusConnectionManagerFvPNS1_21ConnectionRequestDataEEE4callINS_4ListIJS3_EEEvEEvS5_PS1_PPv
fun:_ZN9QtPrivate11QSlotObjectIM22QDBusConnectionManagerFvPNS1_21ConnectionRequestDataEENS_4ListIJS3_EEEvE4implEiPNS_15QSlotObjectBaseEP7QObjectPPvPb
fun:_ZN9QtPrivate15QSlotObjectBase4callEP7QObjectPPv
fun:_ZN14QMetaCallEvent13placeMetaCallEP7QObject
fun:_ZN7QObject5eventEP6QEvent
}
==26444== 727 (184 direct, 543 indirect) bytes in 1 blocks are definitely lost in loss record 209 of 284
==26444== at 0x4C2BF79: calloc (vg_replace_malloc.c:762)
==26444== by 0x1663CA74: ???
==26444== by 0x166409BA: ???
==26444== by 0x16643857: ???
==26444== by 0x166336FD: ???
==26444== by 0x166339BF: ???
==26444== by 0x1662F793: ???
==26444== by 0x1327FC3B: q_dbus_bus_register(DBusConnection*, DBusError*) (qdbus_symbols_p.h:195)
==26444== by 0x132808BE: QDBusConnectionManager::executeConnectionRequest(QDBusConnectionManager::ConnectionRequestData*) (qdbusconnection.cpp:276)
==26444== by 0x13286D27: QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void, void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*)>::call(void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QDBusConnectionManager*, void**) (qobjectdefs_impl.h:152)
==26444== by 0x13286ABC: void QtPrivate::FunctionPointer<void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*)>::call<QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void>(void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QDBusConnectionManager*, void**) (qobjectdefs_impl.h:185)
==26444== by 0x13285FF3: QtPrivate::QSlotObject<void (QDBusConnectionManager::*)(QDBusConnectionManager::ConnectionRequestData*), QtPrivate::List<QDBusConnectionManager::ConnectionRequestData*>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (qobjectdefs_impl.h:414)
==26444==
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: definite
fun:calloc
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
fun:_ZL19q_dbus_bus_registerP14DBusConnectionP9DBusError
fun:_ZN22QDBusConnectionManager24executeConnectionRequestEPNS_21ConnectionRequestDataE
fun:_ZN9QtPrivate11FunctorCallINS_11IndexesListIJLi0EEEENS_4ListIJPN22QDBusConnectionManager21ConnectionRequestDataEEEEvMS4_FvS6_EE4callES9_PS4_PPv
fun:_ZN9QtPrivate15FunctionPointerIM22QDBusConnectionManagerFvPNS1_21ConnectionRequestDataEEE4callINS_4ListIJS3_EEEvEEvS5_PS1_PPv
fun:_ZN9QtPrivate11QSlotObjectIM22QDBusConnectionManagerFvPNS1_21ConnectionRequestDataEENS_4ListIJS3_EEEvE4implEiPNS_15QSlotObjectBaseEP7QObjectPPvPb
}
==26444== 1,119 (368 direct, 751 indirect) bytes in 2 blocks are definitely lost in loss record 232 of 284
==26444== at 0x4C2BF79: calloc (vg_replace_malloc.c:762)
==26444== by 0x1663CA74: ???
==26444== by 0x166414AE: ???
==26444== by 0x16649CB7: ???
==26444== by 0x16649DD2: ???
==26444== by 0x1664A87E: ???
==26444== by 0x1664AFD5: ???
==26444== by 0x16649B79: ???
==26444== by 0x166329FB: ???
==26444== by 0x166333DC: ???
==26444== by 0x166339D9: ???
==26444== by 0x1662F793: ???
==26444==
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: definite
fun:calloc
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
obj:*
}
==26444== LEAK SUMMARY:
==26444== definitely lost: 1,648 bytes in 22 blocks
==26444== indirectly lost: 2,246 bytes in 12 blocks
==26444== possibly lost: 0 bytes in 0 blocks
==26444== still reachable: 301,336 bytes in 6,818 blocks
==26444== suppressed: 0 bytes in 0 blocks
==26444== Reachable blocks (those to which a pointer was found) are not shown.
==26444== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==26444==
==26444== For counts of detected and suppressed errors, rerun with: -v
==26444== ERROR SUMMARY: 9 errors from 9 contexts (suppressed: 0 from 0)
This is normal for certain kind of libraries, such as C standard library. This is why you want Valgrind suppression files, so it knows which leaks are normal. To easily have nice suppression data for Qt, run Valgrind under Qt Creator (documentation link).
The reason for this is, libraries reserve memory for things like communicating with the operating system stuff (such as windowing system), but have no control over when your application no longer needs it. It could be released at application exit via exit hooks, but the entire application is going to be removed from memory, so doing memory cleanup would just slow down application shutdown for literally no gain at all.
Note that most memory is still cleaned up as C++ objects go out of scope. C++ objects need to have their destructors called anyway, which is normally done by delete for objects in heap. Also this is definitely not something you should optimize for in a normal C++ application code. The stuff libraries leave allocated at exit (and need Valgrind suppression) are typically low level stuff, global to the whole application and not owned by a single C++ object instance.
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´m running a big code with lots of MYSQL database access that and I´m noticing a memory leak that consumes the whole server memory after one day running.
By isolating pieces I end up with the following test code:
#include <iostream>
#include <string>
#include <sstream>
#include <thread>
#include <chrono>
#include "mysql_connection.h"
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
int main() {
try
{
sql::Driver *driver = NULL;
sql::Connection *connection = NULL;
driver = get_driver_instance();
connection = driver->connect("tcp://127.0.0.1:3306", "user", "pass");
connection->setSchema("myschema");
connection->setAutoCommit(true);
while (true)
{
std::string sql("INSERT INTO tablename ('field1', 'field2', 'field3') VALUES ('1', '2', '3')");
sql::Statement *stmt;
stmt = connection->createStatement();
stmt->execute(sql.c_str());
stmt->close();
std::cout << sql << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
catch (std::exception& ex)
{
std::cout << "Error occurred: " << std::endl;
std::cout << ex.what() << std::endl;
}
catch(...)
{
std::cout << "Unknown failure occurred." << std::endl;
}
}
As the main while runs, the process memory usage starts increasing like 1Mb per minute.
Using valgrid --leak-check=full I got the following result after hitting to exit from the main loop:
==11988== Process terminating with default action of signal 2 (SIGINT)
==11988== at 0x57F5D6D: recv (recv.c:29)
==11988== by 0x5B1B022: vio_read (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18.1.0)
==11988== by 0x5B1B0A4: vio_read_buff (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18.1.0)
==11988== by 0x5AFA702: ??? (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18.1.0)
==11988== by 0x5AFA976: ??? (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18.1.0)
==11988== by 0x5AFB6A3: my_net_read (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18.1.0)
==11988== by 0x5AF151C: cli_safe_read (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18.1.0)
==11988== by 0x5AF2A15: ??? (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18.1.0)
==11988== by 0x5AF43A5: mysql_real_query (in /usr/lib/x86_64-linux-gnu/libmysqlclient.so.18.1.0)
==11988== by 0x4F15BEE: sql::mysql::NativeAPI::LibmysqlStaticProxy::real_query(st_mysql*, char const*, unsigned long) (in /usr/lib/libmysqlcppconn.so.7.1.1.3)
==11988== by 0x4F176F5: sql::mysql::NativeAPI::MySQL_NativeConnectionWrapper::query(sql::SQLString const&) (in /usr/lib/libmysqlcppconn.so.7.1.1.3)
==11988== by 0x4F10579: sql::mysql::MySQL_Statement::do_query(sql::SQLString const&) (in /usr/lib/libmysqlcppconn.so.7.1.1.3)
==11988==
==11988== HEAP SUMMARY:
==11988== in use at exit: 333,479 bytes in 1,869 blocks
==11988== total heap usage: 5,566 allocs, 3,697 frees, 1,100,674 bytes allocated
==11988==
==11988== 144,880 bytes in 1,811 blocks are definitely lost in loss record 42 of 42
==11988== at 0x4C2C12F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==11988== by 0x4EC4334: sql::mysql::MySQL_Connection::createStatement() (in /usr/lib/libmysqlcppconn.so.7.1.1.3)
==11988== by 0x4011B7: main (test.cpp:32)
==11988==
==11988== LEAK SUMMARY:
==11988== definitely lost: 144,880 bytes in 1,811 blocks
==11988== indirectly lost: 0 bytes in 0 blocks
==11988== possibly lost: 0 bytes in 0 blocks
==11988== still reachable: 188,599 bytes in 58 blocks
==11988== suppressed: 0 bytes in 0 blocks
==11988== Reachable blocks (those to which a pointer was found) are not shown.
==11988== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==11988==
==11988== For counts of detected and suppressed errors, rerun with: -v
==11988== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
So, am I doing something wrong or is this a know MYSQL bug ? How to fix the code and/or mySQL ?
I´m running MySql 5.6.27-0ubuntu1 running on Ubuntu 15.10.
You're missing delete stmt. Better would be to use a std::unique_ptr<sql::Statement>.
(See e.g. https://dev.mysql.com/doc/connector-cpp/en/connector-cpp-examples-query.html)
Try
std::unique_ptr<sql::Statement> stmt(connection->CreateStatement());
I have a toy project which is a game engine. It uses SDL2 and C++11. In the code below I tried to make an objects which cleans memory after itself in destructor. But something goes wrong and some memory leaks. What am I doing wrong?
Example is minimal working code which triggers a leak. I suppose it works like this:
Instance of class Game upon costruction creates instances of SDLEngine and Graphics (in this order), both of which allocates some memory too. When game object is destroyed it calls destructors of Graphics and SDLEngine (in this order). If I add some printing in both of this destructors they are printed in the needed order. But valgrind thinks that memory allocated by SDL_Init() and SDL_CreateWindow() are leaked.
Edit: it is probably valgrind behaviour. I saw a similar question and similar warnings in the pretty basic SDL example: Why does valgrind say basic SDL program is leaking memory?
src/leak-test.cpp:
#include <SDL2/SDL.h>
#include <stdexcept>
class SDLEngine {
public:
SDLEngine() {
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
throw std::runtime_error("SDL_Init"); // line 7
}
if (SDL_ShowCursor(SDL_DISABLE) < 0) {
throw std::runtime_error("SDL_ShowCursor");
}
}
~SDLEngine() {
SDL_Quit();
}
};
class Graphics {
public:
Graphics() :
sdlWindow{SDL_CreateWindow(
"LeakTest",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
320, 240,
0
)} // line 27
{
if (sdlWindow == nullptr) {
throw std::runtime_error("SDL_CreateWindow");
}
}
~Graphics() {
SDL_DestroyWindow(sdlWindow);
}
Graphics(const Graphics&)=delete;
Graphics& operator=(const Graphics&)=delete;
private:
SDL_Window *sdlWindow;
};
class Game {
public:
Game() :
sdlEngine_(),
graphics_() // line 46
{
SDL_Event event;
bool running{true};
while (running) {
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
running = false;
break;
default:
break;
}
}
}
}
~Game() {}
private:
const SDLEngine sdlEngine_;
Graphics graphics_;
};
int main() {
Game game; // line 70
return 0;
}
Makefile:
CXX := g++
MKDIR := mkdir -p
CXXFLAGS += `pkg-config --cflags sdl2 SDL2_image`
CXXFLAGS += -Wall -Werror -Wextra -Weffc++ -pedantic -std=c++0x -g
LDFLAGS += `pkg-config --libs sdl2 SDL2_image`
PROG := bin/leak-test
OBJS := $(patsubst src/%.cpp,obj/%.o, $(wildcard src\/*.cpp))
# escaped to fool SO parser ^
.PHONY: all clean
all: build
build: $(PROG)
clean:
rm -rf $(PROG) $(OBJS)
$(PROG): obj/leak-test.o
$(PROG):
#$(MKDIR) $(dir $#)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $# $^
obj/%.o : src/%.cpp
#$(MKDIR) $(dir $#)
$(CXX) $(CXXFLAGS) -c -MD -o $# $<
Valgrind output:
host:cave-test » valgrind --leak-check=full ./bin/leak-test
==28815== Memcheck, a memory error detector
==28815== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==28815== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==28815== Command: ./bin/leak-test
==28815==
==28815==
==28815== HEAP SUMMARY:
==28815== in use at exit: 66,235 bytes in 506 blocks
==28815== total heap usage: 19,844 allocs, 19,338 frees, 44,931,400 bytes allocated
==28815==
==28815== 20 bytes in 2 blocks are definitely lost in loss record 7 of 101
==28815== at 0x4C274A0: malloc (vg_replace_malloc.c:291)
==28815== by 0x5BF8829: strdup (strdup.c:42)
==28815== by 0x7203666: ??? (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815== by 0x7204474: _XimSetICValueData (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815== by 0x71FFA69: _XimLocalCreateIC (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815== by 0x71E6044: XCreateIC (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815== by 0x5111CD2: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815== by 0x51120F7: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815== by 0x51055FF: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815== by 0x510540F: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815== by 0x507048E: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815== by 0x400D6E: SDLEngine::SDLEngine() (leak-test.cpp:7)
==28815==
==28815== 20 bytes in 2 blocks are definitely lost in loss record 8 of 101
==28815== at 0x4C274A0: malloc (vg_replace_malloc.c:291)
==28815== by 0x5BF8829: strdup (strdup.c:42)
==28815== by 0x7203666: ??? (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815== by 0x7204474: _XimSetICValueData (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815== by 0x71FFA69: _XimLocalCreateIC (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815== by 0x71E6044: XCreateIC (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815== by 0x5111CD2: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815== by 0x51120F7: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815== by 0x51055FF: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815== by 0x400F11: Graphics::Graphics() (leak-test.cpp:27)
==28815== by 0x401012: Game::Game() (leak-test.cpp:46)
==28815== by 0x400D31: main (leak-test.cpp:70)
==28815==
==28815== 104 bytes in 1 blocks are definitely lost in loss record 60 of 101
==28815== at 0x4C274A0: malloc (vg_replace_malloc.c:291)
==28815== by 0xD330A11: ??? (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==28815== by 0xD309600: ??? (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==28815== by 0xD305E7A: ??? (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==28815== by 0xD30660F: glXChooseVisual (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==28815== by 0x510ED0E: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815== by 0x510EF40: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815== by 0x5103B65: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815== by 0x51056FB: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815== by 0x510540F: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815== by 0x507048E: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815== by 0x400D6E: SDLEngine::SDLEngine() (leak-test.cpp:7)
==28815==
==28815== LEAK SUMMARY:
==28815== definitely lost: 144 bytes in 5 blocks
==28815== indirectly lost: 0 bytes in 0 blocks
==28815== possibly lost: 0 bytes in 0 blocks
==28815== still reachable: 66,091 bytes in 501 blocks
==28815== suppressed: 0 bytes in 0 blocks
==28815== Reachable blocks (those to which a pointer was found) are not shown.
==28815== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==28815==
==28815== For counts of detected and suppressed errors, rerun with: -v
==28815== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 7 from 3)
It turns out this leak belongs to layer under SDL, in the X11 library. This bug is very old and known by SDL devs. See this bugzilla thread: https://bugzilla.libsdl.org/show_bug.cgi?id=2086
I close the question now.
I'm trying to read from a input source (in this case stdin) with a timeout. Due to the design of the existing application where this have to fit is it not possible to call run on my io_service.
Here is my try so far:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/optional.hpp>
void set_result( boost::optional<boost::system::error_code> * a, boost::system::error_code b ) {
if( b == 0)
a->reset( b );
}
void receive(boost::asio::io_service & io, boost::asio::posix::stream_descriptor & stream, boost::asio::streambuf & result){
boost::optional<boost::system::error_code> timer_result;
boost::optional<boost::system::error_code> read_result;
boost::asio::deadline_timer timer( io );
timer.expires_from_now( boost::posix_time::milliseconds(5000) );
timer.async_wait( boost::bind(&set_result, &timer_result, _1) );
boost::asio::async_read(
stream,
result,
boost::asio::transfer_at_least(1),
boost::bind( &set_result, &read_result, _1 ));
boost::system::error_code ec;
while(1) {
io.reset();
io.poll_one(ec);
if ( read_result ) {
timer.cancel();
return;
} else if ( timer_result )
throw std::runtime_error("timeout");
}
}
void receive(boost::asio::io_service & io, boost::asio::posix::stream_descriptor & stream, size_t size, boost::asio::streambuf & result){
while( result.size() < size )
receive(io, stream, result);
}
int main(int argc, const char *argv[])
{
boost::asio::io_service io;
boost::asio::posix::stream_descriptor in(io, ::dup(STDIN_FILENO));
for(int i = 0; i < 5; i++){
std::cout << i << " Type in 4 chareters and press enter" << std::endl << std::endl;
std::cout << "in> ";
std::cout.flush();
try {
boost::asio::streambuf buf;
receive(io, in, 5, buf);
std::cout << "out> ";
std::copy(boost::asio::buffer_cast<const char *>(buf.data()), boost::asio::buffer_cast<const char *>(buf.data()) + buf.size(), std::ostream_iterator<char>(std::cout));
} catch (const std::exception & e) {
std::cout << e.what() << std::endl;
}
}
return 0;
}
At my first look, I thought that it was working, but after playing more around with the test app, I got some segmentations faults.
I found that something bad happens if I wait for the first query to timeout, and then enter 5 chars the next.
Here is what valgrind says:
==17216== Memcheck, a memory error detector
==17216== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==17216== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==17216== Command: ./ccTalkScan
==17216==
0 Type in 4 chareters and press enter
asdf
0 system:0
1 Type in 4 chareters and press enter
0 system:125
0 system:0
==17216== Invalid read of size 8
==17216== at 0x546EB4A: ??? (setcontext.S:60)
==17216== by 0x425245: receive(boost::asio::io_service&, boost::asio::posix::basic_stream_descriptor<boost::asio::posix::stream_descriptor_service>&, unsigned long, boost::asio::basic_streambuf<std::allocator<char> >&) (ccTalkScan.cxx:321)
==17216== by 0x42535E: main (ccTalkScan.cxx:333)
==17216== Address 0x7feffdfa8 is not stack'd, malloc'd or (recently) free'd
==17216==
==17216== Invalid read of size 8
==17216== at 0x546EB52: ??? (setcontext.S:63)
==17216== by 0x425245: receive(boost::asio::io_service&, boost::asio::posix::basic_stream_descriptor<boost::asio::posix::stream_descriptor_service>&, unsigned long, boost::asio::basic_streambuf<std::allocator<char> >&) (ccTalkScan.cxx:321)
==17216== by 0x42535E: main (ccTalkScan.cxx:333)
==17216== Address 0x7feffdf98 is not stack'd, malloc'd or (recently) free'd
==17216==
==17216== Invalid read of size 8
==17216== at 0x546EB59: ??? (setcontext.S:64)
==17216== by 0x425245: receive(boost::asio::io_service&, boost::asio::posix::basic_stream_descriptor<boost::asio::posix::stream_descriptor_service>&, unsigned long, boost::asio::basic_streambuf<std::allocator<char> >&) (ccTalkScan.cxx:321)
==17216== by 0x42535E: main (ccTalkScan.cxx:333)
==17216== Address 0x7feffdf68 is not stack'd, malloc'd or (recently) free'd
==17216==
==17216== Invalid read of size 8
==17216== at 0x546EB4A: ??? (setcontext.S:60)
==17216== by 0x5E4BD2C: (below main) (in /lib64/libc-2.12.2.so)
==17216== Address 0x7feffe018 is not stack'd, malloc'd or (recently) free'd
==17216==
==17216== Invalid read of size 8
==17216== at 0x546EB52: ??? (setcontext.S:63)
==17216== by 0x5E4BD2C: (below main) (in /lib64/libc-2.12.2.so)
==17216== Address 0x7feffe008 is not stack'd, malloc'd or (recently) free'd
==17216==
==17216== Invalid read of size 8
==17216== at 0x546EB59: ??? (setcontext.S:64)
==17216== by 0x5E4BD2C: (below main) (in /lib64/libc-2.12.2.so)
==17216== Address 0x7feffdfd8 is not stack'd, malloc'd or (recently) free'd
==17216==
timeout
2 Type in 4 chareters and press enter
0 system:0
timeout
3 Type in 4 chareters and press enter
asdf
==17216== Syscall param readv(vector[...]) points to unaddressable byte(s)
==17216== at 0x5EF7A81: readv (in /lib64/libc-2.12.2.so)
==17216== by 0x42A77A: boost::asio::detail::descriptor_ops::non_blocking_read(int, iovec*, unsigned long, boost::system::error_code&, unsigned long&) (descriptor_ops.ipp:153)
==17216== by 0x4355D1: boost::asio::detail::descriptor_read_op_base<boost::asio::mutable_buffers_1>::do_perform(boost::asio::detail::reactor_op*) (descriptor_read_op.hpp:55)
==17216== by 0x4275DA: boost::asio::detail::reactor_op::perform() (reactor_op.hpp:40)
==17216== by 0x4288F9: boost::asio::detail::epoll_reactor::run(bool, boost::asio::detail::op_queue<boost::asio::detail::task_io_service_operation>&) (epoll_reactor.ipp:286)
==17216== by 0x429577: boost::asio::detail::task_io_service::do_one(boost::asio::detail::scoped_lock<boost::asio::detail::posix_mutex>&, boost::asio::detail::task_io_service::idle_thread_info*) (task_io_service.ipp:264)
==17216== by 0x429165: boost::asio::detail::task_io_service::poll_one(boost::system::error_code&) (task_io_service.ipp:188)
==17216== by 0x4299B8: boost::asio::io_service::poll_one(boost::system::error_code&) (io_service.ipp:103)
==17216== by 0x424FDF: receive(boost::asio::io_service&, boost::asio::posix::basic_stream_descriptor<boost::asio::posix::stream_descriptor_service>&, boost::asio::basic_streambuf<std::allocator<char> >&) (ccTalkScan.cxx:308)
==17216== by 0x425245: receive(boost::asio::io_service&, boost::asio::posix::basic_stream_descriptor<boost::asio::posix::stream_descriptor_service>&, unsigned long, boost::asio::basic_streambuf<std::allocator<char> >&) (ccTalkScan.cxx:321)
==17216== by 0x42535E: main (ccTalkScan.cxx:333)
==17216== Address 0x65ba920 is 0 bytes inside a block of size 512 free'd
==17216== at 0x4C25C4F: operator delete(void*) (vg_replace_malloc.c:387)
==17216== by 0x432317: __gnu_cxx::new_allocator<char>::deallocate(char*, unsigned long) (new_allocator.h:95)
==17216== by 0x430D67: std::_Vector_base<char, std::allocator<char> >::_M_deallocate(char*, unsigned long) (stl_vector.h:146)
==17216== by 0x42F4A0: std::_Vector_base<char, std::allocator<char> >::~_Vector_base() (stl_vector.h:132)
==17216== by 0x42CF5E: std::vector<char, std::allocator<char> >::~vector() (stl_vector.h:313)
==17216== by 0x42AEB5: boost::asio::basic_streambuf<std::allocator<char> >::~basic_streambuf() (basic_streambuf.hpp:114)
==17216== by 0x425374: main (ccTalkScan.cxx:333)
==17216==
0 system:0
4 Type in 4 chareters and press enter
0 system:125
0 system:0
timeout
==17216==
==17216== HEAP SUMMARY:
==17216== in use at exit: 168 bytes in 3 blocks
==17216== total heap usage: 63 allocs, 60 frees, 22,070 bytes allocated
I have tried different things to fix it, but I think that I might have misunderstood a thing or two here. So some help would be nice, and an example would be most appreciated ;)
The problem in the above implementation is that the async_reads which times out is never canceled. Here is how to do this:
while(1) {
io.reset();
io.poll_one(ec);
if ( read_result ) {
timer.cancel(); // cancel the timeout operation as it has not completed yet
return;
} else if ( timer_result ) {
stream.cancel(); // cancel the read operation as it has not completed yet
throw std::runtime_error("timeout");
}
}