<div dir="ltr"><div>hi ross,<br></div><div><br></div><div>colleague could not subscribe to the mailing list with his email address so see below for the forwarded question.<br><br></div><div>best regards,<br></div><div>gerald<br><br></div><div><div><div>------------------------------<wbr>------------------------------<wbr>------------------------------<wbr>----------------------<br><br><div>
<p class="MsoNormal">Hi,</p>
</div>
<div>
<p class="MsoNormal"> </p>
</div>
<div>
<p class="MsoNormal">three weeks ago we've started using libAsan on gcc 4.9 and we have fixed a dozen of small memory errors on our code ever since.</p>
</div>
<div>
<p class="MsoNormal">Today I'm having an error in the live555 code that came up using libAsan.</p>
</div>
<div>
<p class="MsoNormal"> </p>
</div>
<div>
<p class="MsoNormal">It seems that the taskscheduler fires up the
destructor of SocketDescriptor after an evaluation of true on the
fDeleteMyselfNext flag which is set implicitly by calling
Medium::close(our_session).</p>
</div>
<div>
<p class="MsoNormal">The problem is that this event can be fired after
the destruction of SocketDescriptor's rtpInterface, meaning that the
global variable "rtpInterface" inside SocketDescriptor points to a
free'd address.</p>
</div>
<div>
<p class="MsoNormal">It appears that in our code this has never caused
any troubles but now that we use libAsan it has come to our attention
since Asan fire a segfault when memory corruption occurs, there are no
false positives when using libAsan.</p>
</div>
<div>
<p class="MsoNormal"> </p>
</div>
<div>
<p class="MsoNormal">An example of the output when printing a line in RTPInterface::removeStreamSock<wbr>et and in ~RTPInterface:</p>
</div>
<div>
<p class="MsoNormal">...</p>
</div>
<div>
<p class="MsoNormal">Debug: removeStreamSocket @ 0xad3056c8<br>
Debug: delete RTPInterface 0xad3056c8</p>
</div>
<div>
<p class="MsoNormal">Debug: removeStreamSocket @ 0xad3056c8</p>
</div>
<div>
<p class="MsoNormal">...</p>
</div>
<div>
<p class="MsoNormal"> </p>
</div>
<div>
<p class="MsoNormal">As can be seen, after the RTPInterface was delete, removeStreamSocket is being called on the same rtpInterface ptr.</p>
</div>
<div>
<p class="MsoNormal">As it happens the code inside removeStreamSocket
using the invalid ptr doesn't do anything wrong on our side, the first
variable being tested is always NULL, a null check prevents that the
code continues, this however is purely a coincidence.</p>
</div>
<div>
<p class="MsoNormal"> </p>
</div>
<div>
<p class="MsoNormal">I've modified ~SocketDescriptor for debugging, lookupRTPInterface(fStreamChan<wbr>nelId) yields 0x0 so that's another way of telling that something is wrong (see code below).</p>
</div>
<div>
<p class="MsoNormal">Can someone put the same debug prints in their live555 implementation so that it can be confirmed that there is a issue?</p>
</div>
<div>
<p class="MsoNormal"> </p>
</div>
<div>
<p class="MsoNormal">Regards,</p>
</div>
<div>
<p class="MsoNormal">Frederik</p>
</div>
<div>
<p class="MsoNormal"> </p>
</div>
SocketDescriptor::~SocketDescr<wbr>iptor() {<br>
fEnv.taskScheduler().turnOffBa<wbr>ckgroundReadHandling(fOurSocke<wbr>tNum);<br>
removeSocketDescription(fEnv, fOurSocketNum);<br>
<br>
if (fSubChannelHashTable != NULL) {<br>
// Remove knowledge of this socket from any "RTPInterface"s that are using it:<br>
HashTable::Iterator* iter = HashTable::Iterator::create(*f<wbr>SubChannelHashTable);<br>
RTPInterface* rtpInterface;<br>
char const* key;<br>
<br>
while ((rtpInterface = (RTPInterface*)(iter->next(key<wbr>))) != NULL) {<br>
u_int64_t streamChannelIdLong = (u_int64_t)key;<br>
unsigned char streamChannelId = (unsigned char)streamChannelIdLong;<br>
<br>
auto i = lookupRTPInterface(fStreamChan<wbr>nelId);<br>
if (i == rtpInterface)<br>
{<br>
rtpInterface->removeStreamSock<wbr>et(fOurSocketNum, streamChannelId);<br>
}<br>
else<br>
{<br>
qDebug() << "lookupRTPInterface(fStreamCha<wbr>nnelId)
(" << i << ") != rtpInterface (" << rtpInterface
<< ") @ SocketDescriptor " << this;<br>
// prevent further errors:<br>
fServerRequestAlternativeByteH<wbr>andler = nullptr;<br>
}<br>
}<br>
delete iter;<br>
<br>
// Then remove the hash table entries themselves, and then remove the hash table:<br>
while (fSubChannelHashTable->RemoveN<wbr>ext() != NULL) {}<br>
delete fSubChannelHashTable;<br>
}<br>
<br>
// Finally:<br>
if (fServerRequestAlternativeByte<wbr>Handler != NULL) {<br>
// Hack: Pass a special character to our alternative byte handler, to tell it that either<br>
// - an error occurred when reading the TCP socket, or<br>
// - no error occurred, but it needs to take over control of the TCP socket once again.<br>
u_int8_t specialChar = fReadErrorOccurred ? 0xFF : 0xFE;<br>
(*fServerRequestAlternativeByt<wbr>eHandler)(fServerRequestAltern<wbr>ativeByteHandlerClientData, specialChar);<br>
}<br>
}</div></div></div></div>