summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShane Kearns <shane.kearns@accenture.com>2011-04-20 15:21:36 (GMT)
committerShane Kearns <shane.kearns@accenture.com>2011-04-21 16:02:18 (GMT)
commit8a9a6afcf02f089f932bc81431ab46a60af32134 (patch)
tree68614078cc098182b41f5129c92c53bf13e94ecb
parent06c3a3a34ab908c517cfcb6900a79f68f1f31ae2 (diff)
downloadQt-8a9a6afcf02f089f932bc81431ab46a60af32134.zip
Qt-8a9a6afcf02f089f932bc81431ab46a60af32134.tar.gz
Qt-8a9a6afcf02f089f932bc81431ab46a60af32134.tar.bz2
Fix crash when QSocketNotifier used with an invalid descriptor
select code for open C file/socket descriptors was crashing in FD_SET if a QSocketNotifier was created with an invalid descriptor. Added two autotests to QSocketNotifier, one to check notifiers with bogus socket descriptors don't crash, the other to check that notifiers with posix socket descriptors do work. (symbian socket engine doesn't use them so they are not implicitly tested) Reviewed-by: mread Task-Number: QTBUG-18138
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian.cpp6
-rw-r--r--tests/auto/qsocketnotifier/qsocketnotifier.pro2
-rw-r--r--tests/auto/qsocketnotifier/tst_qsocketnotifier.cpp109
3 files changed, 116 insertions, 1 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp
index 79f2596..7166e7d 100644
--- a/src/corelib/kernel/qeventdispatcher_symbian.cpp
+++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp
@@ -1084,6 +1084,12 @@ bool QEventDispatcherSymbian::hasPendingEvents()
void QEventDispatcherSymbian::registerSocketNotifier ( QSocketNotifier * notifier )
{
+ //check socket descriptor is usable
+ if (notifier->socket() >= FD_SETSIZE || notifier->socket() < 0) {
+ //same warning message as the unix event dispatcher for easy testing
+ qWarning("QSocketNotifier: Internal error");
+ return;
+ }
//note - this is only for "open C" file descriptors
//for native sockets, an active object in the symbian socket engine handles this
QSocketActiveObject *socketAO = new QSocketActiveObject(this, notifier);
diff --git a/tests/auto/qsocketnotifier/qsocketnotifier.pro b/tests/auto/qsocketnotifier/qsocketnotifier.pro
index c43c96a..27484c8 100644
--- a/tests/auto/qsocketnotifier/qsocketnotifier.pro
+++ b/tests/auto/qsocketnotifier/qsocketnotifier.pro
@@ -4,7 +4,7 @@ QT = core network
requires(contains(QT_CONFIG,private_tests))
-include(../qnativesocketengine/qsocketengine.pri)
+include(../platformsocketengine/platformsocketengine.pri)
symbian: TARGET.CAPABILITY = NetworkServices
diff --git a/tests/auto/qsocketnotifier/tst_qsocketnotifier.cpp b/tests/auto/qsocketnotifier/tst_qsocketnotifier.cpp
index 5594dc3..b31a6e6 100644
--- a/tests/auto/qsocketnotifier/tst_qsocketnotifier.cpp
+++ b/tests/auto/qsocketnotifier/tst_qsocketnotifier.cpp
@@ -53,6 +53,11 @@
#include <private/qnativesocketengine_p.h>
#define NATIVESOCKETENGINE QNativeSocketEngine
#endif
+#ifdef Q_OS_UNIX
+#include <private/qnet_unix_p.h>
+#endif
+#include <limits>
+#include <select.h>
class tst_QSocketNotifier : public QObject
{
@@ -64,6 +69,8 @@ public:
private slots:
void unexpectedDisconnection();
void mixingWithTimers();
+ void posixSockets();
+ void bogusFds();
};
tst_QSocketNotifier::tst_QSocketNotifier()
@@ -114,6 +121,9 @@ signals:
void tst_QSocketNotifier::unexpectedDisconnection()
{
+#ifdef Q_OS_SYMBIAN
+ QSKIP("Symbian socket engine psuedo descriptors can't be used for QSocketNotifier", SkipAll);
+#else
/*
Given two sockets and two QSocketNotifiers registered on each
their socket. If both sockets receive data, and the first slot
@@ -163,10 +173,14 @@ void tst_QSocketNotifier::unexpectedDisconnection()
UnexpectedDisconnectTester tester(&readEnd1, &readEnd2);
+ QTimer timer;
+ timer.setSingleShot(true);
+ timer.start(30000);
do {
// we have to wait until sequence value changes
// as any event can make us jump out processing
QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
+ QVERIFY(timer.isActive); //escape if test would hang
} while(tester.sequence <= 0);
QVERIFY(readEnd1.state() == QAbstractSocket::ConnectedState);
@@ -179,6 +193,7 @@ void tst_QSocketNotifier::unexpectedDisconnection()
writeEnd1->close();
writeEnd2->close();
server.close();
+#endif
}
class MixingWithTimersHelper : public QObject
@@ -243,5 +258,99 @@ void tst_QSocketNotifier::mixingWithTimers()
QCOMPARE(helper.socketActivated, true);
}
+void tst_QSocketNotifier::posixSockets()
+{
+#ifndef Q_OS_UNIX
+ QSKIP("test only for posix", SkipAll);
+#else
+
+ QTcpServer server;
+ QVERIFY(server.listen(QHostAddress::LocalHost, 0));
+
+ int posixSocket = qt_safe_socket(AF_INET, SOCK_STREAM, 0);
+ sockaddr_in addr;
+ addr.sin_addr.s_addr = htonl(0x7f000001);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(server.serverPort());
+ qt_safe_connect(posixSocket, (const struct sockaddr*)&addr, sizeof(sockaddr_in));
+ QVERIFY(server.waitForNewConnection(5000));
+ QScopedPointer<QTcpSocket> passive(server.nextPendingConnection());
+
+ ::fcntl(posixSocket, F_SETFL, ::fcntl(posixSocket, F_GETFL) | O_NONBLOCK);
+
+ {
+ QSocketNotifier rn(posixSocket, QSocketNotifier::Read);
+ connect(&rn, SIGNAL(activated(int)), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QSignalSpy readSpy(&rn, SIGNAL(activated(int)));
+ QSocketNotifier wn(posixSocket, QSocketNotifier::Write);
+ connect(&wn, SIGNAL(activated(int)), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QSignalSpy writeSpy(&wn, SIGNAL(activated(int)));
+ QSocketNotifier en(posixSocket, QSocketNotifier::Exception);
+ connect(&en, SIGNAL(activated(int)), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QSignalSpy errorSpy(&en, SIGNAL(activated(int)));
+
+ passive->write("hello",6);
+ passive->waitForBytesWritten(5000);
+
+ QTestEventLoop::instance().enterLoop(3);
+ QCOMPARE(readSpy.count(), 1);
+ QCOMPARE(writeSpy.count(), 0);
+ QCOMPARE(errorSpy.count(), 0);
+
+ char buffer[100];
+ qt_safe_read(posixSocket, buffer, 100);
+ QCOMPARE(buffer, "hello");
+
+ qt_safe_write(posixSocket, "goodbye", 8);
+
+ QTestEventLoop::instance().enterLoop(3);
+ QCOMPARE(readSpy.count(), 1);
+ QCOMPARE(writeSpy.count(), 1);
+ QCOMPARE(errorSpy.count(), 0);
+ QCOMPARE(passive->readAll(), QByteArray("goodbye",8));
+ }
+ qt_safe_close(posixSocket);
+#endif
+}
+
+void tst_QSocketNotifier::bogusFds()
+{
+#ifndef Q_OS_WIN
+ QTest::ignoreMessage(QtWarningMsg, "QSocketNotifier: Internal error");
+#endif
+ QSocketNotifier max(std::numeric_limits<int>::max(), QSocketNotifier::Read);
+ QTest::ignoreMessage(QtWarningMsg, "QSocketNotifier: Invalid socket specified");
+#ifndef Q_OS_WIN
+ QTest::ignoreMessage(QtWarningMsg, "QSocketNotifier: Internal error");
+#endif
+ QSocketNotifier min(std::numeric_limits<int>::min(), QSocketNotifier::Write);
+#ifndef Q_OS_WIN
+ QTest::ignoreMessage(QtWarningMsg, "QSocketNotifier: Internal error");
+#endif
+ //bogus magic number is the first pseudo socket descriptor from symbian socket engine.
+ QSocketNotifier bogus(0x40000000, QSocketNotifier::Exception);
+ QSocketNotifier largestlegal(FD_SETSIZE - 1, QSocketNotifier::Read);
+
+ QSignalSpy maxspy(&max, SIGNAL(activated(int)));
+ QSignalSpy minspy(&min, SIGNAL(activated(int)));
+ QSignalSpy bogspy(&bogus, SIGNAL(activated(int)));
+ QSignalSpy llspy(&largestlegal, SIGNAL(activated(int)));
+
+ //generate some unrelated socket activity
+ QTcpServer server;
+ QVERIFY(server.listen(QHostAddress::LocalHost));
+ connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop()));
+ QTcpSocket client;
+ client.connectToHost(QHostAddress::LocalHost, server.serverPort());
+ QTestEventLoop::instance().enterLoop(5);
+ QVERIFY(server.hasPendingConnections());
+
+ //check no activity on bogus notifiers
+ QCOMPARE(maxspy.count(), 0);
+ QCOMPARE(minspy.count(), 0);
+ QCOMPARE(bogspy.count(), 0);
+ QCOMPARE(llspy.count(), 0);
+}
+
QTEST_MAIN(tst_QSocketNotifier)
#include <tst_qsocketnotifier.moc>