GNOME Bugzilla – Bug 54838
Gimp Segment Fault on Add-Bevel Script
Last modified: 2001-06-02 14:59:45 UTC
Gimp Version: 1.2.1 glib version: 1.2.10 (currently from ximian RPM, but also have tried with RedHat rpm, and also glib 1.2.10 compiled from source) Gtk+ version: 1.2.10 (currently from ximian RPM, but also have tried with RedHat rpm version, and also compiled from source) Xfree86: 4.0.1 from RedHat RPM Glibc: 2.2 If I try to add a bevel to any text, I get a segment fault. For example, if I launch Gimp, start a new file, then select the text tool to insert the word "Testing" (font and font-size don't seem to make a difference, but I usually use times at 24pts), then with the newly inserted text still highlighted I right-click, select Script-Fu|Decor|Bevel.... I leave the defualts, and right after the part where the script does the bump map, Gimp crashes with a segmentation fault. I have also seen this problem on RedHat 6.2. Here is a snapshot of the errors just prior to the crash, and the stack trace following the crash: Gtk-WARNING **: invalid cast from `(unknown)' to `GimpDrawable' Gtk-WARNING **: invalid cast from `(unknown)' to `GimpDrawable' Gtk-WARNING **: invalid cast from `(unknown)' to `GimpDrawable' Gtk-WARNING **: invalid cast from `(unknown)' to `GimpDrawable' Gtk-WARNING **: invalid cast from `(unknown)' to `GimpDrawable' Gtk-WARNING **: invalid cast from `(unknown)' to `GimpDrawable' Gimp-CRITICAL **: file gimpdrawable.c: line 635 (gimp_drawable_width): assertion `GIMP_IS_DRAWABLE (drawable)' failed. gimp: fatal error: Segmentation fault gimp (pid:31438): [E]xit, [H]alt, show [S]tack trace or [P]roceed: S
+ Trace 5480
I can reproduce this crash easily. Note that it only works if you run the Add Bevel script before anchoring the layer. Running the script on a floating selection is apparently what causes the crash. The font size and other parameters do not really matter.
The script add-bevel.scm fails at crop-image when the layer to be beveled is (1) small, (2) has a very large offset from the upper left hand corner of the containing image, (3) is a floating layer, and (4) the user is requesting to work on an image copy. This array of conditions can be reproduced without using the text tool; any floating layer that has smaller width or height than the layer's current x or y offset will prompt a crash. crop_image() (crop.c CVS-1.61 line 823) will cull layers immediately if Undo has been disabled for the containing GimpImage and the result of the crop leaves a layer's width or height zero. The floating layer will be culled as well; unfortunately, crop_image persists a dangling pointer to the floating layer, and continues to operate on it. This is the immediate cause of the crash. The condition of Undo being disabled arises from requesting that the AddBevel script operate on a copy image. The script disables undo for the new copy image for the duration of the script run. Garry Osgood Point of failure: (Search for !!!) ------------------------------------------------------ !!!-1 width and height will be zero for small layers !!!-2 with large x and y offsets !!!-3 Layer with zero resultant layer width or height are culled here !!!-4 This floating selection may be a dangling reference to a culled layer; if so, the memory region likely points to something not recognizable as a layer. void crop_image (GImage *gimage, gint x1, gint y1, gint x2, gint y2, gboolean layer_only, gboolean crop_layers) { Layer *layer; Layer *floating_layer; Channel *channel; GList *guide_list_ptr; GSList *list; gint width, height; gint lx1, ly1, lx2, ly2; gint off_x, off_y; gint doff_x, doff_y; width = x2 - x1; height = y2 - y1; /* Make sure new width and height are non-zero */ if (width && height) { gimp_add_busy_cursors (); if (layer_only) { undo_push_group_start (gimage, LAYER_RESIZE_UNDO); layer = gimage->active_layer; if (layer_is_floating_sel (layer)) floating_sel_relax (layer, TRUE); drawable_offsets (GIMP_DRAWABLE (layer), &doff_x, &doff_y); off_x = (doff_x - x1); off_y = (doff_y - y1); layer_resize (layer, width, height, off_x, off_y); if (layer_is_floating_sel (layer)) floating_sel_rigor (layer, TRUE); undo_push_group_end (gimage); } else { floating_layer = gimage_floating_sel (gimage); undo_push_group_start (gimage, CROP_UNDO); /* relax the floating layer */ if (floating_layer) floating_sel_relax (floating_layer, TRUE); /* Push the image size to the stack */ undo_push_gimage_mod (gimage); /* Set the new width and height */ gimage->width = width; gimage->height = height; /* Resize all channels */ list = gimage->channels; while (list) { channel = (Channel *) list->data; channel_resize (channel, width, height, -x1, -y1); list = g_slist_next (list); } /* Don't forget the selection mask! */ channel_resize (gimage->selection_mask, width, height, -x1, -y1); gimage_mask_invalidate (gimage); /* crop all layers */ list = gimage->layers; while (list) { GSList *next; layer = (Layer *) list->data; next = g_slist_next (list); layer_translate (layer, -x1, -y1); drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); if (crop_layers) { drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y); lx1 = CLAMP (off_x, 0, gimage->width); ly1 = CLAMP (off_y, 0, gimage->height); lx2 = CLAMP ((drawable_width (GIMP_DRAWABLE (layer)) + off_x), 0, gimage->width); ly2 = CLAMP ((drawable_height (GIMP_DRAWABLE (layer)) + off_y), 0, gimage->height); !!!-1 width = lx2 - lx1; !!!-2 height = ly2 - ly1; if (width && height) layer_resize (layer, width, height, -(lx1 - off_x), -(ly1 - off_y)); else !!!-3 gimage_remove_layer (gimage, layer); } list = next; } /* Make sure the projection matches the gimage size */ gimage_projection_realloc (gimage); /* rigor the floating layer */ !!!-4 if (floating_layer) floating_sel_rigor (floating_layer, TRUE); guide_list_ptr = gimage->guides; while ( guide_list_ptr != NULL) { undo_push_guide (gimage, (Guide *)guide_list_ptr->data); guide_list_ptr = guide_list_ptr->next; } undo_push_group_end (gimage); /* Adjust any guides we might have laying about */ crop_adjust_guides (gimage, x1, y1, x2, y2); /* shrink wrap and update all views */ channel_invalidate_previews (gimage); layer_invalidate_previews (gimage); gimage_invalidate_preview (gimage); gdisplays_update_full (gimage); gdisplays_shrink_wrap (gimage); } gimp_remove_busy_cursors (NULL); gdisplays_flush (); } }
[Forgotten addendum] Apart from the bug, the script does not always seem to be doing what the author of add-bevel.scm, Andrew Donkin <ard@cs.waiko.ac.nz> had in mind for his 1.03 version: to add, then trim, a one pixel perimeter around a layer. His intent is served when a layer's offset is zero; otherwise he needs to instruct gimp-crop to operate only on the current layer. This boolean is not being extruded through to the scheme interface from the underlying core routine crop_image(); so there is no way for Mr. Donkin to request such a thing. Fixing this will take a little more work than the dangling pointer in crop_image(). GRO
1. Seth Burgess, in additional comments to #9350, reported the crash on floating selections. 2. The mis-cropping cited by dyfa@addict.de in #9350, is related to my additional comment to this bug made on 19 May 2001. The scheme interface does not permit a script writer to indicate that she wishes to crop a layer only, and not the entire image. For layers smaller than canvases, this miscropping is the general rule. 3. I am testing a partial fix, one that prevents the crash (fixes a dangling pointer) but does not address the cropping issue. The script works as the author intended only when the layer size equals the canvas size. *** This bug has been marked as a duplicate of 9350 ***