Bug 101866

Summary: raster source pattern callback weirdness
Product: cairo Reporter: Christoph Reiter <reiter.christoph>
Component: generalAssignee: Chris Wilson <chris>
Status: RESOLVED NOTABUG QA Contact: cairo-bugs mailing list <cairo-bugs>
Severity: normal    
Priority: medium    
Version: unspecified   
Hardware: Other   
OS: All   
Whiteboard:
i915 platform: i915 features:
Attachments: example program

Description Christoph Reiter 2017-07-21 07:58:22 UTC
Created attachment 132810 [details]
example program

I'm currently trying to bind raster source patterns in pycairo and hitting some problems I don't understand.

See the example program:

1) Set a callback through cairo_raster_source_pattern_set_acquire
2) Wait until the callback is called

Expected:

  The first parameter passed to the callback is the pattern

Actual:

  Some different pattern is passed and it is dead, so doing anything with it crashes.
Comment 1 Uli Schlachter 2017-07-22 10:42:09 UTC
Use cairo_raster_source_pattern_set_callback_data() to set the closure argument of your callback: https://www.cairographics.org/manual/cairo-Raster-Sources.html#cairo-raster-source-pattern-set-callback-data

The pattern argument is a static, stack-allocated copy that cairo creates internally. I have to admit that I am not sure why this pattern is given to the callback at all. The backtrace for the creation of the copy looks like that (I guess that both calls create copies of the raster pattern):

Breakpoint 2, _cairo_pattern_init_static_copy (pattern=pattern@entry=0x7fffffffe690, other=other@entry=0x55555575aab0) at cairo-pattern.c:368
368	{
(gdb) bt
#0  _cairo_pattern_init_static_copy (pattern=pattern@entry=0x7fffffffe690, other=other@entry=0x55555575aab0) at cairo-pattern.c:368
#1  0x00007ffff7aa7552 in _cairo_gstate_copy_pattern (original=0x55555575aab0, pattern=0x7fffffffe690) at cairo-gstate.c:937
#2  _cairo_gstate_copy_transformed_pattern (pattern=pattern@entry=0x7fffffffe690, original=0x55555575aab0, ctm_inverse=ctm_inverse@entry=0x55555575a690, gstate=<optimized out>)
    at cairo-gstate.c:946
#3  0x00007ffff7aa9346 in _cairo_gstate_copy_transformed_source (pattern=0x7fffffffe690, gstate=0x55555575a540) at cairo-gstate.c:973
#4  _cairo_gstate_paint (gstate=0x55555575a540) at cairo-gstate.c:1063
#5  0x00007ffff7a978ca in INT_cairo_paint (cr=0x55555575a510) at cairo.c:2221
#6  0x0000555555554d9f in draw (cr=0x55555575a510) at test.c:50
#7  0x0000555555554dea in main () at test.c:65
(gdb) cont
Continuing.

Breakpoint 2, _cairo_pattern_init_static_copy (pattern=pattern@entry=0x7fffffffe3d0, other=other@entry=0x7fffffffe690) at cairo-pattern.c:368
368	{
(gdb) bt
#0  _cairo_pattern_init_static_copy (pattern=pattern@entry=0x7fffffffe3d0, other=other@entry=0x7fffffffe690) at cairo-pattern.c:368
#1  0x00007ffff7a9e59f in _cairo_composite_reduce_pattern (dst=0x7fffffffe3d0, src=0x7fffffffe690) at cairo-composite-rectangles.c:56
#2  _cairo_composite_rectangles_init (clip=0x0, source=0x7fffffffe690, op=<optimized out>, surface=0x55555575a380, surface@entry=0x7fffffffe690, extents=0x7fffffffe350, 
    extents@entry=0x7fffffffe2f0) at cairo-composite-rectangles.c:97
#3  _cairo_composite_rectangles_init_for_paint (extents=extents@entry=0x7fffffffe350, surface=surface@entry=0x55555575a380, op=<optimized out>, source=0x7fffffffe690, clip=0x0)
    at cairo-composite-rectangles.c:122
#4  0x00007ffff7a9f8ae in _cairo_compositor_paint (compositor=0x7ffff7dd7320 <spans>, surface=0x55555575a380, op=<optimized out>, source=<optimized out>, clip=<optimized out>)
    at cairo-compositor.c:55
#5  0x00007ffff7b0e391 in _cairo_surface_paint (surface=0x55555575a380, op=op@entry=CAIRO_OPERATOR_OVER, source=0x7fffffffe690, clip=0x0) at cairo-surface.c:2120
#6  0x00007ffff7aa9294 in _cairo_gstate_paint (gstate=0x55555575a540) at cairo-gstate.c:1067
#7  0x00007ffff7a978ca in INT_cairo_paint (cr=0x55555575a510) at cairo.c:2221
#8  0x0000555555554d9f in draw (cr=0x55555575a510) at test.c:50
#9  0x0000555555554dea in main () at test.c:65


For this bug report: I would argue that your expected behavior just is not the behavior that cairo provides, so there is no bug here. I'm not sure what you mean exactly with "it is dead, so doing anything with it crashes". Your example program does not crash here.
Comment 2 Christoph Reiter 2017-07-22 11:25:15 UTC
(In reply to Uli Schlachter from comment #1)
> Use cairo_raster_source_pattern_set_callback_data() to set the closure
> argument of your callback:
> https://www.cairographics.org/manual/cairo-Raster-Sources.html#cairo-raster-
> source-pattern-set-callback-data

Thanks. I'm using that now. I'd would have preferred to use cairo_pattern_get/set_user_data() so there can be no conflict if Python gets passed an existing object with configured callbacks/callback data from C. But I guess that's unlikely to happen anyway.

> The pattern argument is a static, stack-allocated copy that cairo creates
> internally. I have to admit that I am not sure why this pattern is given to
> the callback at all. The backtrace for the creation of the copy looks like
> that (I guess that both calls create copies of the raster pattern):

If there is no use for it I'll just not pass it to the Python callback then, thanks.

> For this bug report: I would argue that your expected behavior just is not
> the behavior that cairo provides, so there is no bug here. I'm not sure what
> you mean exactly with "it is dead, so doing anything with it crashes". Your
> example program does not crash here.

I meant that the object has a reference count of 0 and wrapping it, which involved refing/unrefing it, made it crash if I remember correctly. The example program should not crash but show a reference count of 0.

Closing is fine with me, thanks.
Comment 3 Christoph Reiter 2017-07-22 11:49:17 UTC
fyi, this is the Python API now: https://pycairo.readthedocs.io/en/latest/reference/patterns.html#cairo.RasterSourcePattern
Comment 4 Bryce Harrington 2017-09-20 21:28:36 UTC
Closing as per comment #2

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.