DO NOT REPLY TO THIS MESSAGE. INSTEAD, POST ANY RESPONSES TO THE LINK BELOW.
[STR New]
Link: http://www.fltk.org/str.php?L1894
Version: 1.1-current
This is a long standing bug. Maybe since version 1.0.
The docs of Fl_Group state: "The destructor also deletes all the children.
This allows a whole tree to be deleted at once, without having to keep a
pointer to all the children in the user code. A kludge has been done so
the Fl_Group and all of it's children can be automatic (local) variables,
but you must declare the Fl_Group first, so that it is destroyed last."
Obviously, the kludge is this statement in Fl_Group::clear() at line #357:
if (o->parent() == this) delete o;
together with the Fl_Widget destructor setting its parent_ to 0 (without
removing itself from the parent group).
Most of the time, this works...
But sometimes, it can happen, that the memory of a deleted child widget
has already been "returned to the system" and thus isn't accessible any
more. Then, the program segfaults in o->parent().
I will attach a test program (crash.cxx) that demonstrates this behavior,
together with comments, how to make it "work" or "crash". The values given
in the head of "crash.cxx" are from my test systems: Windows XP (SP2) and
Linux (debian/Knoppix based, kernel 2.6.17). They may vary on different
systems, or the program may not crash at all, dependent on the memory
allocation implementation.
The test program adds two widgets (My_Input) to a group, and each My_Input
adds two other box widgets (green and red) to the same group.
There are two buttons to remove (1) My_Input #1 from the group and (2) the
complete group from the window.
IMHO, this is all perfectly correct code WRT FLTK docs and implementation
details, but if I'm wrong, please correct me.
I'll attach another, slightly modified source file with a documented
debugging session in the next post.
Albrecht
Link: http://www.fltk.org/str.php?L1894
Version: 1.1-current
/*
===============================================================
modify "KBS" below to allocate a different amount of memory
KBS = 1 ... 127 may work (linux)
KBS = 128 or more may crash (linux)
KBS = 1 ... 15 may work (windows)
KBS = 16 or more may crash (windows)
test for yourself ...
compile and link with: fltk-config --compile crash.cxx
run the program, click Button 1, then click Button 2, then
close the window.
This is, what should happen (comments after '#'):
# program started:
>>> My_Box(1[1]): this=003D4080, parent()=003D26D8, mem=15 KB
>>> My_Box(1[2]): this=003D7CD8, parent()=003D26D8, mem=15 KB
>>> My_Box(2[1]): this=003DB9A0, parent()=003D26D8, mem=15 KB
>>> My_Box(2[2]): this=00DE0048, parent()=003D26D8, mem=15 KB
# Button 1 clicked:
button1_cb - delete input1 ...
>>> ~My_Input (1): parent()=00000000
>>> ~My_Box(1[2]): this=003D7CD8, parent()=00000000
--- ~My_Box(1[2]): this=003D7CD8, parent()=00000000
--- ~My_Input (1): parent()=00000000
>>> ~My_Box(1[1]): this=003D4080, parent()=00000000
--- ~My_Box(1[1]): this=003D4080, parent()=00000000
# Button 2 clicked:
button2_cb - delete group ...
>>> ~My_Input (2): parent()=003D26D8
>>> ~My_Box(2[2]): this=00DE0048, parent()=003D26D8
--- ~My_Box(2[2]): this=00DE0048, parent()=003D26D8
--- ~My_Input (2): parent()=003D26D8
>>> ~My_Box(2[1]): this=003DB9A0, parent()=003D26D8
--- ~My_Box(2[1]): this=003DB9A0, parent()=003D26D8
# Window close button clicked:
exit_cb() - exiting normally :-)
===============================================================
*/
#define KBS 15 // modify: different values see above
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Widget.H>
#include <FL/fl_message.H>
#include <stdio.h>
#include <stdlib.h>
class My_Input;
Fl_Window *window;
Fl_Group *group;
Fl_Button *button1;
Fl_Button *button2;
My_Input *input1;
My_Input *input2;
class My_Box : public Fl_Box {
int idx; // box index
char dummy_array[1024*KBS]; // allocate <KBS> KB memory
public:
My_Box (int, int, int, int, char *, int);
~My_Box();
};
My_Box::My_Box (int X, int Y, int W, int H, char *L, int I)
: Fl_Box (X,Y,W,H,L) {
align (FL_ALIGN_INSIDE);
idx = I; // box index
printf (">>> My_Box(%s[%d]): this=%p, parent()=%p, mem=%d KB\n",
label(),idx,this,parent(),KBS);
}
My_Box::~My_Box () {
printf (">>> ~My_Box(%s[%d]): this=%p,
parent()=%p\n",label(),idx,this,parent());
if (parent()) parent()->remove(this);
printf ("--- ~My_Box(%s[%d]): this=%p,
parent()=%p\n",label(),idx,this,parent());
}
class My_Input : public Fl_Input {
My_Box box1;
My_Box *box2;
public:
My_Input (int, int, int, int, char *);
~My_Input();
};
My_Input::My_Input (int X, int Y, int W, int H, char *L)
: Fl_Input (X,Y,W,H,L), box1(X+W+1,Y,H,H,L,1) {
box1.box(FL_THIN_DOWN_BOX); // 1st box
box1.color(FL_RED);
box2 = new My_Box(X+W+H+2,Y,H,H,L,2); // 2nd box
box2->box(FL_THIN_UP_BOX);
box2->color(FL_GREEN);
}
My_Input::~My_Input () {
printf (">>> ~My_Input (%s): parent()=%p\n",label(),parent());
if (box1.parent()) box1.parent()->remove(box1);
if (box2->parent()) box2->parent()->remove(box2);
delete box2;
printf ("--- ~My_Input (%s): parent()=%p\n",label(),parent());
}
void exit_cb(Fl_Widget *,void *) {
printf ("exit_cb() - exiting normally :-)\n");
exit(0);
}
void button1_cb(Fl_Widget *,void *) {
button1->deactivate();
group->remove(input1); // remove from group
printf ("button1_cb - delete input1 ...\n");
delete input1;
window->redraw();
}
void button2_cb(Fl_Widget *,void *) {
button1->deactivate();
button2->deactivate();
window->remove(group);
printf ("button2_cb - delete group ...\n");
delete group;
window->redraw();
}
int main(int argc, char **argv) {
setvbuf (stdout,NULL,_IONBF,0); // unbuffered for testing
window = new Fl_Window(600,400);
group = new Fl_Group(10,10,580,180);
input1 = new My_Input( 50,50,100,20,"1");
input2 = new My_Input(350,50,100,20,"2");
group->end();
group->box(FL_FRAME_BOX);
button1 = new Fl_Button( 50,250,200,100,"Delete Input 1");
button1->callback(button1_cb,0);
button2 = new Fl_Button(350,250,200,100,"Delete Group");
button2->callback(button2_cb,0);
window->end();
window->callback(exit_cb);
window->resizable(group);
window->size_range(600,400,0,0);
window->show(argc, argv);
return Fl::run();
}
_______________________________________________
fltk-bugs mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-bugs