summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShane Kearns <shane.kearns@accenture.com>2011-01-17 15:13:52 (GMT)
committerShane Kearns <shane.kearns@accenture.com>2011-01-17 15:47:28 (GMT)
commit4fb5c42ede2b33c3092d70aa3e32cf6c677bd4d8 (patch)
treed96c7aa1c882619e75cb2a85a7a67d73d601c424
parentb1477e557681372d2c7119d637048123f0bad120 (diff)
downloadQt-4fb5c42ede2b33c3092d70aa3e32cf6c677bd4d8.zip
Qt-4fb5c42ede2b33c3092d70aa3e32cf6c677bd4d8.tar.gz
Qt-4fb5c42ede2b33c3092d70aa3e32cf6c677bd4d8.tar.bz2
Fix uncaught exception crash when socket ready read signal throws
When the application (in this case, an autotest) ran out of memory by calling readAll() in a slot, the exception propagated to the symbian active scheduler where it caused an assertion failure. Additionally, QAbstractSocket was left in a bad state because its member variables that guard against re-entrancy were left set. 1. Catch exceptions and convert to leaves in QAsyncSelect 2. Implement RunError function to set the socket engine error state 3. Use QScopedValueRollback in QAbstractSocket to ensure the reentrancy guards are reverted if an exception is thrown. Reviewed-by: Markus Goetz Reviewed-by: mread
-rw-r--r--src/network/socket/qabstractsocket.cpp10
-rw-r--r--src/network/socket/qsymbiansocketengine.cpp37
-rw-r--r--src/network/socket/qsymbiansocketengine_p.h3
3 files changed, 40 insertions, 10 deletions
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index c638e2a..156b905 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -375,6 +375,7 @@
#include <qpointer.h>
#include <qtimer.h>
#include <qelapsedtimer.h>
+#include <qscopedvaluerollback.h>
#ifndef QT_NO_OPENSSL
#include <QtNetwork/qsslsocket.h>
@@ -592,6 +593,7 @@ bool QAbstractSocketPrivate::canReadNotification()
socketEngine->setReadNotificationEnabled(false);
}
}
+ QScopedValueRollback<bool> rsncrollback(readSocketNotifierCalled);
readSocketNotifierCalled = true;
if (!isBuffered)
@@ -605,7 +607,6 @@ bool QAbstractSocketPrivate::canReadNotification()
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::canReadNotification() buffer is full");
#endif
- readSocketNotifierCalled = false;
return false;
}
@@ -617,7 +618,6 @@ bool QAbstractSocketPrivate::canReadNotification()
qDebug("QAbstractSocketPrivate::canReadNotification() disconnecting socket");
#endif
q->disconnectFromHost();
- readSocketNotifierCalled = false;
return false;
}
newBytes = readBuffer.size() - newBytes;
@@ -637,9 +637,9 @@ bool QAbstractSocketPrivate::canReadNotification()
;
if (!emittedReadyRead && hasData) {
+ QScopedValueRollback<bool> r(emittedReadyRead);
emittedReadyRead = true;
emit q->readyRead();
- emittedReadyRead = false;
}
// If we were closed as a result of the readyRead() signal,
@@ -648,7 +648,6 @@ bool QAbstractSocketPrivate::canReadNotification()
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::canReadNotification() socket is closing - returning");
#endif
- readSocketNotifierCalled = false;
return true;
}
@@ -662,7 +661,6 @@ bool QAbstractSocketPrivate::canReadNotification()
socketEngine->setReadNotificationEnabled(readSocketNotifierState);
readSocketNotifierStateSet = false;
}
- readSocketNotifierCalled = false;
return true;
}
@@ -768,9 +766,9 @@ bool QAbstractSocketPrivate::flush()
if (written > 0) {
// Don't emit bytesWritten() recursively.
if (!emittedBytesWritten) {
+ QScopedValueRollback<bool> r(emittedBytesWritten);
emittedBytesWritten = true;
emit q->bytesWritten(written);
- emittedBytesWritten = false;
}
}
diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp
index 2f991de..455bf5e 100644
--- a/src/network/socket/qsymbiansocketengine.cpp
+++ b/src/network/socket/qsymbiansocketengine.cpp
@@ -1308,6 +1308,9 @@ void QSymbianSocketEnginePrivate::setError(TInt symbianError)
case KErrNotSupported:
setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString);
break;
+ case KErrNoMemory:
+ setError(QAbstractSocket::SocketResourceError, ResourceErrorString);
+ break;
default:
socketError = QAbstractSocket::NetworkError;
socketErrorString = QString::number(symbianError);
@@ -1564,22 +1567,47 @@ void QAsyncSelect::DoCancel()
void QAsyncSelect::RunL()
{
+ QT_TRYCATCH_LEAVING(run());
+}
+
+//RunError is called by the active scheduler if RunL leaves.
+//Typically this will happen if a std::bad_alloc propagates down from the application
+TInt QAsyncSelect::RunError(TInt aError)
+{
+ if (engine) {
+ QT_TRY {
+ engine->d_func()->setError(aError);
+ QEvent e(QEvent::SockAct);
+ if (iExcN)
+ iExcN->event(&e);
+ if (iReadN)
+ iReadN->event(&e);
+ }
+ QT_CATCH(...) {}
+ }
+#ifdef QNATIVESOCKETENGINE_DEBUG
+ qDebug() << "QAsyncSelect::RunError" << aError;
+#endif
+ return KErrNone;
+}
+
+void QAsyncSelect::run()
+{
//TODO: block when event loop demands it
//if (maybeQueueForLater())
// return;
-
m_inSocketEvent = true;
m_selectBuf() &= m_selectFlags; //the select ioctl reports everything, so mask to only what we requested
//TODO: KSockSelectReadContinuation does what?
- if (m_selectBuf() & KSockSelectRead) {
+ if (iReadN && (m_selectBuf() & KSockSelectRead)) {
QEvent e(QEvent::SockAct);
iReadN->event(&e);
}
- if (m_selectBuf() & KSockSelectWrite) {
+ if (iWriteN && (m_selectBuf() & KSockSelectWrite)) {
QEvent e(QEvent::SockAct);
iWriteN->event(&e);
}
- if ((m_selectBuf() & KSockSelectExcept) || iStatus != KErrNone) {
+ if (iExcN && ((m_selectBuf() & KSockSelectExcept) || iStatus != KErrNone)) {
QEvent e(QEvent::SockAct);
iExcN->event(&e);
}
@@ -1598,6 +1626,7 @@ void QAsyncSelect::deleteLater()
iExcN = 0;
iReadN = 0;
iWriteN = 0;
+ engine = 0;
m_deleteLater = true;
} else {
delete this;
diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h
index bc85f9c..f36b7dd 100644
--- a/src/network/socket/qsymbiansocketengine_p.h
+++ b/src/network/socket/qsymbiansocketengine_p.h
@@ -72,6 +72,7 @@ class QNetworkInterface;
class Q_AUTOTEST_EXPORT QSymbianSocketEngine : public QAbstractSocketEngine
{
Q_OBJECT
+ friend class QAsyncSelect;
public:
QSymbianSocketEngine(QObject *parent = 0);
~QSymbianSocketEngine();
@@ -167,6 +168,8 @@ public:
protected:
void DoCancel();
void RunL();
+ void run();
+ TInt RunError(TInt aError);
private:
QReadNotifier* iReadN;