ofAppNoWindow outside of int main(...) leads to segfaults

Hello!
I’d like to move the code around ofSetupOpenGL() from the main function into an addon (that parses cmdline arguments, config files first, to get the desired window resolution or to start in headless mode).

This works fine in fullscreen or windowed mode, but even the following code (a slightly modified version of the ofAppNoWindow example) segfaults in of 0.11.2 on amd64 (debian/linux 6.1.8-1):

#include "ofMain.h" #include "ofApp.h" #include "ofAppNoWindow.h"

void f(){
ofAppNoWindow window;
ofSetupOpenGL(&window, 1024, 768, OF_WINDOW);
}

int main() {
// ofAppNoWindow window;
// ofSetupOpenGL(&window, 1024, 768, OF_WINDOW);
f();
ofRunApp(new ofApp());
}

This might be not even related to openframeworks, but maybe someone could explain why the position of these two lines of code matter?!

Thanks you in advance!

hello!

the short, mechanical answer is scope: by the time you call ofRunApp(), the ofAppNoWindow window does not exist anymore (it exists only within the scope of your f() function).

this lead to a more subtle question: why does that matter? because of hidden “side-effects” within ofSetupOpenGL(): in there, a pointer is constructed out of the address &window. Then, ofRunApp() “wirelessly” expect that invisible-to-you pointer to point to an actual window (but by then it’s gone). This sort of “wireless” behaviour is a sign of fragile design (as you just revealed) as you are implicitly expected to maintain the lifetime of your window beyond where you can “see” it used.

detecting bad pointers is hard for the system, but at the segfault, your debugger should have oriented you in the vicinity of line 73 of ofMainLoop.cpp:

ofAddListener(window->events().setup,app.get(),&ofBaseApp::setup,OF_EVENT_ORDER_APP);

it may not spell out “you are referencing a window that does not exist” (it’s hard to deduce), but it’s telling you something in there is the cause of the crash (in your case, ->events() does not exist because window is invalid).

all that being said you must additionally wonder: “but I’m not interested in the window, I’m using ofAppNoWindow!” heh you should certainly not need a window! but considering the origins and use of OF, the window is pretty deeply ingrained, and the noWindow is still a window.

note that there is another pattern of bootstrapping OF that looks like this (it should be what a fresh ProjectGenerated project provides):

#include "ofMain.h"
#include "ofApp.h"

int main( ) {
  ofGLWindowSettings settings;
  settings.setSize(1024, 768);
  settings.windowMode = OF_WINDOW; //can also be OF_FULLSCREEN
  auto window = ofCreateWindow(settings);
  ofRunApp(window, make_shared<ofApp>());
  ofRunMainLoop();
}

here the relationship is made apparent, as the window is explicitly passed to ofRunApp. better design, as you would not have been tempted to separate the auto window line from the ofRunApp() one. (and incidentally it’s making use of ofGLWindowSettings which provides more flexibility than the direct interface to ofSetupOpenGL()).

2 Likes

Hello Burton!

Reading your comprehensive and highly instructive answer, the problem is embarrassingly obvious.
Applying the newly acquired knowledge, I can easily rewrite my code to solve any issues regarding bootstrapping OF.
I really prefer your alternative pattern that “visibly” passes the window to ofRunApp().

As OF surely was never designed to run in headless mode, the provided “ofAppNoWindow” class seems to be a legitimate solution to address usecases that do not require any visible window.
No problem with that design decision!

I am very grateful to you for explaining factually basic C/C++ topics, that inspired me to read about shared/smart pointers and spending some time with gdb and interpreting its output.
Again, thank you very much for your time and afford solving my silly problem in that unexpected great way! (apologize for my bad english)