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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -229,6 +229,8 @@ void done_with_network()
dpm->Done(); dpm->Done();
timer_mgr->Expire(); timer_mgr->Expire();
dns_mgr->Flush();
mgr.Drain();
mgr.Drain(); mgr.Drain();
if ( remote_serializer ) 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;
}
}