diff options
author | Benoit Foucher <benoit@zeroc.com> | 2022-01-10 10:56:20 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-10 10:56:20 +0100 |
commit | a5540e4660c164a2ea2c7d3c6ffa059695895a6e (patch) | |
tree | 2278596977a59a0597eefa76bbbc1109e2bd885e /cpp/src | |
parent | Enable verbose output for authenticode signing (diff) | |
download | ice-a5540e4660c164a2ea2c7d3c6ffa059695895a6e.tar.bz2 ice-a5540e4660c164a2ea2c7d3c6ffa059695895a6e.tar.xz ice-a5540e4660c164a2ea2c7d3c6ffa059695895a6e.zip |
Fix for potential CFStream/NSStream deadlock with the iOS transports (#1329)
Diffstat (limited to 'cpp/src')
-rw-r--r-- | cpp/src/Ice/ios/StreamTransceiver.cpp | 48 | ||||
-rw-r--r-- | cpp/src/IceIAP/Transceiver.mm | 33 |
2 files changed, 56 insertions, 25 deletions
diff --git a/cpp/src/Ice/ios/StreamTransceiver.cpp b/cpp/src/Ice/ios/StreamTransceiver.cpp index b033ed1dfa5..88485a3b810 100644 --- a/cpp/src/Ice/ios/StreamTransceiver.cpp +++ b/cpp/src/Ice/ios/StreamTransceiver.cpp @@ -314,10 +314,18 @@ IceObjC::StreamTransceiver::close() SocketOperation IceObjC::StreamTransceiver::write(Buffer& buf) { - IceUtil::Mutex::Lock sync(_mutex); - if(_error) + // Don't hold the lock while calling on the CFStream API to avoid deadlocks in case the CFStream API calls + // the stream notification callbacks with an internal lock held. { - checkErrorStatus(_writeStream.get(), 0, __FILE__, __LINE__); + IceUtil::Mutex::Lock sync(_mutex); + if(_error) + { + checkErrorStatus(_writeStream.get(), 0, __FILE__, __LINE__); + } + else if (_writeStreamRegistered) + { + return SocketOperationWrite; + } } size_t packetSize = static_cast<size_t>(buf.b.end() - buf.i); @@ -355,10 +363,18 @@ IceObjC::StreamTransceiver::write(Buffer& buf) SocketOperation IceObjC::StreamTransceiver::read(Buffer& buf) { - IceUtil::Mutex::Lock sync(_mutex); - if(_error) + // Don't hold the lock while calling on the CFStream API to avoid deadlocks in case the CFStream API calls + // the stream notification callbacks with an internal lock held. { - checkErrorStatus(0, _readStream.get(), __FILE__, __LINE__); + IceUtil::Mutex::Lock sync(_mutex); + if (_error) + { + checkErrorStatus(0, _readStream.get(), __FILE__, __LINE__); + } + else if (_readStreamRegistered) + { + return SocketOperationRead; + } } size_t packetSize = static_cast<size_t>(buf.b.end() - buf.i); @@ -493,23 +509,21 @@ void IceObjC::StreamTransceiver::checkErrorStatus(CFWriteStreamRef writeStream, CFReadStreamRef readStream, const char* file, int line) { - if((writeStream && (CFWriteStreamGetStatus(writeStream) == kCFStreamStatusAtEnd)) || - (readStream && (CFReadStreamGetStatus(readStream) == kCFStreamStatusAtEnd))) + assert(writeStream || readStream); + + CFStreamStatus status = writeStream ? CFWriteStreamGetStatus(writeStream) : CFReadStreamGetStatus(readStream); + + if (status == kCFStreamStatusAtEnd || status == kCFStreamStatusClosed) { throw ConnectionLostException(file, line); } - UniqueRef<CFErrorRef> err; - if(writeStream && CFWriteStreamGetStatus(writeStream) == kCFStreamStatusError) - { - err.reset(CFWriteStreamCopyError(writeStream)); - } - else if(readStream && CFReadStreamGetStatus(readStream) == kCFStreamStatusError) - { - err.reset(CFReadStreamCopyError(readStream)); - } + assert(status == kCFStreamStatusError); + UniqueRef<CFErrorRef> err; + err.reset(writeStream ? CFWriteStreamCopyError(writeStream) : CFReadStreamCopyError(readStream)); assert(err.get()); + CFStringRef domain = CFErrorGetDomain(err.get()); if(CFStringCompare(domain, kCFErrorDomainPOSIX, 0) == kCFCompareEqualTo) { diff --git a/cpp/src/IceIAP/Transceiver.mm b/cpp/src/IceIAP/Transceiver.mm index dfba38805ac..f1a775715f7 100644 --- a/cpp/src/IceIAP/Transceiver.mm +++ b/cpp/src/IceIAP/Transceiver.mm @@ -263,10 +263,18 @@ IceObjC::iAPTransceiver::close() SocketOperation IceObjC::iAPTransceiver::write(Buffer& buf) { - IceUtil::Mutex::Lock sync(_mutex); - if(_error) + // Don't hold the lock while calling on the NSStream API to avoid deadlocks in case the NSStream API calls + // the stream notification callbacks with an internal lock held. { - checkErrorStatus(_writeStream, __FILE__, __LINE__); + IceUtil::Mutex::Lock sync(_mutex); + if(_error) + { + checkErrorStatus(_writeStream, __FILE__, __LINE__); + } + else if(_writeStreamRegistered) + { + return SocketOperationWrite; + } } size_t packetSize = static_cast<size_t>(buf.b.end() - buf.i); @@ -303,10 +311,18 @@ IceObjC::iAPTransceiver::write(Buffer& buf) SocketOperation IceObjC::iAPTransceiver::read(Buffer& buf) { - IceUtil::Mutex::Lock sync(_mutex); - if(_error) + // Don't hold the lock while calling on the NSStream API to avoid deadlocks in case the NSStream API calls + // the stream notification callbacks with an internal lock held. { - checkErrorStatus(_readStream, __FILE__, __LINE__); + IceUtil::Mutex::Lock sync(_mutex); + if(_error) + { + checkErrorStatus(_readStream, __FILE__, __LINE__); + } + else if(_readStreamRegistered) + { + return SocketOperationRead; + } } size_t packetSize = static_cast<size_t>(buf.b.end() - buf.i); @@ -418,14 +434,15 @@ void IceObjC::iAPTransceiver::checkErrorStatus(NSStream* stream, const char* file, int line) { NSStreamStatus status = [stream streamStatus]; - if(status == NSStreamStatusAtEnd) + if(status == NSStreamStatusAtEnd || status == NSStreamStatusClosed) { throw ConnectionLostException(file, line); } assert(status == NSStreamStatusError); - NSError* err = [stream streamError]; + assert(err != nil); + NSString* domain = [err domain]; if([domain compare:NSPOSIXErrorDomain] == NSOrderedSame) { |