[cairo] cairo_xcb_surface_create() segfaults on second call with different xcb info

Ryan Flannery ryan.flannery at gmail.com
Sat Nov 10 05:36:12 UTC 2018


Hi Uli,

Thanks much for your reply and very thorough explanation!

On Thu, Nov 8, 2018 at 3:36 PM Uli Schlachter <psychon at znc.in> wrote:
>
> Hi Ryan,
>
> On 08.11.18 04:48, Ryan Flannery wrote:
> > I'm guessing I'm either missing some tear-down/cleanup between calls
> > that I'm not seeing from the documentation and google'ing, or there's
> > some state/etc within the cairo API I'm missing.
> >
> > Anyone seen something similar or have any idea why this might be caused?
>
> Cairo has to get quite some information from the X11 server. Which
> extensions are supported? In which version? Does shared memory work?
> Stuff like this.
>
> Obviously, querying this all the time would be slow. Thus, cairo caches
> this information. Namely, there is an instance of cairo_device_t. This
> instance is kept around even when all surfaces using this device are
> destroyed.
>
> When a new cairo surface is created, it needs to get an instance of
> cairo_device_t for all of this information. To identify an
> already-existing device, the xcb_connection_t* pointer is used. Same
> pointer means same XCB connection. Thus, when you call xcb_disconnect(),
> the cache now contains a dangling pointer. The next call to
> xcb_connect() might very well allocate an xcb_connection_t* with the
> same pointer. Thus, you now get a cache hit even though there is a new
> XCB connection. Bad things happen afterwards.
>
> (But right now I do not know where you crash comes from)

THANK YOU! This explains it. There is some state cairo in tracking,
namely that pointer value (not the contents, but the pointer value
itself) for a sort-of caching (it sounds like).

With this, I believe I can work-around it in my application and keep
the current design. Specially, I can keep the "UI portions"
independent of each other (desirable) provided I guarantee the
xcb_connection_t pointer passed is a different one, for each run.
That's easy enough on my side.

> > Sample code below. The "test()" function is where I create an x window
> > (and related bits), followed by a cairo surface and cairo_t, and then
> > simply sleep for a second and tear everything down. The second call to
> > test() will reliably segfault on cairo_xcb_surface_create().
>
> Fun fact: Does not crash here on Debian testing.
> Dies in a failed assertion when run under xtrace (sometimes known as
> x11trace).
> [...]
> >    cairo_destroy(c);
>
> Add this here:
>
>   cairo_device_finish(cairo_surface_get_device(cs));
>
> >    cairo_surface_destroy(cs);
> >    xcb_destroy_window(x, w);
> >    xcb_disconnect(x);
> > }

This sounds great.
I think I can trivially modify my code with this to fix the issue and
still keep the separate UI runs independent of each other.

> If you want to keep the device around for later (i.e. have multiple
> surface using the same device), you can save a pointer via:
>
>   cairo_device_t *device = cairo_device_reference(....);
>
> Now, you have to later call cairo_device_destroy() when you no longer
> need the reference, but you get a pointer to the cairo_device_t
> independent of a cairo xcb surface.
>
> Oh and: You have to finish the device before you call xcb_disconnect().
> Finishing the device can still cause X11 requests to be sent (i.e. to
> send out pending drawing that was not yet done).
>
> Also: Finishing the device automatically finishes all cairo_surface_t
> instances for this XCB devices.

Ok - this raises a question for me about the device state between
surface creation.
Do you mean one of the following:

1. Calling cairo_device_finish(cairo_surface_get_device(cs)) when
destroying a xcb/cairo setup should, effectively, remove the state
tracked in cairo_xcb_surface_create() (and thus allow a subsequent
call with the same pointer value, but different contents, succeed)?

-or-

2. That there's still state there and I should track that
cairo_device_t* reference on my side, even if I call the
cairo_device_finish() bits?

I could probably answer that on my own if I had my dev laptop with me,
but I'm sadly away from that for 2 days and still so curious on this
:D

Thanks so much again for your explanation!! I'm confident I can get
this working on my side once I'm back.

Cheers,
-Ryan


More information about the cairo mailing list