Fix for disable_analyzer() problem.

When calling an Analyzer's method to remove a child analyzer, we now
postpone the actual removal to later, as otherwise the call to Done()
might trigger further analyzer activity that can interfere with code
running after that that triggered the removal.

This should fix the SSL assertion crashes that we have seen.

This change is a bit tricky internally, but the trace-based tests
produce the same output as before so things should be fine ...
This commit is contained in:
Robin Sommer 2011-07-22 16:19:24 -07:00
parent d01b8c9d3d
commit 8dc1a52d9d
2 changed files with 42 additions and 13 deletions

View file

@ -243,6 +243,7 @@ Analyzer::Analyzer(AnalyzerTag::Tag arg_tag, Connection* arg_conn)
protocol_confirmed = false;
skip = false;
finished = false;
removing = false;
parent = 0;
orig_supporters = 0;
resp_supporters = 0;
@ -424,10 +425,16 @@ void Analyzer::ForwardPacket(int len, const u_char* data, bool is_orig,
Analyzer* current = *i;
next = ++i;
if ( ! current->finished )
if ( ! (current->finished || current->removing ) )
current->NextPacket(len, data, is_orig, seq, ip, caplen);
else
{
if ( removing )
{
current->Done();
removing = false;
}
// Analyzer has already been disabled so delete it.
DBG_LOG(DBG_DPD, "%s deleted child %s",
fmt_analyzer(this).c_str(), fmt_analyzer(current).c_str());
@ -453,11 +460,17 @@ void Analyzer::ForwardStream(int len, const u_char* data, bool is_orig)
Analyzer* current = *i;
next = ++i;
if ( ! current->finished )
if ( ! (current->finished || current->removing ) )
current->NextStream(len, data, is_orig);
else
{
// Analyzer has already been disabled so delete it.
if ( current->removing )
{
current->Done();
removing = false;
}
DBG_LOG(DBG_DPD, "%s deleted child %s",
fmt_analyzer(this).c_str(), fmt_analyzer(current).c_str());
children.erase(--i);
@ -482,10 +495,16 @@ void Analyzer::ForwardUndelivered(int seq, int len, bool is_orig)
Analyzer* current = *i;
next = ++i;
if ( ! current->finished )
if ( ! (current->finished || current->removing ) )
current->NextUndelivered(seq, len, is_orig);
else
{
if ( current->removing )
{
current->Done();
removing = false;
}
// Analyzer has already been disabled so delete it.
DBG_LOG(DBG_DPD, "%s deleted child %s",
fmt_analyzer(this).c_str(), fmt_analyzer(current).c_str());
@ -508,10 +527,16 @@ void Analyzer::ForwardEndOfData(bool orig)
Analyzer* current = *i;
next = ++i;
if ( ! current->finished )
if ( ! (current->finished || current->removing ) )
current->NextEndOfData(orig);
else
{
if ( current->removing )
{
current->Done();
removing = false;
}
// Analyzer has already been disabled so delete it.
DBG_LOG(DBG_DPD, "%s deleted child %s",
fmt_analyzer(this).c_str(), fmt_analyzer(current).c_str());
@ -563,15 +588,17 @@ Analyzer* Analyzer::AddChildAnalyzer(AnalyzerTag::Tag analyzer)
void Analyzer::RemoveChildAnalyzer(Analyzer* analyzer)
{
LOOP_OVER_CHILDREN(i)
if ( *i == analyzer && ! analyzer->finished )
if ( *i == analyzer && ! (analyzer->finished || analyzer->removing) )
{
DBG_LOG(DBG_DPD, "%s disabled child %s",
DBG_LOG(DBG_DPD, "%s disabling child %s",
fmt_analyzer(this).c_str(), fmt_analyzer(*i).c_str());
(*i)->Done();
// We don't delete it here as we may in fact
// iterate over the list right now. Done() sets
// "finished" to true and this is checked
// later to delete it.
// We just flag it as being removed here but postpone
// actually doing that to later. Otherwise, we'd need
// to call Done() here, which then in turn might
// cause further code to be executed that may assume
// something not true because of a violation that
// triggered the removal in the first place.
(*i)->removing = true;
return;
}
}
@ -579,11 +606,12 @@ void Analyzer::RemoveChildAnalyzer(Analyzer* analyzer)
void Analyzer::RemoveChildAnalyzer(AnalyzerID id)
{
LOOP_OVER_CHILDREN(i)
if ( (*i)->id == id && ! (*i)->finished )
if ( (*i)->id == id && ! ((*i)->finished || (*i)->removing) )
{
DBG_LOG(DBG_DPD, "%s disabled child %s", GetTagName(), id,
fmt_analyzer(this).c_str(), fmt_analyzer(*i).c_str());
(*i)->Done();
// See comment above.
(*i)->removing = true;
return;
}
}

View file

@ -299,6 +299,7 @@ private:
bool timers_canceled;
bool skip;
bool finished;
bool removing;
static AnalyzerID id_counter;