Segfault when calling QWidget::show (on Debian 9)
-
I have a Qt 4.8.7 program that is built on Debian 9. We compile Qt from source. The program segfaults only in a release build.
Debug build runs fine. After some debugging, I was able to figure out that the crash happens at the statementmpMainWindow->show();
where
mpMainWindow
is a pointer to a class that hasQMainWindow
as its base class. Using gdb, I was able to get a call stack at the moment of the crash (using the release build). It looks as follows:user@debianvbox:~/SVN/PolarisRel/Apps$ gdb ./MyApplication ... cutting away some gdb intro output ... Reading symbols from ./MyApplication...(no debugging symbols found)...done. (gdb) r Starting program: /home/user/SVN/PolarisRel/Apps/MyApplication [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". ... cutting away some program output ... Program received signal SIGSEGV, Segmentation fault. strlen () at ../sysdeps/x86_64/strlen.S:106 106 ../sysdeps/x86_64/strlen.S: No such file or directory. (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 0x000055555594a3ef in MyApplication::mfRun(int, char**, QString&) () #7 0x0000555555c01d0a in ICService::mfExec(int, char**, QString&, bool) () #8 0x0000555555bfe53e in ICService::mfParseArguments(int, char**, bool) () #9 0x000055555594e617 in MyApplication::mfParseArguments(int, char**) () #10 0x000055555592a43e in main () (gdb)
I'm a bit puzzled why I don't see the
show()
function in the call stack, as to me that seems the place where the crash occurs.Also interesting to know is that this same application does not crash in release mode when I build it on Red Hat Enterprise Linux 8.
Any thoughts on how I can debug this further or what could be the problem? If
ldd
orstrace
output is required, please let me know. -
@Bart_Vandewoestyne said in Segfault when calling QWidget::show (on Debian 9):
I'm a bit puzzled why I don't see the
show()
function in the call stack, as to me that seems the place where the crash occurs.In the meanwhile, I have figured out why that is: in the Qt 4.8.7 source in
include\QtGui\qwidget.h
we have#ifndef Q_WS_WINCE inline void show() { setVisible(true); } #else void show(); #endif
and since on my Debian 9
Q_WS_WINCE
is not defined,show()
is immediately inlined withsetVisible(true)
. -
@Bart_Vandewoestyne said in Segfault when calling QWidget::show (on Debian 9):
mpMainWindow
I would guess this is either a nullptr or not initialized. Build your app with debug information, go to stack frame 7 and print out the value of mpMainWindow .
-
@Christian-Ehrlicher said in Segfault when calling QWidget::show (on Debian 9):
I would guess this is either a nullptr or not initialized. Build your app with debug information, go to stack frame 7 and print out the value of mpMainWindow .
I can confirm that
mpMainWindow
is notnullptr
: I've added an if-test for that and I print something tostdout
if it is null. Nothing is printed, so it's definitely not null (not saying the pointer value is OK though...)Next to that, it seems that our problem is very similar to the one described at https://www.mathiaswestin.net/2014/05/solved-qt-segmentation-fault-on.html.
-
@Bart_Vandewoestyne said in Segfault when calling QWidget::show (on Debian 9):
Nothing is printed,
Then you did something wrong. Also checking an invalid pointer for != nullptr will most likley evaluate to true. Please show us your code.
-
@Bart_Vandewoestyne said in Segfault when calling QWidget::show (on Debian 9):
Next to that, it seems that our problem is very similar to the one described at https://www.mathiaswestin.net/2014/05/solved-qt-segmentation-fault-on.html.
That's a very odd one! And unfortunately where it refers to http://www.qtcentre.org/archive/index.php/t-45135.html?s=ea17a4ab05c00533d49f938c1da47077, that post has gone bye-byes, so I can't look up what was claimed to be the exact issue....
This issue about
char **argv
vschar *argv[]
(https://www.mathiaswestin.net/2014/05/solved-qt-segmentation-fault-on.html) can (should) only be an issue if you actually do something withargv
. Temporarily at least can you not use it (presumably you only pass it toQApplication
? And then I don't see why its declaration in yourmain()
should matter.... Or do you do something else with it?), to see whether that fixes?P.S.
I see that post says the stack trace is6 QWidget::show qwidget.h 494 0x804fd0c 7 mgccis::shell::MainApplication::InitializeInterface mainapplication.cpp 29 0x804facc 8 main main.cpp 25 0x804efb0
What was that
mgccis::shell::MainApplication::InitializeInterface
?Meanwhile I see now you go
MyApplication::mfParseArguments(int, char**) ()
, etc. It ends up calling yourMyApplication::mfRun(int, char**, QString&) ()
. What does that do withargv
? -
@JonB
char **argv
andchar *argv[]
is actually the same - the problem in this post was that Q(Core)Application needsint &
- but this should not matter here since it's only a problem when you not instantiate Q(Core)Application in main(). -
@Christian-Ehrlicher said in Segfault when calling QWidget::show (on Debian 9):
char **argv and char *argv[] is actually the same
I know and I agree! That's why I said it "That's a very odd one!", and I didn't see why that declaration mattered. More to the point I wanted to read what the original "solution" post had said about this, but it's gone into the blue yonder.....
Let's wait and see whether the OP here finds this really has something to do with the problem now....
-
@JonB said in Segfault when calling QWidget::show (on Debian 9):
Meanwhile I see now you go
MyApplication::mfParseArguments(int, char**) ()
, etc. It ends up calling yourMyApplication::mfRun(int, char**, QString&) ()
. What does that do withargv
?Well, actually, in
MyApplication::mfParseArguments(int argc, char** argv)
theargv
frommain
is taken and a copy of it is created. This copy has one extra-e
argument and is thus one element longer. Something in essence like this (original code slightly modified):char** newArgvs; newArgvs = new char*[argc+1]; for(i = 0; i < argc + 1; i++) { newArgvs[i] = new char[256]; } strcpy(newArgvs[0], argv[0]); strcpy(newArgvs[1], "-e"); for(i = 1; i < argc; i++) { strcpy(newArgvs[i+1], argv[i]); } argc++;
and then at the end of
MyApplication::mfParseArguments
thatnewArgvs
is passed toICService::mfParseArguments
:return ICService::mfParseArguments(argc, newArgvs, false);
which in its turn then passes this info through to
ICService::mfExec
and that one then passes it toMyApplication::mfRun
which callsQWidget::show
that segfaults. -
The question is - where do you pass it to your Q(Core)Application.
-
@Christian-Ehrlicher said in Segfault when calling QWidget::show (on Debian 9):
The question is - where do you pass it to your Q(Core)Application.
That is indeed a good question... it is currently not yet clear to me where the single instance of the
QApplication
class is created. I'll have to spend some more time with the code to figure that out, and report back once I know more.In the meanwhile: is it crucial that
argc
andargv
are passed to that singleQApplication
instance, and could that be the reason for a segfault when callingQWidget::show()
? -
@Bart_Vandewoestyne said in Segfault when calling QWidget::show (on Debian 9):
@Christian-Ehrlicher said in Segfault when calling QWidget::show (on Debian 9):
The question is - where do you pass it to your Q(Core)Application.
That is indeed a good question... it is currently not yet clear to me where the single instance of the
QApplication
class is created. I'll have to spend some more time with the code to figure that out, and report back once I know more.OK. For as far as I can see it now, the call to
QApplication(argc, argv)
happens inICService::mfExec
before the call toMyApplication::mfRun
and is with the newargc
andargv
, where the newargc
is one more than the oldargc
(passed tomain
), and the newargv
has one element (-e
) more than the oldargv
(that was passed tomain
).Is it troublesome if in a call to
QApplication(newArgc, newArgv)
we have thatnewArgc != argc
andnewArgv
is not the same asargv
, whereargc
andargv
were the arguments passed tomain
? -
@Bart_Vandewoestyne said in Segfault when calling QWidget::show (on Debian 9):
for(i = 1; i < argc; i++)
{
strcpy(newArgvs[i+1], argv[i]);
}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-pointerThe Standard (C99 5.1.2.2.1p2) mandates that:
If they are declared, the parameters to the main function shall obey the following constraints:
— The value of argc shall be nonnegative.
— argv[argc] shall be a null pointer.
Note the last point. I doubt it's that, but worth a try on your new copy?
-
@Bart_Vandewoestyne said in Segfault when calling QWidget::show (on Debian 9):
strcpy(newArgvs[0], argv[0]);
This could easily overflow. What's the result of
strlen(argv[0])
? -
Christian Ehrlicher Lifetime Qt Championreplied to Bart_Vandewoestyne on last edited by Christian Ehrlicher
@Bart_Vandewoestyne said in Segfault when calling QWidget::show (on Debian 9):
the call to QApplication(argc, argv) happens in ICService::mfExec
Some code would be good...
You already posted a link with the solution but ignored it constantly - Q(Core)Application takes a reference to anint
so the callers should pass this to. Otherwise there might be a dangling reference. But without code...wrt to your strange copy stuff (whyever you need to modify your command line - sounds like a strange hack for me):
std::vector<char*> newArgs; newArgs.push_back(argv[0]); newArgs.push_back(const_cast<char*>("-e")); for (int i = 1; i < argc; ++i) newArgs.push_back(argv[i]); argc += 1; ...mfParseArguments(argc, newArgs.data());
-
@kshegunov said in Segfault when calling QWidget::show (on Debian 9):
This could easily overflow. What's the result of
strlen(argv[0])
?I've added
std::cout << "strlen(argv[0]) = " << strlen(argv[0]) << std::endl;
right before the
strcpy
statement and the result is 14. Knowing thatnewArgvs[0]
was allocated withnew char[256]
I would assume this is not causing trouble. -
@Christian-Ehrlicher said in Segfault when calling QWidget::show (on Debian 9):
Some code would be good...
Sorry for not posting code here, @Christian-Ehrlicher, but my question is related to code I work on professionally and for as far as I know I am not allowed to share any code.
-
@Bart_Vandewoestyne said in Segfault when calling QWidget::show (on Debian 9):
allowed to share any code.
Then good luck. We can't guess your code...
Apart from this you already shared code.
-
@Christian-Ehrlicher said in Segfault when calling QWidget::show (on Debian 9):
I would guess this is either a nullptr or not initialized. Build your app with debug information, go to stack frame 7 and print out the value of mpMainWindow .
I've added the
-g
option to our release build and when I run the application in gdb it now segfaults with the following call stack:user@debianvbox:~/SVN/PolarisRel/Apps$ gdb ./PolarisSlave GNU gdb (Debian 7.12-6) 7.12.0.20161007-git Copyright (C) 2016 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from ./PolarisSlave...done. (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". Program received signal SIGSEGV, Segmentation fault. strlen () at ../sysdeps/x86_64/strlen.S:106 106 ../sysdeps/x86_64/strlen.S: No such file or directory. (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 (gdb) f 7 #7 BSPPolarisSlave::mfRun (this=0x7fffffffe0e0, argc=<optimized out>, argv=<optimized out>, errormsg=...) at BSPPolarisSlave.cpp:443 443 mpMainWindow->show(); (gdb) p mpMainWindow $1 = (BSPPolarisSlaveMainWindow *) 0x555556627c40
Some things I noticed are:
mpMainWindow
is notnullptr
.- In the call to
BSPPolarisSlave::mfRun
argc
andargv
are marked as 'optimized out'... and similarly, in the call toQWidget::show
, thethis
parameter is also 'optimized out'. I have not much experience with gdb (most of the time, I debug in the Visual Studio debugger)... but could this 'optimizing out' be the problem?
-
@Bart_Vandewoestyne said in Segfault when calling QWidget::show (on Debian 9):
mpMainWindow is not nullptr
are you sure it is initialised then ? gdb, in contrast to its MSVC equivalent, does no null initialisations during debug runs. So an uninitialised pointer is very rarely a nullptr