subject: resource problem in FLTK, bug?

44 views
Skip to first unread message

Andre Steenveld

unread,
Sep 9, 2026, 5:38:13 AMSep 9
to fltk.general
Dear all,

Lately I'm testing a lot with the examples from `FLTK-Tutorial.pdf' (by Georg Potthast).
The tutorial is from 2012 and is writen for FLTK v1.3.0 but works fine for v1.4.5 except for one example. My aim is to play a bit with the code, move things around, add some logging. Just to see how things work. Then I run the examples from a command line to be able to see what I write to stdout while clicking in the gui. And I do this on a Debian Trixie system with GCC and CMake.

The one example that fails reports `free(): invalid pointer' but no `new/delete' is used so I assume it is a resource problem in FLTK.
The versions of FLTK I use are direct clones from git, build and used in location. I have tested agains FLTK v1.4.5 and v1.5.0 and the results are identical (for all examples).
I'm not using the version that Debian Trixie provide by default because that has problems, I found out a few months ago and was discussed on this forum as well.

When I run the example I get the following console output:
```
$ ./ex5t
main(): open FLTK main form
FLTK: fl_main: ...
FLTK: fl_main: show
FLTK: fl_main: run
FLTK: bla
FLTK: ja ja
FLTK: 0
free(): invalid pointer
Aborted
```

The console output suggests that the problem is triggered when returning from the call to `fl_main' and no exception is catched in `main' which suggest it is triggered by destructor operations on FLTK objects created in `fl_main'.
I am not (yet) able to narrow it down any further.

There are 17 examples and only this one shows the problem in both versions of FLTK I tested it with.

My questions are:
- is this a problem in the FLTK code?
- should I report this as a bug?

This is the code that I'm using. Except for the logging lines identical to the original example but with an extra call from `main(...)' to `fl_main(...)' in trying to identify where the problem lives.
```
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Output.H>

#include <iostream>
#define _log(prefix, msg) std::cout << prefix << ": " << msg << std::endl
#define logm(msg) _log("main()", msg)
#define log(msg) _log("FLTK", msg)

constexpr const int WIDTH = 300;
constexpr const int HEIGHT = 90;

Fl_Input input1(90, 10, 180, 20, "Input: ");
Fl_Output output1(90, 40, 180, 20, "Output: ");

static void cb_input1(
    Fl_Input*,
    void* userdata
) {
    log(input1.value());
    input1.label((const char*)userdata);
    output1.value(input1.value());
    input1.value("");
}

int fl_main(int argc, char **argv)
{
    log("fl_main: ...");
    Fl_Window win(WIDTH, HEIGHT, "FLTK Tutorial - Example 5, input/output");

    win.begin();
        win.add(input1);
        input1.callback(
            (Fl_Callback*)cb_input1,
            (void *)"Enter next:"
        );

        // trigger on release of widget focus or on enter key.
        input1.when( FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY );
        win.add(output1);
    win.end();

    log("fl_main: show");
    win.show();

    log("fl_main: run");
    auto result = Fl::run();
    log(result);
    return result;
}

int main(int argc, char **argv) {
    int result = 0;
    try {
        logm("open FLTK main form");
        result = fl_main(argc, argv);
        logm("OK");
    }
    catch (...) {
        result = -1;
        logm("Exception");
    }
    logm(result);
    return result;
}
```

Andre Steenveld

unread,
Sep 9, 2026, 6:17:31 AMSep 9
to fltk.general
Found out what the problem was, use of static instances.

Here is the output after correcten and the corrected code.

```
$ ./ex5t
main(): open FLTK main form
FLTK: fl_main: ...
FLTK: fl_main: show
FLTK: fl_main: run
FLTK: bla
FLTK: ja ja
FLTK: 0
main(): OK
main(): 0
```

and the code now looks like this:
```
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Output.H>

#include <iostream>
#define _log(prefix, msg) std::cout << prefix << ": " << msg << std::endl
#define logm(msg) _log("main()", msg)
#define log(msg) _log("FLTK", msg)

constexpr const int WIDTH = 300;
constexpr const int HEIGHT = 90;

//Fl_Input input1(90, 10, 180, 20, "Input: ");
//Fl_Output output1(90, 40, 180, 20, "Output: ");
Fl_Input * input1;
Fl_Output * output1;


static void cb_input1(
    Fl_Input*,
    void* userdata
) {
    log(input1->value());
    input1->label((const char*)userdata);
    output1->value(input1->value());
    input1->value("");

}

int fl_main(int argc, char **argv)
{
    log("fl_main: ...");
    Fl_Window win(WIDTH, HEIGHT, "FLTK Tutorial - Example 5, input/output");

    win.begin();
        //win.add(input1);
        input1 = new Fl_Input(90, 10, 180, 20, "Input: ");
        input1->callback(

            (Fl_Callback*)cb_input1,
            (void *)"Enter next:"
        );

        // trigger on release of widget focus or on enter key.
        input1->when( FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY );

       //win.add(output1);
       output1 = new Fl_Output(90, 40, 180, 20, "Output: ");

    win.end();

    log("fl_main: show");
    win.show();

    log("fl_main: run");
    auto result = Fl::run();
    log(result);
    return result;
}

int main(int argc, char **argv) {
    int result = 0;
    try {
        logm("open FLTK main form");
        result = fl_main(argc, argv);
        logm("OK");
    }
    catch (...) {
        result = -1;
        logm("Exception");
    }
    logm(result);
    return result;
}
```

problem solved.

Op woensdag 9 september 2026 om 11:38:13 UTC+2 schreef Andre Steenveld:

Greg Ercolano

unread,
Sep 9, 2026, 11:44:26 AMSep 9
to fltkg...@googlegroups.com

On 9/9/26 03:17, Andre Steenveld wrote:

Found out what the problem was, use of static instances.
[..]
problem solved.

    Ah, good.

    Is it a bug report then for Georg Potthast?
    He might still be maintaining the tutorial.

    He posted here on fltk.general as recently as 2017, so you may be able to reach him by his email that way:
    https://groups.google.com/g/fltkgeneral/c/VqbQHJaLFo4/m/H6RHGtffBAAJ

Andre Steenveld

unread,
Sep 10, 2026, 4:13:23 AMSep 10
to fltkg...@googlegroups.com, Greg Ercolano


On 9/9/26 5:44 PM, Greg Ercolano wrote:
>
>     Is it a bug report then for Georg Potthast?
>     He might still be maintaining the tutorial.
>
Sounds like a good idea ;-)

>     He posted here on fltk.general as recently as 2017, so you may be
> able to reach him by his email that way:
Nine years... give it a try anyway.

Ian MacArthur

unread,
Sep 10, 2026, 4:39:42 AMSep 10
to fltk.general
On Wednesday, 9 September 2026 at 16:44:26 UTC+1 Erco wrote:


    Is it a bug report then for Georg Potthast?
    He might still be maintaining the tutorial.

I wonder if it might imply a "weakness" in our docs though?
Should we be explicitly saying that it may not be a "Good Idea" to add static objects as children of a dynamically created window?
(Maybe we already do and I have forgotten, but I guess even in that case the point stands!)

I assume the "issue" here is that the stack-automatically created window goes out of scope when main() terminates, and is then reaped (deleted) and tries to clean up it's children - but in this case the children are static objects so don't want to be deleted at this point...

 

Andre Steenveld

unread,
Sep 10, 2026, 5:41:06 AMSep 10
to fltkg...@googlegroups.com


On 9/10/26 10:39 AM, Ian MacArthur wrote:
On Wednesday, 9 September 2026 at 16:44:26 UTC+1 Erco wrote:


    Is it a bug report then for Georg Potthast?
    He might still be maintaining the tutorial.

I wonder if it might imply a "weakness" in our docs though?
Should we be explicitly saying that it may not be a "Good Idea" to add static objects as children of a dynamically created window?
(Maybe we already do and I have forgotten, but I guess even in that case the point stands!)
Sounds to me like the thing to do. (I have not seen any remark to using static instances in the documentation.)


I assume the "issue" here is that the stack-automatically created window goes out of scope when main() terminates, and is then reaped (deleted) and tries to clean up it's children - but in this case the children are static objects so don't want to be deleted at this point...
And I have noticed several examples in the tutorial by Georg Potthast where exactly this is how this is done.
In several variations like the one documented in the previous message.

But also variations where there is a static `Fl_Window win' instance and where parts are added which are local to a function context (and on the stack). When leaving the function then all instances that are in its local scope disapear and `win' will have dead pointer.

There is more than one way to violate this principle. The underlaying problem, IMHO, is the use of raw (and naked) pointers, `new' and `delete'.

Bad thing (for the Tutorial) is that most of the effects happens when the example is closing down and you will not notice it.
But when applying the same techniques in a library then it becomes a different thing in total. (Example works, why is my code throwing a null reference exception?)


Albrecht Schlosser

unread,
Sep 10, 2026, 12:00:42 PMSep 10
to fltkg...@googlegroups.com
On 9/10/26 11:40 Andre Steenveld wrote:

On 9/10/26 10:39 AM, Ian MacArthur wrote:
On Wednesday, 9 September 2026 at 16:44:26 UTC+1 Erco wrote:


    Is it a bug report then for Georg Potthast?
    He might still be maintaining the tutorial.

I wonder if it might imply a "weakness" in our docs though?
Should we be explicitly saying that it may not be a "Good Idea" to add static objects as children of a dynamically created window?
(Maybe we already do and I have forgotten, but I guess even in that case the point stands!)
Sounds to me like the thing to do. (I have not seen any remark to using static instances in the documentation.)

I'm sure that it is mentioned, and I found it in the docs of the destructor of Fl_Group. Not the best place, admittedly, but pretty explicit. Citation:

"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.

It is allowed that the Fl_Group and all of its children are automatic (local) variables, but you must declare the Fl_Group first, so that it is destroyed last.

If you add static or automatic (local) variables to an Fl_Group, then it is your responsibility to remove (or delete) all such static or automatic child widgets before destroying the group - otherwise the group will attempt to call delete operator on them leading to undefined behavior! "

https://www.fltk.org/doc-1.4/classFl__Group.html#a9a71aac1ca586825ff0c790f8f99f9cf


The fault of the posted demo program was that it `add()`ed static (global) child widgets to the group w/o removing them before the group was destroyed.

I assume the "issue" here is that the stack-automatically created window goes out of scope when main() terminates, and is then reaped (deleted) and tries to clean up it's children - but in this case the children are static objects so don't want to be deleted at this point...
And I have noticed several examples in the tutorial by Georg Potthast where exactly this is how this is done.
In several variations like the one documented in the previous message.

But also variations where there is a static `Fl_Window win' instance and where parts are added which are local to a function context (and on the stack). When leaving the function then all instances that are in its local scope disapear and `win' will have dead pointer.

No, this is not true. A widget that is `delete`d (goes out of scope) removes itself from its parent group by means of its destructor. No stale pointers in the parent group in this case (but the window doesn't contain the widgets which were intended to be in the window or group).


There is more than one way to violate this principle. The underlaying problem, IMHO, is the use of raw (and naked) pointers, `new' and `delete'.

The concept of FLTK was inherited by an even older C library (Forms or Xforms) and then modified in the 1990's. This principle is not going to be changed because it's not possible w/o breaking contracts.


Bad thing (for the Tutorial) is that most of the effects happens when the example is closing down and you will not notice it.

But that is the problem of the tutorial, isn't it? Not FLTK's fault.

Nowadays it's possible to use lots of helping techniques like Valgrind or Address Sanitizer (ASAN) to test one's code. I'm using ASAN regularly to check the test and demo programs, and if I wrote and published a tutorial I would thoroughly test all my demo programs with one of these tools.


But when applying the same techniques in a library then it becomes a different thing in total. (Example works, why is my code throwing a null reference exception?)

Every library has its rules, and some may be hard to understand. I didn't create FLTK and its API, but most of the issues can be avoided easily, for instance by allocating all children of a window or group with `new`.

IMHO the text "it is allowed that ..." in the docs means that this is considered an exception to the rule, although it is possible. In other parts of the docs (or in code comments) this is called a "kludge" [1]. We could probably be more explicit about this and the recommended ways to create hierarchies of widgets.

Documentation of Fl_Scroll::Fl_Scroll():
[1] 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_Scroll and all of its children can be automatic (local) variables, but you must declare the Fl_Scroll first, so that it is destroyed last.
https://www.fltk.org/doc-1.4/classFl__Scroll.html#a5260c8bbc420a09ff59a36ecf0489409

Reply all
Reply to author
Forward
0 new messages