PDA

View Full Version : Memory corruption related to signal emission?



blooglet
28th December 2011, 17:04
I suspect I'm dealing with memory corruption somewhere in my program. I'm getting a SIGSEGV on a call to a function from a trusted third-party library. With some trial and error I've discovered that this segfault happens when the lines


emit newStreamFound(_streams[streamOneSSRC]);
emit newStreamFound(_streams[streamTwoSSRC]);

are not commented. This happens even when no slots are connected to this signal. As far as I know there are no thread safety issues. I ran a Valgrind memory analysis with these lines disabled and this is what came up:

http://i.imgur.com/c02qm.png

I can't make heads or tails of this output. The test condition in the do while loop depends on one variable that is, in fact, initialized at the top of the function. Does any of this point to issues that should be investigated? If not, what are the next steps I can take?

amleto
28th December 2011, 22:46
right, so have you debugged the values of streamOneSSRC, and the array value at that index?

blooglet
29th December 2011, 09:34
I should probably mention that _streams is a QMap. streamOneSSRC and streamTwoSSRC are uint32_t with values similar to 738621152 and 3435571404. I've asserted that


assert(_streams.find(streamOneSSRC) != _streams.end());
assert(_streams.find(streamTwoSSRC) != _streams.end());

right before the signal emission happens.

stampede
29th December 2011, 10:42
Why do you think this is related to signal emission, and not to accessing the QMap ?
Does it crash if you just print the values ?


// emit newStreamFound(_streams[streamOneSSRC]);
// emit newStreamFound(_streams[streamTwoSSRC]);
qDebug() << _streams[streamOneSSRC];
qDebug() << _streams[streamTwoSSRC];

blooglet
29th December 2011, 11:39
Nope, that seems to work just fine.


VideoStream(0x7fffe4110e20)
VideoStream(0x7fffe4110e90)

But then again if I'm dealing with a memory corruption bug this behavior could be undefined.

amleto
29th December 2011, 12:29
how are you pasing the data through the signaal/slot? const ref?

blooglet
29th December 2011, 13:15
By pointer.


void newStreamFound(VideoStream*);

_streams is a QMap<uint32_t, VideoStream*>.

amleto
29th December 2011, 18:34
you've got a problem somewhere else then. emitting a signal with a pointer as an argument, and with no slots connected, does not cause a seg fault.

blooglet
29th December 2011, 18:53
Right... so it's likely to be memory corruption like I thought then? Can you conclude anything from the Valgrind memory analysis about where the error might be?

amleto
29th December 2011, 21:10
seg fault is always doing something dodgy to memory isnt it?

valgrind doesnt play too nicely with qt from what little I have read about it so not sure you can conclude much from it.

stampede
29th December 2011, 21:43
Build debug version, launch with debugger and examine (post here) backtrace after crash.

blooglet
30th December 2011, 08:55
I got this from gdb.


Program received signal SIGSEGV, Segmentation fault.
0x00007ffff711000c in ?? () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
(gdb) backtrace
#0 0x00007ffff711000c in ?? () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#1 0x00007ffff711101a in QPainter::QPainter(QPaintDevice*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#2 0x00007ffff73fdb3d in QFrame::paintEvent(QPaintEvent*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#3 0x00007ffff701325b in QWidget::event(QEvent*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#4 0x00007ffff73fd7cb in QFrame::event(QEvent*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#5 0x00007ffff6fb2faf in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#6 0x00007ffff6fb9c8b in QApplication::notify(QObject*, QEvent*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#7 0x00007ffff6a62dc4 in QCoreApplication::notifyInternal(QObject*, QEvent*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtCore.so.4
#8 0x00007ffff700d202 in QWidgetPrivate::drawWidget(QPaintDevice*, QRegion const&, QPoint const&, int, QPainter*, QWidgetBackingStore*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#9 0x00007ffff700dd32 in QWidgetPrivate::paintSiblingsRecursive(QPaintDevic e*, QList<QObject*> const&, int, QRegion const&, QPoint const&, int, QPainter*, QWidgetBackingStore*) ()
from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#10 0x00007ffff700cf7f in QWidgetPrivate::drawWidget(QPaintDevice*, QRegion const&, QPoint const&, int, QPainter*, QWidgetBackingStore*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#11 0x00007ffff71ebf6a in ?? () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#12 0x00007ffff7004086 in QWidgetPrivate::syncBackingStore() () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#13 0x00007ffff7013911 in QWidget::event(QEvent*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#14 0x00007ffff741a4e1 in QMainWindow::event(QEvent*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#15 0x00007ffff6fb2faf in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#16 0x00007ffff6fb9c8b in QApplication::notify(QObject*, QEvent*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#17 0x00007ffff6a62dc4 in QCoreApplication::notifyInternal(QObject*, QEvent*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtCore.so.4
#18 0x00007ffff6a63ef1 in QCoreApplicationPrivate::sendPostedEvents(QObject* , int, QThreadData*) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtCore.so.4
#19 0x00007ffff6a90703 in ?? () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtCore.so.4
#20 0x00007ffff553da5d in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#21 0x00007ffff553e258 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#22 0x00007ffff553e429 in g_main_context_iteration () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#23 0x00007ffff6a90a1c in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtCore.so.4
#24 0x00007ffff7065c0f in ?? () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtGui.so.4
#25 0x00007ffff6a62115 in QEventLoop::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtCore.so.4
#26 0x00007ffff6a62366 in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtCore.so.4
#27 0x00007ffff6a641a4 in QCoreApplication::exec() () from /opt/QtSDK/Desktop/Qt/474/gcc/lib/libQtCore.so.4
#28 0x000000000040781f in launchGUI (ip=0x7fffffffe3c6 "127.0.0.1", port=12000) at ../VideoStreamer/main.cpp:36
#29 0x0000000000407795 in main (argc=3, argv=0x7fffffffe068) at ../VideoStreamer/main.cpp:27

stampede
30th December 2011, 09:21
Can you post the code for launchGUI (or maybe whole main.cpp) ?

blooglet
30th December 2011, 09:32
#include "main.h"

#include "view/videoplayerwindow.h"
#include <iostream>
#include <cerrno>
#include <QtGui/QApplication>
using std::cerr;
using std::endl;

int main(int argc, char *argv[])
{
_argc = argc;
_argv = argv;

if (argc < 3) {
cerr << "USAGE: " << argv[0] << " 127.0.0.1 12345" << endl;
exit(EXIT_FAILURE);
}

// Try to convert the port input into a number
uint16_t port = strtoul(argv[2], NULL, 10);
if (errno != 0 || port < 1) {
cerr << "Invalid port number. Quitting." << endl;
exit(EXIT_FAILURE);
}

return launchGUI(argv[1], port);
}

int launchGUI(char *ip, uint16_t port) {
try {
QApplication a(_argc, _argv);
VideoPlayerWindow w(ip, port);
w.show();

return a.exec();
} catch (VideoStreamerCriticalException& ve) {
cerr << "A critical error occured with the video stream.\n -- " << ve << "\n\nThis program will now quit." << endl;
return 0;
}
}

where int _argc and char** _argv are defined in main.h.

stampede
30th December 2011, 09:41
Ok. Now it could be good to see VideoPlayerWindow implementation (constructor, all methods called from constructor, and paintEvent implementation if there is one).

blooglet
30th December 2011, 10:17
Nothing fancy to see here.


VideoPlayerWindow::VideoPlayerWindow(char *ip, uint16_t port, QWidget *parent) :
QMainWindow(parent),
_vss(ip, port)
{
setupGUI();

_vss.startReceiver();
}

void VideoPlayerWindow::setupGUI() {
// QMainWindow takes ownership of the widget, so no need
// to delete it.
_vpWidget = new VideoPlayerWidget(this);
setCentralWidget(_vpWidget);

connect(&_vss, SIGNAL(newStreamFound(VideoStream*)), _vpWidget, SLOT(addVideoStream(VideoStream*)));
}

with member variables


VideoPlayerWidget* _vpWidget;
VideoStreamerSession _vss;

VideoStreamerSession::startReceiver() starts an asynchronous receiver thread that processes incoming data related to streaming video.

I'd rather not post the entire program online, but if you need any more code I'll upload the project to temporary storage.

stampede
30th December 2011, 10:22
I'd rather not post the entire program online
I understand.
Does it crash if you do not startReceiver() ? You said that there are threads involved - to me its always first place to look for potential errors.
//edit: ok, probably there you have the "emit" statements. You may try to implement single-threaded version of the receiver, my bet is that threads are somehow responsible for the app crash.

blooglet
30th December 2011, 10:28
It does not crash if I don't call startReceiver(). But like I said here (http://www.qtcentre.org/threads/46587-Memory-corruption-related-to-signal-emission?p=210483#post210483): if I remove these two signal emission commands (they're executed on the receiver thread, by the way) and still call startReceiver(), the program doesn't crash either. Even when no slots are connected to these signals, the mere emission of these signals causes a SIGSEGV somewhere else in the program. This leads me to believe it's not a thread safety issue but a memory corruption issue. I build with Qt 4.7.4, but any time I suspect an error is my code is caused by a Qt-related bug it turns out I'm wrong.

stampede
30th December 2011, 10:57
I think its not possible to help you more without digging through the sources.
Its all up to your creative thinking now. You may try to create separate application, where you can test the VideoStream and VideoStreamerSession classes, without the gui layer. Or try to implement single-threaded version of receiver. Or try to allocate the _vss on heap (if you are out of ideas, why not try this).
Sorry, but without seeing the code, I can't help you more.

blooglet
30th December 2011, 13:47
Holy smokes... I just did some more digging and I found the culprit. I looked through all the "// TODO" comments in my code and then I remembered I had an odd issue with a signal/slot connection on a QTimer* that produced a warning in the debug output. The timer just wouldn't fire. I commented out the connect() command because I had more important things to do. When I came back to this snippet of code, I noticed that I hadn't initialized the QTimer*... I feel like crap for wasting your and my own time. Too bad Valgrind didn't detect this, because then the error would have been exposed much earlier.

Thanks for your help, though! :)

amleto
30th December 2011, 17:28
that uninited pointer isnt around or as a consequence of launchGui, is it? your valgrind output says ''uninit'd value was created by a stack allocation'' main.cpp:30

blooglet
30th December 2011, 19:11
I've posted main.cpp here (http://www.qtcentre.org/threads/46587-Memory-corruption-related-to-signal-emission?p=210585#post210585). I have no idea what Valgrind is referring to. Probably char* ip but since argv[1] isn't deallocated until the program stops I don't see a problem here.