Solved Segfault when calling QWidget::show (on Debian 9)
-
@J-Hilk or run it with valgrind (compile with -O2 and -g)
-
@Christian-Ehrlicher never used valgrind before, as I usually don't do linux stuff. But I trust your expertise :D
oh it also now supports macOS, maybe I should give it a try sometime soon than!
-
@J-Hilk said in Segfault when calling QWidget::show (on Debian 9):
@Bart_Vandewoestyne new debian, huh. New/updated compiler then as well?
Yes, due to the switch from Debian 8 to Debian 9, a new compiler as well. Debian 8 (where everything works) has
dev@debian8:~$ g++ --version | head -1 g++ (Debian 4.9.2-10+deb8u2) 4.9.2
while Debian 9 (where the release build segfaults) has
user@debianvbox:~$ g++ --version | head -1 g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
I assume you have tried the release build with
-O0
?I hadn't, but now I have ;-) And I have interesting news: when using
-O0
the segfault is gone! From-O1
and further, we get the segfault. -
@Christian-Ehrlicher said in Segfault when calling QWidget::show (on Debian 9):
@J-Hilk or run it with valgrind (compile with -O2 and -g)
I have no experience with valgrind, but looks like a good suggestion so I will try and report back.
-
@Christian-Ehrlicher said in Segfault when calling QWidget::show (on Debian 9):
@J-Hilk or run it with valgrind (compile with -O2 and -g)
OK, so I compiled with
-O2
and-g
and ran my program through valgrind. This is what I got:user@debianvbox:~/SVN/PolarisRel/Apps$ valgrind ./PolarisSlave ==5165== Memcheck, a memory error detector ==5165== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==5165== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info ==5165== Command: ./PolarisSlave ==5165== ==5165== Invalid read of size 8 ==5165== at 0x8B3B205: XSetCommand (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0) ==5165== by 0x8B3F7EF: XSetWMProperties (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0) ==5165== by 0x5EE707C: QWidgetPrivate::create_sys(unsigned long, bool, bool) (in /home/user/SVN/PolarisRel/ThirdParty/Qt/qt-install/lib/libQtGui.so.4.8.7) ==5165== by 0x5E9F768: QWidget::create(unsigned long, bool, bool) (in /home/user/SVN/PolarisRel/ThirdParty/Qt/qt-install/lib/libQtGui.so.4.8.7) ==5165== by 0x5EA7696: QWidget::setVisible(bool) (in /home/user/SVN/PolarisRel/ThirdParty/Qt/qt-install/lib/libQtGui.so.4.8.7) ==5165== by 0x4FE1FC: show (qwidget.h:497) ==5165== by 0x4FE1FC: BSPPolarisSlave::mfRun(int, char**, QString&) (BSPPolarisSlave.cpp:443) ==5165== by 0x7B50D9: ICService::mfExec(int, char**, QString&, bool) (in /home/user/SVN/PolarisRel/Apps/PolarisSlave) ==5165== by 0x7B190D: ICService::mfParseArguments(int, char**, bool) (in /home/user/SVN/PolarisRel/Apps/PolarisSlave) ==5165== by 0x501BB2: BSPPolarisSlave::mfParseArguments(int, char**) (BSPPolarisSlave.cpp:659) ==5165== by 0x4DE3AC: main (BSPPolarisSlaveMain.cpp:71) ==5165== Address 0xbe71780 is 0 bytes after a block of size 16 alloc'd ==5165== at 0x4C2C93F: operator new[](unsigned long) (vg_replace_malloc.c:423) ==5165== by 0x501A27: BSPPolarisSlave::mfParseArguments(int, char**) (BSPPolarisSlave.cpp:637) ==5165== by 0x4DE3AC: main (BSPPolarisSlaveMain.cpp:71) ==5165== ==5165== Invalid read of size 1 ==5165== at 0x4C2EDA2: strlen (vg_replace_strmem.c:454) ==5165== by 0x8B3B1EC: XSetCommand (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0) ==5165== by 0x8B3F7EF: XSetWMProperties (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0) ==5165== by 0x5EE707C: QWidgetPrivate::create_sys(unsigned long, bool, bool) (in /home/user/SVN/PolarisRel/ThirdParty/Qt/qt-install/lib/libQtGui.so.4.8.7) ==5165== by 0x5E9F768: QWidget::create(unsigned long, bool, bool) (in /home/user/SVN/PolarisRel/ThirdParty/Qt/qt-install/lib/libQtGui.so.4.8.7) ==5165== by 0x5EA7696: QWidget::setVisible(bool) (in /home/user/SVN/PolarisRel/ThirdParty/Qt/qt-install/lib/libQtGui.so.4.8.7) ==5165== by 0x4FE1FC: show (qwidget.h:497) ==5165== by 0x4FE1FC: BSPPolarisSlave::mfRun(int, char**, QString&) (BSPPolarisSlave.cpp:443) ==5165== by 0x7B50D9: ICService::mfExec(int, char**, QString&, bool) (in /home/user/SVN/PolarisRel/Apps/PolarisSlave) ==5165== by 0x7B190D: ICService::mfParseArguments(int, char**, bool) (in /home/user/SVN/PolarisRel/Apps/PolarisSlave) ==5165== by 0x501BB2: BSPPolarisSlave::mfParseArguments(int, char**) (BSPPolarisSlave.cpp:659) ==5165== by 0x4DE3AC: main (BSPPolarisSlaveMain.cpp:71) ==5165== Address 0x50 is not stack'd, malloc'd or (recently) free'd ==5165== ==5165== ==5165== Process terminating with default action of signal 11 (SIGSEGV) ==5165== Access not within mapped region at address 0x50 ==5165== at 0x4C2EDA2: strlen (vg_replace_strmem.c:454) ==5165== by 0x8B3B1EC: XSetCommand (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0) ==5165== by 0x8B3F7EF: XSetWMProperties (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0) ==5165== by 0x5EE707C: QWidgetPrivate::create_sys(unsigned long, bool, bool) (in /home/user/SVN/PolarisRel/ThirdParty/Qt/qt-install/lib/libQtGui.so.4.8.7) ==5165== by 0x5E9F768: QWidget::create(unsigned long, bool, bool) (in /home/user/SVN/PolarisRel/ThirdParty/Qt/qt-install/lib/libQtGui.so.4.8.7) ==5165== by 0x5EA7696: QWidget::setVisible(bool) (in /home/user/SVN/PolarisRel/ThirdParty/Qt/qt-install/lib/libQtGui.so.4.8.7) ==5165== by 0x4FE1FC: show (qwidget.h:497) ==5165== by 0x4FE1FC: BSPPolarisSlave::mfRun(int, char**, QString&) (BSPPolarisSlave.cpp:443) ==5165== by 0x7B50D9: ICService::mfExec(int, char**, QString&, bool) (in /home/user/SVN/PolarisRel/Apps/PolarisSlave) ==5165== by 0x7B190D: ICService::mfParseArguments(int, char**, bool) (in /home/user/SVN/PolarisRel/Apps/PolarisSlave) ==5165== by 0x501BB2: BSPPolarisSlave::mfParseArguments(int, char**) (BSPPolarisSlave.cpp:659) ==5165== by 0x4DE3AC: main (BSPPolarisSlaveMain.cpp:71) ==5165== If you believe this happened as a result of a stack ==5165== overflow in your program's main thread (unlikely but ==5165== possible), you can try to increase the size of the ==5165== main thread stack using the --main-stacksize= flag. ==5165== The main thread stack size used in this run was 8388608. ==5165== ==5165== HEAP SUMMARY: ==5165== in use at exit: 1,121,308 bytes in 9,104 blocks ==5165== total heap usage: 22,310 allocs, 13,206 frees, 4,039,124 bytes allocated ==5165== ==5165== LEAK SUMMARY: ==5165== definitely lost: 2,944 bytes in 6 blocks ==5165== indirectly lost: 13,190 bytes in 537 blocks ==5165== possibly lost: 54,718 bytes in 437 blocks ==5165== still reachable: 1,050,456 bytes in 8,124 blocks ==5165== suppressed: 0 bytes in 0 blocks ==5165== Rerun with --leak-check=full to see details of leaked memory ==5165== ==5165== For counts of detected and suppressed errors, rerun with: -v ==5165== ERROR SUMMARY: 5 errors from 2 contexts (suppressed: 0 from 0) Segmentation fault
I'll try to decipher this myself, but if in the meanwhile someone more experienced with valgrind can point me in the right direction, that would be nice :-)
-
from my point of view, I would say the issue is with your strange string manipulation stuff.
You have to be very careful, when working with stringliterals, it is super easy to run into undefined behaviour, when you try to modify them.
-
@Bart_Vandewoestyne said in Segfault when calling QWidget::show (on Debian 9):
by 0x501A27: BSPPolarisSlave::mfParseArguments(int, char**) (BSPPolarisSlave.cpp:637)
This is where you have to take a look on. You do something wrong there for an argument.
-
Please provide the the line that @Christian-Ehrlicher mentioned; it's the call to
mfExec
. -
OK, I think we're getting there... In
ICBlackBoxBase::mfInitialize
we call theICBlackBoxBaseApplication
constructor which calls theQApplication
constructor with certainargc
andargv
arguments:ICBlackBoxBaseApplication::ICBlackBoxBaseApplication(int &argc, char** argv, ICBlackBoxBase* apApp) : QApplication(argc,argv), mpApp(apApp) { }
Now let's see what argc and argv we are passing there. I've set a breakpoint right before the location where we call this constructor, and this is the call stack:
(gdb) bt #0 ICBlackBoxBase::mfInitialize (this=0x7fffffffe0e0, argc=2, argv=0x5555565cd3d0, errormsg=...) at ICBlackBoxBase.cpp:101 #1 0x0000555555c0101d in ICService::mfExec(int, char**, QString&, bool) () #2 0x0000555555bfd86e in ICService::mfParseArguments(int, char**, bool) () #3 0x000055555594db13 in BSPPolarisSlave::mfParseArguments (this=0x7fffffffe0e0, argc=2, argv=0x7fffffffe258) at BSPPolarisSlave.cpp:654 #4 0x000055555592a3bd in main (argc=1, argv=0x7fffffffe258) at BSPPolarisSlaveMain.cpp:71
As you can see, in
main
we have thatargc
is 1, but inICBlackBoxBase::mfInitialize
(the function from which we call theICBlackBoxBaseApplication
constructor, and thus also theQApplication
constructor) we have thatargc
is 2 (since an extra-e
argument was added). Now let's look atargv
in bothmain
andICBlackBoxBase::mfInitialize
. Inmain
we have:(gdb) f 4 #4 0x000055555592a3bd in main (argc=1, argv=0x7fffffffe258) at BSPPolarisSlaveMain.cpp:71 71 return (polarisSlave.mfParseArguments(argc, argv)); (gdb) p argc $12 = 1 (gdb) p argv[0] $13 = 0x7fffffffe53a "/home/user/SVN/PolarisRel/Apps/PolarisSlave" (gdb) p argv[argc] $14 = 0x0
but in
ICBlackBoxBase::mfInitialize
we have:(gdb) f 0 #0 ICBlackBoxBase::mfInitialize (this=0x7fffffffe0e0, argc=2, argv=0x5555565cd3d0, errormsg=...) at ICBlackBoxBase.cpp:101 101 { (gdb) p argc $15 = 2 (gdb) p argv[0] $16 = 0x5555565cf830 "/home/user/SVN/PolarisRel/Apps/PolarisSlave" (gdb) p argv[1] $17 = 0x5555565cf940 "-e" (gdb) p argv[argc] $18 = 0x20 <error: Cannot access memory at address 0x20>
so there
argv[argc]
is not null! And now I have to find out why :-) -
@Bart_Vandewoestyne said in Segfault when calling QWidget::show (on Debian 9):
so there
argv[argc]
is not null! And now I have to find out why :-)Earlier I wrote:
I shall be surprised if it is this, but....
I think your code is not 100% technically correct. You do not
NULL
terminate your new vector. Technically you should find your originalargv
had an extra element at the end:argv[argc] == NULL
. You do not copy this orNULL
terminate your newnewArgvs
. E.g. https://stackoverflow.com/questions/16418932/is-argvargc-equal-to-null-pointer
— argv[argc] shall be a null pointer.It is not clear whether this matters or not. If code only uses
argc
to index up toargv[argc - 1]
then it does not. If code does do something about looking atargv[argc]
to check fornullptr
then it does matter. If you have the source code where it goes wrong you may be able to delermine. -
@Bart_Vandewoestyne said in Segfault when calling QWidget::show (on Debian 9):
ICBlackBoxBaseApplication::ICBlackBoxBaseApplication(int &argc, char** argv, ICBlackBoxBase* apApp) : QApplication(argc,argv), mpApp(apApp) { }
I have an alternative theory. Work with me on this one, please!
I believe the
BSPPolarisSlave
&ICService
classes are your own(?). ThisICBlackBoxBaseApplication
constructor callsQApplication(argc,argv)
withargc
, and especiallyargv
, *with the values they have on entry to the constructor. However (I believe you are saying) something it then does altersargc
, and especiallyargv
, to add further arguments, right? Note in your traceback howargv
has a different (pointer) value fromBSPPolarisSlave::mfParseArguments()
down toICBlackBoxBase::mfInitialize()
--- it has been changed.Now, I am unclear whether the original
argv
, with its strings, is being used from the originalQApplication(argc,argv)
, and just possibly the value/strings array is no longer valid. But it may be what is used the very first timeQWidget::show()
is called (to do some X initialisations from any (potential) X-type command-line arguments passed to your Qt app. Remember that https://doc.qt.io/qt-5/qcoreapplication.html#QCoreApplication saysWarning: The data referred to by argc and argv must stay valid for the entire lifetime of the QCoreApplication object. In addition, argc must be greater than zero and argv must contain at least one valid character string.
I think you should find that
QWidget::show()
which is inBSPPolarisSlave::mfRun()
. On the line above it do something about printing out Qt's idea of the command line arguments which were used during the earlierQApplication(argc,argv)
. I believe static QStringList QCoreApplication::arguments() accesses these. SoqDebug()
those beforeQWidget::show()
, do they look good or garbled?Finally, the question is why/what are these classes altering
argc
/argvfor, apparently to add additional arguments? If these new arguments are intended to be seen by Qt then it looks like you should not be calling
QApplication(argc,argv)` until after they have been modified to hold the new command line? -
I have also found the following text on https://doc.qt.io/archives/qt-4.8/qapplication.html#details
"Since the
QApplication
object does so much initialization, it must be created before any other objects related to the user interface are created.QApplication
also deals with common command line arguments. Hence, it is usually a good idea to create it before any interpretation or modification ofargv
is done in the application itself."It worries me... I don' think we actually modify
argv
(but we do modifyargc
)... but we do create anewArgv
that has one more command line argument and thatnewArgv
together with the modifiedargc
is what gets passed toQApplication
later on...So in summary, I think this is what we do:
- Start from
main
withargc
andargv
. - increment
argc
by one and createnewArgv
fromargv
(newArgv
has one extra-e
command line argument). - Call the
QApplication
constructor with the incrementedargc
andnewArgv
...
- Start from
-
@Bart_Vandewoestyne
I know this. I suggested what you need to do, to theQWidget::show()
inBSPPolarisSlave::mfRun()
.... -
@JonB said in Segfault when calling QWidget::show (on Debian 9):
@Bart_Vandewoestyne
I know this. I suggested what you need to do, to theQWidget::show()
inBSPPolarisSlave::mfRun()
....Yes, thanks for that suggestion. I'll look into it. I guess we were both typing our replies at the same time, but you were the first to press the 'Submit' button :-) Stay tuned for more! :-)
-
@Bart_Vandewoestyne
Hold on.First there is a logic fault in new code. Although it may not matter to your error right now, because you are still inside
ICService::mfParseArguments(argc, newArgs.data())
, yournewArgs
(local) variable does not respectThe data referred to by argc and argv must stay valid for the entire lifetime of the QCoreApplication object
At least try making
newArgs
static
.You still have not said "who" is supposed to "see" these extra arguments ---
QCoreApplication
or not?Also, who uses the
-e
you append, and are you sure what uses that does not expect a further argument to follow the-e
? [EDIT Oh, I see you insert the-e
, not append it.] -
@JonB said in Segfault when calling QWidget::show (on Debian 9):
I believe the
BSPPolarisSlave
&ICService
classes are your own(?).For the record: yes. I even think the
ICService
class is based on an older version ofQtService
from https://skycoder42.github.io/QtService/.This
ICBlackBoxBaseApplication
constructor callsQApplication(argc,argv)
withargc
, and especiallyargv
, *with the values they have on entry to the constructor. However (I believe you are saying) something it then does altersargc
, and especiallyargv
, to add further arguments, right?I think it's the other way around: we create a
newArgv
that has one extra-e
parameter and we also incrementargc
, and those are eventually passed toQApplication
.Note in your traceback how
argv
has a different (pointer) value fromBSPPolarisSlave::mfParseArguments()
down toICBlackBoxBase::mfInitialize()
--- it has been changed.OK. This indeed sounds not good... I will look into that.
[...]
I think you should find thatQWidget::show()
which is inBSPPolarisSlave::mfRun()
. On the line above it do something about printing out Qt's idea of the command line arguments which were used during the earlierQApplication(argc,argv)
. I believe static QStringList QCoreApplication::arguments() accesses these. SoqDebug()
those beforeQWidget::show()
, do they look good or garbled?I've changed
mpMainWindow->show();
into
QApplication::arguments(); mpMainWindow->show();
and when I run the program in gdb, it now no longer crashes at the call to
show()
, but rather at the call toQApplication::arguments()
, again pointing in the direction that clearly something is wrong with thisargc
,argv
andnewArgvs
code...Finally, the question is why/what are these classes altering
argc
/argvfor, apparently to add additional arguments? If these new arguments are intended to be seen by Qt then it looks like you should not be calling
QApplication(argc,argv)` until after they have been modified to hold the new command line?This is the code that does the modification:
//As PolarisSlave is derived from ICService we must start with -e argument to run //PolarisSlave as a regular program and not as a service. char** newArgvs; newArgvs = new char*[argc+1]; for(i = 0; i < argc + 1; i++) { newArgvs[i] = new char[256]; } strcpy(newArgvs[0], argv[0]); if (!showHelp) { strcpy(newArgvs[1], "-e"); for(i = 1; i < argc; i++) { strcpy(newArgvs[i+1], argv[i]); } argc++; } else { strcpy(newArgvs[1], "-h"); } return ICService::mfParseArguments(argc, newArgvs, false);
Note that we first do the
argc
/argv
/newArgvs
stuff, and then we call the functionreturn ICService::mfParseArguments(argc, newArgvs, false);
which passes these arguments on to other functions and eventually calls the
QApplication
constructor with these modified arguments.Also, reading the first comment, I would say that that
-e
argument is added because we don't want to start the program as a service (remember ourICService
class is probably based onQtService
, and using-e
seems to avoid that we run it as a service). -
@Bart_Vandewoestyne said in Segfault when calling QWidget::show (on Debian 9):
QApplication::arguments();
I said to try:
qDebug() << QApplication::arguments();
though of course it will crash.
Your code looks dodgy to me, at least in the
showHelp
case, which probably doesn't arise in your current example. I'm not going to type up the potential issues you might encounter, use a debugger if you want to step through. I don't know how that relates to the issue of theQApplication
arguments anyway. I don't know why you insert a-e
in this code when you previously showednewArgs.push_back(const_cast<char*>("-e"));
elsewhere.Basically I am finding it too difficult to follow your code, and I'm not sure if you are changing stuff. In any case this should be a debugging exercise now. I can see that the first
QWidget
call needsQApplication::arguments()
to be correct, and I think that is not, so follow how that goes from valid to inavlid through your sequence of calls/changes. -
@JonB said in Segfault when calling QWidget::show (on Debian 9):
I said to try:
qDebug() << QApplication::arguments();
I tried that, but I didn't get any output except for a segmentation fault. And that looked rather reasonable to me because I assume
QApplication::arguments()
gets called beforeoperator<<
, not? And ifQApplication::arguments()
segfaults, we won't see any further output... -
@JonB said in Segfault when calling QWidget::show (on Debian 9):
[...]
Basically I am finding it too difficult to follow your code, and I'm not sure if you are changing stuff. In any case this should be a debugging exercise now. I can see that the firstQWidget
call needsQApplication::arguments()
to be correct, and I think that is not, so follow how that goes from valid to inavlid through your sequence of calls/changes.No problem. Thanks to you (and the others in this thread) for your help! I now have a clearer idea of where the problem is. It looks like it has indeed something to do with that modification of
argc
andargv
. I'm used to debugging with the Visual Studio debugger, but this one has to be tackled in Linux, so I'll probably have to improve my gdb skills a bit... ;-) -
For those that are still following this thread: there is again a little bit of progress. Since the call stack at the moment of the crash was
(gdb) bt #0 strlen () at ../sysdeps/x86_64/strlen.S:106 #1 0x00007ffff3e101ed in XSetCommand () from /usr/lib/x86_64-linux-gnu/libX11.so.6 #2 0x00007ffff3e147f0 in XSetWMProperties () from /usr/lib/x86_64-linux-gnu/libX11.so.6 #3 0x00007ffff659007d in QWidgetPrivate::create_sys(unsigned long, bool, bool) () from /home/user/SVN/PolarisRel/ThirdParty/Qt/qt-install/lib/libQtGui.so.4 #4 0x00007ffff6548769 in QWidget::create(unsigned long, bool, bool) () from /home/user/SVN/PolarisRel/ThirdParty/Qt/qt-install/lib/libQtGui.so.4 #5 0x00007ffff6550697 in QWidget::setVisible(bool) () from /home/user/SVN/PolarisRel/ThirdParty/Qt/qt-install/lib/libQtGui.so.4 #6 0x000055555594a1fd in QWidget::show (this=<optimized out>) at ../../ThirdParty/Qt/qt-install/include/QtGui/qwidget.h:497 #7 BSPPolarisSlave::mfRun (this=0x7fffffffe0e0, argc=<optimized out>, argv=<optimized out>, errormsg=...) at BSPPolarisSlave.cpp:443 #8 0x0000555555c010da in ICService::mfExec(int, char**, QString&, bool) () #9 0x0000555555bfd90e in ICService::mfParseArguments(int, char**, bool) () #10 0x000055555594dbb3 in BSPPolarisSlave::mfParseArguments (this=0x7fffffffe0e0, argc=2, argv=0x7fffffffe258) at BSPPolarisSlave.cpp:659 #11 0x000055555592a3ad in main (argc=1, argv=0x7fffffffe258) at BSPPolarisSlaveMain.cpp:71
and @JonB pointed me to the implementation of
QWidgetPrivate::create_sys
insrc/gui/kernel/qwidget_x11.cpp
(Qt 4.8.7), I wanted to see what the values ofargc
andargv
were inside thatcreate_sys
function. Unfortunately, my Qt 4.8.7 build has no debug info, and I didn't find a way to create a Qt 4.8.7 build with debug info, so I added the following code right before the call toXSetWMProperties
:qDebug() << "Test by Bart"; qDebug() << "qApp->d_func()->argc == " << qApp->d_func()->argc; for (int i = 0; i < qApp->d_func()->argc; ++i) { qDebug() << "qApp->d_func()->argv[" << i << "] == " << qApp->d_func()->argv[i]; }
and the output from within gdb is
(gdb) r Starting program: /home/user/SVN/PolarisRel/Apps/PolarisSlave [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". Test by Bart qApp->d_func()->argc == 32767 qApp->d_func()->argv[ 0 ] == /home/user/SVN/PolarisRel/Apps/PolarisSlave qApp->d_func()->argv[ 1 ] == -e qApp->d_func()->argv[ 2 ] == Program received signal SIGSEGV, Segmentation fault. 0x00007ffff5bb5abb in QString::fromLatin1_helper(char const*, int) () from /home/user/SVN/PolarisRel/ThirdParty/Qt/qt-install/lib/libQtCore.so.4 (gdb)
so it looks like it's the value of argc (32767 !!!!!) that is screwed up for some reason. I will now try to figure out where that happens.