Menu

#88 Threading error with QT5

SNAP_3.0
open
nobody
rev_3.4 (1)
1
2016-01-20
2016-01-14
Gert Wollny
No

Tests fail randomly because apparently timers are stopped from the wrong thread.

The result is probably a race condition that sometimes results in a segfault.

One backtrace looks like this:

Program received signal SIGSEGV, Segmentation fault.
0x00007fffe6e4a204 in g_main_context_check (context=context@entry=0x7fffd8002450, max_priority=2147483647, fds=fds@entry=0x3097b70, n_fds=n_fds@entry=3)
at /usr/src/debug/dev-libs/glib-2.44.1-r1/glib-2.44.1/glib/gmain.c:3641
3641              check = source->source_funcs->check;
(gdb) bt 
#0  0x00007fffe6e4a204 in g_main_context_check (context=context@entry=0x7fffd8002450, max_priority=2147483647, fds=fds@entry=0x3097b70, n_fds=n_fds@entry=3)
at /usr/src/debug/dev-libs/glib-2.44.1-r1/glib-2.44.1/glib/gmain.c:3641
#1  0x00007fffe6e4a7a0 in g_main_context_iterate (context=context@entry=0x7fffd8002450, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>)
at /usr/src/debug/dev-libs/glib-2.44.1-r1/glib-2.44.1/glib/gmain.c:3805
#2  0x00007fffe6e4a90c in g_main_context_iteration (context=0x7fffd8002450, may_block=may_block@entry=1) at /usr/src/debug/dev-libs/glib-2.44.1-r1/glib-2.44.1/glib/gmain.c:3869
#3  0x00007ffff3cb1797 in QEventDispatcherGlib::processEvents (this=0x1ae4130, flags=...) at kernel/qeventdispatcher_glib.cpp:418
#4  0x00007ffff3c64dba in QEventLoop::exec (this=this@entry=0x7fffffffcd50, flags=..., flags@entry=...) at kernel/qeventloop.cpp:204
#5  0x00007ffff3c6b7cc in QCoreApplication::exec () at kernel/qcoreapplication.cpp:1188
#6  0x00007ffff44ba2ac in QGuiApplication::exec () at kernel/qguiapplication.cpp:1507
#7  0x00007ffff49ccd95 in QApplication::exec () at kernel/qapplication.cpp:2956
#8  0x00000000007dec82 in main (argc=7, argv=<optimized out>) at /home/gerddie/src/External/itk-snap/GUI/Qt/main.cxx:794

The problem is that "source->source_funcs" points to unaccessablöe memoy.

See also the attached test log.

Best,
Gert

1 Attachments

Discussion

  • Gert Wollny

    Gert Wollny - 2016-01-14

    The program itself seems to run fine though (Needed to specify the compile flag -fPIC though).

     
  • Gert Wollny

    Gert Wollny - 2016-01-19

    I found the source of the problem:

    in GUI/QT/main.cxx you call

    testingEngine->LaunchTest(argdata.xTestId);
    

    which, I assume, starts a new thread. Then, in Testing/GUI/Qt/SNAPTestQt.cxx you call

    
    

    from within this newly created thread from various locations This results in QT starting to clean up, but since the main thread is still running, it doesn't expect this and will randomly segfault because it sometimes wants to access memory that was already released from the test thread. For this reason the program itself works fine, only the tests fail randomly.

    The proper solution is to not call ::exit, but to let the main thread react to the finished signal that this thread will send after the test is finished. The test status should then be stored in a SNAPTestQt member variable so that it can be retrived later.

    I guess, with QT4 the thread handling was somewhat different, so that calling ::exit from one thread did not result in this king of race condition.

    I'm not very familiar with QT and the inner workings of itksnap, therefore I can not propose a patch that takes care of this problem, but I think with this description you should be able to correct the problem easily.

     
  • Gert Wollny

    Gert Wollny - 2016-01-20

    I did a bit more digging, and it seems it wouldn't be too difficult to send a signal to the main thread, i.e. the connect method can take care of thread affinity and relay signals correctly. However. in your test scripts you usually end up with a modal dialog open, and hence the main window event loop is blocked and can not react to the signal.

    On top of that, e.g. in the Workspace test this dialog is the SaveModified... dialog running as a modal dialog, and since you handle the buttons via a slot that uses the actual stock button ID, it is not straightforward to send the Discard button press to close that dialog without having it re-open when trying to exit the app.

    For that reason you might want to consider rewriting the handling of the SaveModified related stuff, to call the QDialog::exec() method, and then base the actual action on its return value. This way you could call dialog.done(code) in the test script, and with the code that corresponds to Discard, and after this even close the main window from the test script.

    Well, I guess I'll leave it to you from here, because I actually don't know why you handle the SaveModified..Dialog like you do, and I don't want to interfere with your coding paradim :)

    Best,
    Gert

     

Log in to post a comment.