[reSIProcate] Bug in BaseConnection (or TcpBaseTransport?)
Byron Campen
bcampen at estacado.net
Thu May 4 09:23:03 CDT 2006
Scott:
Yes, but all destructors in a class tree need to be virtual, or you
run into problems. For instance, if you have a TcpConnection* cast as
a Connection*, and you delete it, ~TcpConnection() never gets called,
since the vptr doesn't exist.
list:
I would argue that this self-deletion behavior is incorrect, and
needs to be removed. Having "delete this" as a side-effect of a call
is usually insane, and makes a class unsuitable for stack allocation.
(I am planning on making a sweep through the codebase for other
instances of "delete this", and bringing poorly-chosen instances to
the attention to the list) Also, this sort of decision should not be
made way down at the base-class; this should be up to the Transport
objects.
Best regards,
Byron Campen
> I suspect what is causing the trap is the DebugLog of
> *currConnection after it has been deleted – we could either remove
> this log, or to get rid of the self deletion… Perhaps we should
> change preparseNewBytes to return an error (or set to a newly
> created error state) – then in Connection::read(), if
> preparseNewBytes returns an error – we should return bytesRead < 0
> – which will cause TcpBaseTransport to delete the connection.
>
>
>
> As for the destructor problem – you are correct – default
> destructors are not virtual. But TlsConnection is not inherited
> from TcpConnection – it is derived from Connection – which does
> have a virtual destructor.
>
>
>
> Scott
>
>
>
> From: resiprocate-devel-bounces at list.sipfoundry.org
> [mailto:resiprocate-devel-bounces at list.sipfoundry.org] On Behalf Of
> Byron Campen
> Sent: Wednesday, May 03, 2006 2:38 PM
> To: resiprocate-devel
> Subject: [reSIProcate] Bug in BaseConnection (or TcpBaseTransport?)
>
>
>
> Here is the relevant code in TcpBaseTransport...
>
>
>
> *snip*
>
>
>
> Connection* currConnection = mConnectionManager.getNextRead(fdset);
>
> if (currConnection)
>
> {
>
> if ( fdset.readyToRead(currConnection->getSocket()) ||
>
> currConnection->hasDataToRead() )
>
> {
>
> DebugLog (<< "TcpBaseTransport::processSomeReads() " <<
> *currConnection);
>
> fdset.clear(currConnection->getSocket());
>
>
>
> int bytesRead = currConnection->read(mStateMachineFifo);
>
> DebugLog (<< "TcpBaseTransport::processSomeReads() "
>
> << *currConnection << " read=" << bytesRead);
>
> if (bytesRead < 0)
>
> {
>
> DebugLog (<< "Closing connection bytesRead=" <<
> bytesRead);
>
> delete currConnection;
>
> }
>
> }
>
>
>
> *snip*
>
>
>
> The problem here is that Connection::read() can result in deletion
> of currConnection (see the following)
>
>
>
> from Connection::read()
>
> *snip*
>
> int
>
> Connection::read(Fifo<TransactionMessage>& fifo)
>
> {
>
> std::pair<char*, size_t> writePair = getWriteBuffer();
>
> size_t bytesToRead = resipMin(writePair.second,
>
> static_cast<size_t>
> (Connection::ChunkSize));
>
>
>
> assert(bytesToRead > 0);
>
> int bytesRead = read(writePair.first, bytesToRead);
>
> if (bytesRead <= 0)
>
> {
>
> delete [] writePair.first;
>
> return bytesRead;
>
> }
>
> getConnectionManager().touch(this);
>
> preparseNewBytes(bytesRead, fifo); //.dcm. may delete this
>
> return bytesRead;
>
> }
>
>
>
> *snip*
>
>
>
> from ConnectionBase::preparseNewBytes()
>
> *snip*
>
> case ReadingHeaders:
>
> {
>
> unsigned int chunkLength = mBufferPos + bytesRead;
>
> char *unprocessedCharPtr;
>
> MsgHeaderScanner::ScanChunkResult scanChunkResult =
>
> mMsgHeaderScanner.scanChunk(mBuffer,
>
> chunkLength,
>
> &unprocessedCharPtr);
>
> if (scanChunkResult == MsgHeaderScanner::scrError)
>
> {
>
> //.jacob. Not a terribly informative warning.
>
> WarningLog(<< "Discarding preparse!");
>
> delete [] mBuffer;
>
> mBuffer = 0;
>
> delete mMessage;
>
> mMessage = 0;
>
> //.jacob. Shouldn't the state also be set here?
>
> delete this;
>
> return;
>
> }
>
>
>
> *snip*
>
>
>
> Long story short, someone throws garbage at us over a Tcp
> socket, and we corrupt our heap. So, where should the
> responsibility for deletion of connections lie? If it belongs in
> ConnectionBase, we need to document this in the header file, in
> upper case, preferably about 50 times. (Although it looks like the
> function return cannot be used to discover whether or not deletion
> occurred, and it appears that this would be difficult to change, so
> I would argue we need to stop this behavior.) And, as a general
> principle, I get very angry when my objects delete themselves on a
> whim. Imagine the fun if I had a stack-allocated Connection that
> decided to delete itself?
>
>
>
> Also, it is worth noting that a virtual destructor has
> not been declared for TcpConnection, and an explicitly non-virtual
> destructor has been declared for TlsConnection. I am not sure
> whether auto-generated destructors are virtual, so there are
> potentially two more guns aimed at our foot here.
>
>
>
> Best regards,
>
> Byron Campen
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://list.resiprocate.org/pipermail/resiprocate-devel/attachments/20060504/93a84457/attachment.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 2369 bytes
Desc: not available
URL: <http://list.resiprocate.org/pipermail/resiprocate-devel/attachments/20060504/93a84457/attachment.bin>
More information about the resiprocate-devel
mailing list