Bug 15761

Summary: cairo_surface_set_device_offset crashes pidgin on windows
Product: cairo Reporter: David Grohmann <dave1g>
Component: win32 backendAssignee: cairo-bugs mailing list <cairo-bugs>
Status: RESOLVED NOTOURBUG QA Contact: cairo-bugs mailing list <cairo-bugs>
Severity: normal    
Priority: medium CC: daniel_atallah
Version: 1.6.4   
Hardware: Other   
OS: All   
URL: http://developer.pidgin.im/ticket/5662
Whiteboard:
i915 platform: i915 features:
Attachments: crash stack trace
crash stack with newest DLLs
debug log of pidgin (contains gtk print statements on the last couple lines)

Description David Grohmann 2008-04-29 20:24:05 UTC
Created attachment 16250 [details]
crash stack trace

this was printed to the debug console:

(22:59:28) Gdk: gdkwindow-win32.c:2192: CopyCursor failed: The operation completed successfully.
(22:59:29) Gdk: gdkpixmap-win32.c:302: CreateDIBSection failed: The parameter is incorrect.
(22:59:29) Gdk: gdkpixmap-win32.c:114: DeleteObject failed: The operation completed successfully.
(22:59:29) Gdk: _gdk_drawable_ref_cairo_surface: assertion `GDK_IS_DRAWABLE (drawable)' failed


then crashed.
Comment 1 David Grohmann 2008-04-29 20:25:15 UTC
pidgin bug tracker http://developer.pidgin.im/ticket/5662
Comment 2 David Grohmann 2008-04-29 20:56:49 UTC
I've installed the dlls from http://www.gtk.org/download-windows.html and was able to produce the same crash from pidgin. Though they also caused many visual artifacts in pidgin, mostly icons appearing as red X's all over the place.
Comment 3 David Grohmann 2008-04-29 20:58:21 UTC
Created attachment 16251 [details]
crash stack with newest DLLs
Comment 4 David Grohmann 2008-04-29 21:01:11 UTC
Created attachment 16252 [details]
debug log of pidgin (contains gtk print statements on the last couple lines)
Comment 5 David Grohmann 2008-05-25 10:28:18 UTC
better summary...
Comment 6 David Grohmann 2008-07-04 21:01:36 UTC
Using the gtk 2.12.10 available for download on GTK+ for windows site  I see this printed out

(23:54:51) stun: got public ip 208.120.218.196
(23:55:08) Gdk: gdkgc-win32.c:823: SaveDC failed: Not enough storage is available to process this command.
(23:55:08) Gdk: gdkdrawable-win32.c:1534: BitBlt failed: The operation completed successfully.
(23:55:08) Gdk: gdkgc-win32.c:963: RestoreDC failed: The parameter is incorrect.
(23:55:08) Gdk: gdkgc-win32.c:823: SaveDC failed: Not enough storage is available to process this command.
(23:55:08) Gdk: gdkgc-win32.c:963: RestoreDC failed: The parameter is incorrect.
(23:55:08) Gdk: gdkpixmap-win32.c:302: CreateDIBSection failed: The parameter is incorrect.
(23:55:08) Gdk: gdkpixmap-win32.c:114: DeleteObject failed: The operation completed successfully.
(23:55:08) Gdk: _gdk_drawable_ref_cairo_surface: assertion `GDK_IS_DRAWABLE (drawable)' failed


And here is the stack trace

-------------------

Error occured on Friday, July 4, 2008 at 23:55:08.

Windows Version 5.1 Build 2600 Service Pack 2

C:\Program Files\Pidgin\pidgin.exe caused an Access Violation at location 68dd6cff in module C:\Program Files\Common Files\GTK\2.0\bin\libcairo-2.dll Reading from location 000000bc.

Registers:
eax=00000000 ebx=01c4e188 ecx=ffffffff edx=fffffd97 esi=01bcc858 edi=063e0fe8
eip=68dd6cff esp=0022f330 ebp=0022f348 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210206

Call stack:
68DD6CFF C:\Program Files\Common Files\GTK\2.0\bin\libcairo-2.dll  cairo_surface_set_device_offset
         C:\Program Files\Common Files\GTK\2.0\bin\libgdk-win32-2.0-0.dll [2.12.10.0]
6C35B347 C:\Program Files\Common Files\GTK\2.0\bin\libgdk-win32-2.0-0.dll  gdk_window_begin_paint_region
         C:\Program Files\Common Files\GTK\2.0\bin\libgtk-win32-2.0-0.dll [2.12.10.0]
6188A388 C:\Program Files\Common Files\GTK\2.0\bin\libgtk-win32-2.0-0.dll  gtk_main_do_event
         C:\Program Files\Common Files\GTK\2.0\bin\libgdk-win32-2.0-0.dll [2.12.10.0]
6C35C4C3 C:\Program Files\Common Files\GTK\2.0\bin\libgdk-win32-2.0-0.dll  gdk_window_clear_area_e
6C35C608 C:\Program Files\Common Files\GTK\2.0\bin\libgdk-win32-2.0-0.dll  gdk_window_process_all_updates
         C:\Program Files\Common Files\GTK\2.0\bin\libgtk-win32-2.0-0.dll [2.12.10.0]
617E7689 C:\Program Files\Common Files\GTK\2.0\bin\libgtk-win32-2.0-0.dll  gtk_container_check_resize
         C:\Program Files\Common Files\GTK\2.0\bin\libgdk-win32-2.0-0.dll [2.12.10.0]
6C3417E8 C:\Program Files\Common Files\GTK\2.0\bin\libgdk-win32-2.0-0.dll  gdk_threads_set_lock_functions
         C:\Program Files\Common Files\GTK\2.0\bin\libglib-2.0-0.dll [2.16.3.0]
685E70D7 C:\Program Files\Common Files\GTK\2.0\bin\libglib-2.0-0.dll  g_main_context_dispatch
685E85AB C:\Program Files\Common Files\GTK\2.0\bin\libglib-2.0-0.dll  g_main_context_acquire
685E879A C:\Program Files\Common Files\GTK\2.0\bin\libglib-2.0-0.dll  g_main_loop_run
         C:\Program Files\Common Files\GTK\2.0\bin\libgtk-win32-2.0-0.dll [2.12.10.0]
618895EE C:\Program Files\Common Files\GTK\2.0\bin\libgtk-win32-2.0-0.dll  gtk_main
         C:\Program Files\Pidgin\pidgin.dll [2.4.3.0]
64A8ED51 C:\Program Files\Pidgin\pidgin.dll  pidgin_main  /home/stu/build/win32/pidgin-2.4.3-mtn/pidgin/gtkmain.c:897
         C:\Program Files\Pidgin\pidgin.exe [2.4.3.0]
00401EFF C:\Program Files\Pidgin\pidgin.exe  WinMain@16  win32/winpidgin.c:658
00402736 C:\Program Files\Pidgin\pidgin.exe
004010B6 C:\Program Files\Pidgin\pidgin.exe  __mingw_CRTStartup  /home/bitwalk/redhat/BUILD/mingw-3.14/mingw-runtime-3.14/crt1.c:237
Comment 7 David Grohmann 2008-07-04 21:03:56 UTC
cairo is 1.6.4-2 in this version of windows gtk
Comment 8 David Grohmann 2008-07-15 18:07:14 UTC
_gdk_drawable_ref_cairo_surface() can return NULL, but gdk_window_begin_paint_region() does not check if it did so before passing the result to cairo_surface_set_device_offset(), which also doesn't check if it's NULL before dereferencing it. 

Is it possible my error is a NULL pointer dereference?
-------------------------------------------------------
Excerpt from gdkwindow.c line 970-1026 
...
void	      
gdk_window_begin_paint_region (GdkWindow *window,
			       GdkRegion *region)
{
...
  paint->surface = _gdk_drawable_ref_cairo_surface (paint->pixmap);
  cairo_surface_set_device_offset (paint->surface,
				   - paint->x_offset, - paint->y_offset);
...
}
...
-------------------------------------------------------
Excerpt from  gdkdraw.c lines 1257-1275
...
/**
 * _gdk_drawable_ref_cairo_surface:
 * @drawable: a #GdkDrawable
 * 
 * Obtains a #cairo_surface_t for the given drawable. If a
 * #cairo_surface_t for the drawable already exists, it will be
 * referenced, otherwise a new surface will be created.
 * 
 * Return value: a newly referenced #cairo_surface_t that points
 *  to @drawable. Unref with cairo_surface_destroy()
 **/
cairo_surface_t *
_gdk_drawable_ref_cairo_surface (GdkDrawable *drawable)
{
  g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);

  return GDK_DRAWABLE_GET_CLASS (drawable)->ref_cairo_surface (drawable);
}
....
Comment 9 David Grohmann 2008-07-15 19:32:10 UTC
GTK bug - http://bugzilla.gnome.org/show_bug.cgi?id=543209
Comment 11 Carl Worth 2008-07-15 19:43:32 UTC
(In reply to comment #8)
> _gdk_drawable_ref_cairo_surface() can return NULL, but
> gdk_window_begin_paint_region() does not check if it did so before passing the
> result to cairo_surface_set_device_offset(), which also doesn't check if it's
> NULL before dereferencing it. 

That's quite possible. And for cairo, this is the expected behavior of this
function.

If a cairo function returns a cairo_status_t value, then it will return
CAIRO_STATUS_NULL_POINTER if you pass it NULL. But the void functions
will simply dereference the pointer and crash.

If you're interested in seeing that behavior change at all, then that
would be a discussion to be had on the cairo mailing list, (see
http://cairographics.org/lists )

-Carl
Comment 12 David Grohmann 2008-07-15 19:51:23 UTC
(In reply to comment #11)
> (In reply to comment #8)
> > _gdk_drawable_ref_cairo_surface() can return NULL, but
> > gdk_window_begin_paint_region() does not check if it did so before passing the
> > result to cairo_surface_set_device_offset(), which also doesn't check if it's
> > NULL before dereferencing it. 
> 
> That's quite possible. And for cairo, this is the expected behavior of this
> function.
> 
> If a cairo function returns a cairo_status_t value, then it will return
> CAIRO_STATUS_NULL_POINTER if you pass it NULL. But the void functions
> will simply dereference the pointer and crash.
> 
> If you're interested in seeing that behavior change at all, then that
> would be a discussion to be had on the cairo mailing list, (see
> http://cairographics.org/lists )
> 
> -Carl
> 

Well I think I may have erred in filing this bug report here in the first place, as that GTK function should be checking the return value of the other GTK function first knowing that libcairo will happily crash on NULL input.  It's just that the crash stack first implicated cairo, since that's the library it crashed in.

I'm just trying to figure out who is to blame so I can get this fixed. If either cairo, or GTK check for NULL before dereferencing then it solves the problem, I will leave it up to the 2 development communities to choose who should be the one checking.
Comment 13 Chris Wilson 2008-10-10 11:30:08 UTC
The crash is caused by GTK+ passing a NULL surface to cairo, something which should not happen. In particular, it looks like GTK+ made an error when trying to create the win32 drawable and that should be fixed at source.

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.