简体   繁体   中英

Memory leaks with Cairo

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM