Fixing DNS memory leaks.

Some of the changes only clean up at termination to make perftools
happt, but there were some "real" leaks as well.

This fixes all DNS leaks I could reproducem, including most likely
what's reported in #534. Closing #534.

I'm also adding a new btest subdir core/leaks with tests requiring
perftools support. These don't compare against base lines but abort
whenever perftools reports a leak (with stack information to track it
down). Right now, these are passing.
This commit is contained in:
Robin Sommer 2011-10-08 18:54:58 -07:00
parent 8627b87b3e
commit bd9c937236
10 changed files with 113 additions and 8 deletions

View file

@ -592,6 +592,8 @@ void DNS_Mgr::Resolve()
}
else
--num_pending;
delete dr;
}
}
@ -847,6 +849,7 @@ const char* DNS_Mgr::LookupAddrInCache(dns_mgr_addr_type addr)
if ( d->Expired() )
{
dns_mgr->addr_mappings.Remove(&h);
delete d;
return 0;
}
@ -866,6 +869,7 @@ TableVal* DNS_Mgr::LookupNameInCache(string name)
{
HashKey h(name.c_str());
dns_mgr->host_mappings.Remove(&h);
delete d;
return 0;
}
@ -1038,14 +1042,29 @@ void DNS_Mgr::CheckAsyncHostRequest(const char* host, bool timeout)
}
}
void DNS_Mgr::Process()
void DNS_Mgr::Flush()
{
DoProcess(false);
IterCookie* cookie = addr_mappings.InitForIteration();
DNS_Mapping* dm;
host_mappings.Clear();
addr_mappings.Clear();
}
void DNS_Mgr::Process()
{
DoProcess(false);
}
void DNS_Mgr::DoProcess(bool flush)
{
while ( asyncs_timeouts.size() > 0 )
{
AsyncRequest* req = asyncs_timeouts.top();
if ( req->time + DNS_TIMEOUT > current_time() )
if ( req->time + DNS_TIMEOUT > current_time() || flush )
break;
if ( req->IsAddrReq() )
@ -1086,6 +1105,8 @@ void DNS_Mgr::Process()
CheckAsyncHostRequest(dr->ReqHost(), true);
IssueAsyncRequests();
delete dr;
}
}

View file

@ -49,6 +49,7 @@ public:
virtual ~DNS_Mgr();
bool Init();
void Flush();
// Looks up the address or addresses of the given host, and returns
// a set of addr.
@ -111,6 +112,9 @@ protected:
void CheckAsyncAddrRequest(dns_mgr_addr_type addr, bool timeout);
void CheckAsyncHostRequest(const char* host, bool timeout);
// Process outstanding requests.
void DoProcess(bool flush);
// IOSource interface.
virtual void GetFds(int* read, int* write, int* except);
virtual double NextTimestamp(double* network_time);

View file

@ -67,6 +67,19 @@ Dictionary::Dictionary(dict_order ordering, int initial_size)
}
Dictionary::~Dictionary()
{
DeInit();
delete order;
}
void Dictionary::Clear()
{
DeInit();
Init(2);
tbl2 = 0;
}
void Dictionary::DeInit()
{
for ( int i = 0; i < num_buckets; ++i )
if ( tbl[i] )
@ -84,7 +97,6 @@ Dictionary::~Dictionary()
}
delete [] tbl;
delete order;
if ( tbl2 == 0 )
return;
@ -103,7 +115,9 @@ Dictionary::~Dictionary()
delete chain;
}
delete [] tbl2;
tbl2 = 0;
}
void* Dictionary::Lookup(const void* key, int key_size, hash_t hash) const

View file

@ -118,11 +118,15 @@ public:
void MakeRobustCookie(IterCookie* cookie)
{ cookies.append(cookie); }
// Remove all entries.
void Clear();
unsigned int MemoryAllocation() const;
private:
void Init(int size);
void Init2(int size); // initialize second table for resizing
void DeInit();
// Internal version of Insert().
void* Insert(DictEntry* entry, int copy_key);

View file

@ -1463,6 +1463,7 @@ TableVal* ListVal::ConvertToSet() const
loop_over_list(vals, i)
t->Assign(vals[i], 0);
Unref(s);
return t;
}
@ -1582,6 +1583,7 @@ TableVal::TableVal(TableType* t, Attributes* a) : MutableVal(t)
void TableVal::Init(TableType* t)
{
::Ref(t);
table_type = t;
expire_expr = 0;
expire_time = 0;
@ -1604,6 +1606,7 @@ TableVal::~TableVal()
if ( timer )
timer_mgr->Cancel(timer);
Unref(table_type);
delete table_hash;
delete AsTable();
delete subnets;

View file

@ -869,7 +869,7 @@ protected:
DECLARE_SERIAL(TableVal);
const TableType* table_type;
TableType* table_type;
CompositeHash* table_hash;
Attributes* attrs;
double expire_time;

View file

@ -2828,13 +2828,15 @@ public:
// Overridden from DNS_Mgr:Lookup:Callback.
virtual void Resolved(const char* name)
{
trigger->Cache(call, new StringVal(name));
Val* result = new StringVal(name);
trigger->Cache(call, result);
Unref(result);
trigger->Release();
}
virtual void Resolved(TableVal* addrs)
{
Ref(addrs);
// No Ref() for addrs.
trigger->Cache(call, addrs);
trigger->Release();
}
@ -2842,12 +2844,19 @@ public:
virtual void Timeout()
{
if ( lookup_name )
trigger->Cache(call, new StringVal("<\?\?\?>"));
{
Val* result = new StringVal("<\?\?\?>");
trigger->Cache(call, result);
Unref(result);
}
else
{
ListVal* lv = new ListVal(TYPE_ADDR);
lv->Append(new AddrVal("0.0.0.0"));
trigger->Cache(call, lv->ConvertToSet());
Val* result = lv->ConvertToSet();
trigger->Cache(call, result);
Unref(result);
Unref(lv);
}

View file

@ -229,6 +229,8 @@ void done_with_network()
dpm->Done();
timer_mgr->Expire();
dns_mgr->Flush();
mgr.Drain();
mgr.Drain();
if ( remote_serializer )

View file

@ -0,0 +1,48 @@
# Needs perftools support.
#
# @TEST-REQUIRES: bro --help 2>&1 | grep -q mem-leaks
#
# @TEST-EXEC: HEAP_CHECK_DUMP_DIRECTORY=. HEAPCHECK=local bro -m -r $TRACES/wikipedia.trace %INPUT
# Add the state tracking information variable to the connection record
event connection_established(c: connection)
{
when ( local addrs = lookup_hostname("localhost") )
{
print "1a", c$id$resp_h, addrs;
}
timeout 100secs
{
print "1b", c$id$resp_h;
}
when ( local addrs2 = lookup_hostname("qq.ww.ee.rrrrr") )
{
print "2a", c$id$resp_h, addrs2;
}
timeout 100secs
{
print "2b", c$id$resp_h;
}
when ( local a = lookup_addr(c$id$resp_h) )
{
print "3a", c$id$resp_h, a;
}
timeout 100secs
{
print "3b", c$id$resp_h;
}
when ( local a2 = lookup_addr(1.2.3.4) )
{
print "4a", c$id$resp_h, a2;
}
timeout 100secs
{
print "4b", c$id$resp_h;
}
}