GNOME Bugzilla – Bug 319204
64bit problem with Gtk2::Gdk::Color properties?
Last modified: 2005-12-21 17:05:11 UTC
Version details: Gtk2 1.110 Distribution/Version: Ubuntu Breezy The below program generates the wrong output when run on x86_64: Parsed color: 1,2,3 Color from button (property): 0,0,3 Color from button (property, after set): 0,0,3 Color from selection: 1,2,3 Color from selection (property): 0,0,3 I expected that the output would be 1,2,3 for all. On i686: Parsed color: 1,2,3 Color from button (property): 1,2,3 Color from button (property, after set): 1,2,3 Color from selection: 1,2,3 Color from selection (property): 1,2,3 #!/usr/bin/perl -w use strict; use Gtk2 -init; use Glib qw(:constants); my $color = Gtk2::Gdk::Color->parse('#010203'); print "Parsed color: ", &color2string($color), "\n"; my $color_button = Gtk2::ColorButton->new_with_color($color); print "Color from button (property): ", &color2string($color_button->get('color')), "\n"; $color_button->set('color', $color); print "Color from button (property, after set): ", &color2string($color_button->get('color')), "\n"; my $color_selection = Gtk2::ColorSelection->new; $color_selection->set_current_color($color); print "Color from selection: ", &color2string($color_selection->get_current_color), "\n"; print "Color from selection (property): ", &color2string($color_selection->get('current_color')), "\n"; sub color2string { join(',', map { $_[0]->$_ / 257 } qw(red green blue)); }
Ouch, looks like the new converters still need some work. In perl's CORE/config.h, what is IVTYPE defined to be on the x86_64 box? What does perl -MConfig -wle'foreach (qw(use64bitall use64bitint)) { print $Config{ $_ } || "undef"; }' print?
x86_64$ perl -MConfig -wle'foreach (qw(use64bitall use64bitint)) { print $Config{ $_ } || "undef"; }' define define
And what is IVTYPE in CORE/config.h defined to be?
#define IVTYPE long /**/ #define UVTYPE unsigned long /**/ #define I8TYPE char /**/ #define U8TYPE unsigned char /**/ #define I16TYPE short /**/ #define U16TYPE unsigned short /**/ #define I32TYPE int /**/ #define U32TYPE unsigned int /**/ #ifdef HAS_QUAD #define I64TYPE long /**/ #define U64TYPE unsigned long /**/ #endif #define NVTYPE double /**/ #define IVSIZE 8 /**/ #define UVSIZE 8 /**/ #define I8SIZE 1 /**/ #define U8SIZE 1 /**/ #define I16SIZE 2 /**/ #define U16SIZE 2 /**/ #define I32SIZE 4 /**/ #define U32SIZE 4 /**/ #ifdef HAS_QUAD #define I64SIZE 8 /**/ #define U64SIZE 8 /**/ #endif
Ok, your configuration matches the one I had in mind when writing the #ifdef wrappers for the big integer converters. The weird thing is though, that as far as I can tell, nothing in your code should ever result in one of the 64 bit converters being called. There's simply nothing in there involving either gint64 or guint64. Does the bug happen with older versions of Gtk2 as well? Or only with 1.110? If it only happens with 1.110, can you run this program through gdb, set breakpoints on the converters and put the resulting backtraces here? $ gdb perl (gdb) r color.pl # run it once first so gdb knows about the function names (gdb) b newSVGInt64 (gdb) b newSVGUInt64 (gdb) b SvGInt64 (gdb) b SvGUInt64 (gdb) r color.pl Now whenever a breakpoint is reached, get the backtrace and continue: (gdb) bt # ... (gdb) c The output of 'bt' is what I'd need.
I have this same problem with 1.100 as shipped by Ubuntu and 1.110 that I compiled myself. Like you expected, it did not hit any breakpoints. $ gdb debugperl GNU gdb 6.3-debian Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "x86_64-linux-gnu"...Using host libthread_db library "/lib/libthread_db.so.1". (gdb) r colortest64 Starting program: /usr/bin/debugperl colortest64 [Thread debugging using libthread_db enabled] [New Thread 46912504633040 (LWP 7384)] Starting Parsed color: 1,2,3 Color from button (property): 0,0,3 Color from button (property, after set): 0,0,3 Color from selection: 1,2,3 Color from selection (property): 0,0,3 Program exited normally. (gdb) b newSVGInt64 Breakpoint 1 at 0x2aaaab434bf0 (gdb) b newSVGUInt64 Breakpoint 2 at 0x2aaaab434c40 (gdb) b SvGInt64 Breakpoint 3 at 0x2aaaab434bc0 (gdb) b SvGUInt64 Breakpoint 4 at 0x2aaaab434c10 (gdb) r colortest64 Starting program: /usr/bin/debugperl colortest64 [Thread debugging using libthread_db enabled] [New Thread 46912504633040 (LWP 7402)] Starting Parsed color: 1,2,3 Color from button (property): 0,0,3 Color from button (property, after set): 0,0,3 Color from selection: 1,2,3 Color from selection (property): 0,0,3 Program exited normally. (gdb)
I hacked a bit in GdkColor.xs to try to dump the GdkColor structure. I also changed the colortest64 script to also output pixel. It looks like the first 64 bits of the GdkColor are being overwritten by a pointer. This wipes out the pixel, red and green color value. If this is true, that would explain why it works under 32-bit, only pixel is overwritten. BTW, it looks like the pointer points to 16 bytes beyond the start of the GdkColor. $ perl ../colortest64 Starting 0x942720: 0000000001010202030300000000000000000000000000000000000000000000 0x942720: 0000000001010202030300000000000000000000000000000000000000000000 Parsed color: 0x00000000,0x0101,0x0202,0x0303 0x942730: 4027940000000000030396ab0000000000000000000000000303000000000000 Color from button (property): 0x00942740,0x0000,0x0000,0x0303 0x942730: 4027940000000000030396ab0000000000000000000000000303000000000000 Color from button (property, after set): 0x00942740,0x0000,0x0000,0x0303 0x942730: b8c67700010102020303c4aa0000000000000000000000000303000000000000 Color from selection: 0x0077c6b8,0x0101,0x0202,0x0303 0x942730: 4027940000000000030396ab0000000000000000000000000303000000000000 Color from selection (property): 0x00942740,0x0000,0x0000,0x0303 0x942730: b8c67700010102020303c4aa0000000000000000000000000303000000000000 Color from selection: 0x0077c6b8,0x0101,0x0202,0x0303 0x942730: 4027940000000000030396ab0000000000000000000000000303000000000000 Color from selection (property): 0x00942740,0x0000,0x0000,0x0303
This is the output on x86. Looks like the first 32 bits of the GdkColor are overwritten with a pointer. The pointer is 12 bytes beyond the start of the GdkColor. Starting 0x83b2558: 0000000001010202030300000000000000000000000000000000000000000000 0x83b2558: 0000000001010202030300000000000000000000000000000000000000000000 Parsed color: 0x00000000,0x0101,0x0202,0x0303 0x83b2564: 70253b0801010202030321080000000001010202030300000000000000000000 Color from button (property): 0x083b2570,0x0101,0x0202,0x0303 0x83b2564: 70253b0801010202030321080000000001010202030300000000000000000000 Color from button (property, after set): 0x083b2570,0x0101,0x0202,0x0303 0x83b2564: 47286c62010102020303ebbf0000000001010202030300000000000000000000 Color from selection: 0x626c2847,0x0101,0x0202,0x0303 0x83b2564: 70253b0801010202030321080000000001010202030300000000000000000000 Color from selection (property): 0x083b2570,0x0101,0x0202,0x0303 0x83b2564: 47286c62010102020303ebbf0000000001010202030300000000000000000000 Color from selection: 0x626c2847,0x0101,0x0202,0x0303 0x83b2564: 70253b0801010202030321080000000001010202030300000000000000000000 Color from selection (property): 0x083b2570,0x0101,0x0202,0x0303
Some notes from stepping through the source: GdkColor is 1xsizeof(guint32)+3*sizeof(guint16) = 4+3*2 = 12 bytes. I would not be surprised if the compiler padded this to 16 on ia64. GdkColors are allocated using a GMemChunk -- that is, a fixed-size allocator. You will see the same addresses over and over, and garbage from previous uses will remain in memory. gtk_color_selection_get_color() does not alter the value of pixel in the passed-in GdkColor; it only modifies red, green, and blue. g_object_get() copies boxed objects by default. The implementation of gdk_color_copy() bumps to the next free spot in the GMemChunk and then does *new_color = *color, which means that the value of pixel is copied in ->get(), unlike with $selection->get_color(). Gtk2 uses the default GPerlBoxedWrapperClass for dealing with GdkColors, so the pointer held by the sv that you see in perl actually points to another block of memory which contains the GType of the object, the pointer to it, and a flag that says whether we should kill the boxed object on DESTROY.
Created attachment 53751 [details] [review] Patch to copy boxed values in Glib::Object::get() I have been contemplating this sort of change to solve other problems, but it would be interesting to find out if this has any effect on your bug.
$ perl -IGlib-1.110/blib/arch/ -IGlib-1.110/blib/lib/ -IGtk2-1.110/blib/arch/ -IGtk2-1.110/blib/lib/ colortest64 Starting Parsed color: 0x00000000,0x0101,0x0202,0x0303 Color from button (property): 0x00951398,0x0101,0x0202,0x0303 Color from button (property, after set): 0x00951398,0x0101,0x0202,0x0303 Color from selection: 0x0077e008,0x0101,0x0202,0x0303 Color from selection (property): 0x00a179d0,0x0101,0x0202,0x0303 Color from selection: 0x0077e008,0x0101,0x0202,0x0303 Color from selection (property): 0x00a179d0,0x0101,0x0202,0x0303 :-D
So, it looks like this is the correct fix. muppet, there's an unstable release due next week (2005-11-14). Can you get this in before that date? (One minor nag: gperl_sv_from_value2 isn't really descriptive. I've no better idea, though. All I can come up with is _full which isn't great either.)
I don't like the name, either, but a better one proves elusive. For the time being, i'll make it a private function, not exported in gperl.h.
Committed to HEAD. What about stable-1-10 ? 2005/11/13 muppetman * GValue.xs, GObject.xs: The GObject property interface passes around pointers to boxed objects, but does not transfer ownership of them. Thus, the old code was letting perl hold on to dead pointers. We basically need to be able to specify whether to copy boxed objects when converting from GValue to SV. Since gperl_sv_from_value() is public and API frozen, add a new private function, _gperl_sv_from_value_internal(), and call this from both gperl_sv_from_value() and Glib::Object::get(). Fixes http://bugzilla.gnome.org/show_bug.cgi?id=319204 and several other hard-to-diagnose intermittent bugs.
It's a pretty important fix for 64-bit platforms, so -- yes, I think it should go into stable-1-10 too. Is there any way to test this stuff for regressions?
Okay, committed to stable-1-10. I have been testing whether the patch works on some bindings for another library. It basically involves seeing whether you crash by trying to access dead memory. I'm not sure there's a way to test this inside Glib itself without some extra XS scaffolding. Will look into that.
Closing since the bug has been fixed.