Reputation: 391
The following code shows cached domain names in DNS client. Could somebody please help me to find the memory leak when it hits int stat = DnsGetCacheDataTable(pEntry); line?
PS: please use DNSAPI.lib while compiling the code.
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <WinDNS.h>
#include <stdarg.h>
typedef struct _DNS_CACHE_ENTRY {
struct _DNS_CACHE_ENTRY* pNext; // Pointer to next entry
PWSTR pszName; // DNS Record Name
unsigned short wType; // DNS Record Type
unsigned short wDataLength; // Not referenced
unsigned long dwFlags; // DNS Record FlagsB
} DNSCACHEENTRY, *PDNSCACHEENTRY;
typedef int(WINAPI *DNS_GET_CACHE_DATA_TABLE)(PDNSCACHEENTRY);
void UpdateDNS(void)
{
PDNSCACHEENTRY pEntry = (PDNSCACHEENTRY) malloc(sizeof(DNSCACHEENTRY));
// Loading DLL
HINSTANCE hLib = LoadLibrary(TEXT("DNSAPI.dll"));
// Get function address
DNS_GET_CACHE_DATA_TABLE DnsGetCacheDataTable = (DNS_GET_CACHE_DATA_TABLE) GetProcAddress(hLib, "DnsGetCacheDataTable");
int stat = DnsGetCacheDataTable(pEntry);
printf("stat = %d\n", stat);
pEntry = pEntry->pNext;
while (pEntry) {
wprintf(L"%s : %d \n", (pEntry->pszName), (pEntry->wType));
pEntry = pEntry->pNext;
}
free(pEntry);
}
int main(int argc, char **argv) {
while (TRUE)
{
Sleep(100);
UpdateDNS();
}
return 0;
}
Upvotes: 4
Views: 2442
Reputation: 15642
There are several problems with this code.
Consider that you're calling LoadLibrary
at the beginning without calling FreeLibrary
at the end. Whilst not technically a memory leak, it's probably not the brightest idea...
Consider that by moving straight to pEntry->pNext
before the loop, you're skipping an entry. Your memory leak occurs in that very same line of code, when you assign over the value returned by malloc
:
PDNSCACHEENTRY pEntry = (PDNSCACHEENTRY) malloc(sizeof(DNSCACHEENTRY));
/* ... */
pEntry = pEntry->pNext;
You don't even need malloc
for this, but to make matters worse, you should only ever free
values that malloc
returns, rendering this erroneous:
free(pEntry);
In fact, not only do you not need malloc
(or free
) for this, but what do you need is actually DnsRecordListFree
.
Here's what your code should probably look like:
PDNS_RECORD entry;
HINSTANCE hLib = LoadLibrary(TEXT("DNSAPI.dll"));
DNS_GET_CACHE_DATA_TABLE DnsGetCacheDataTable = (DNS_GET_CACHE_DATA_TABLE) GetProcAddress(hLib, "DnsGetCacheDataTable");
int stat = DnsGetCacheDataTable(&entry);
printf("stat = %d\n", stat);
for (DNSCACHEENTRY *pTemp = &entry; pTemp; pTemp = pTemp->pNext) {
wprintf(L"%s : %d \n", pTemp->pszName, pTemp->wType);
}
DnsRecordListFree(entry, DnsFreeRecordList);
Upvotes: 4
Reputation: 1286
Tried with Deleaker because at the first glance the code looked well:
Then started debugging... and of course! You free not original pEntry but modified one.
Here the corrected code:
void UpdateDNS(void)
{
PDNSCACHEENTRY pEntry = (PDNSCACHEENTRY) malloc(sizeof(DNSCACHEENTRY) + 0x10000);
PDNSCACHEENTRY pFirstEntry = pEntry;
// Loading DLL
HINSTANCE hLib = LoadLibrary(TEXT("DNSAPI.dll"));
// Get function address
DNS_GET_CACHE_DATA_TABLE DnsGetCacheDataTable = (DNS_GET_CACHE_DATA_TABLE) GetProcAddress(hLib, "DnsGetCacheDataTable");
int stat = DnsGetCacheDataTable(pEntry);
printf("stat = %d\n", stat);
pEntry = pEntry->pNext;
while (pEntry) {
wprintf(L"%s : %d \n", (pEntry->pszName), (pEntry->wType));
pEntry = pEntry->pNext;
}
free(pFirstEntry);
}
UPDATE: in fact you don't need to allocate any memory because DnsGetCacheDataTable allocated it itself. Tried to free the memory using DnsRecordListFree but it seems it doesn't work. Still leaks:
Finally I got the code that doesn't leak:
typedef int(WINAPI *DNS_GET_CACHE_DATA_TABLE)(PDNSCACHEENTRY*);
typedef void (WINAPI *P_DnsApiFree)(PVOID pData);
void UpdateDNS(void)
{
PDNSCACHEENTRY pEntry = NULL;
// Loading DLL
HINSTANCE hLib = LoadLibrary(TEXT("DNSAPI.dll"));
// Get function address
DNS_GET_CACHE_DATA_TABLE DnsGetCacheDataTable = (DNS_GET_CACHE_DATA_TABLE)GetProcAddress(hLib, "DnsGetCacheDataTable");
P_DnsApiFree pDnsApiFree = (P_DnsApiFree)GetProcAddress(hLib, "DnsApiFree");
int stat = DnsGetCacheDataTable(&pEntry);
PVOID pFirstEntry = pEntry;
printf("stat = %d\n", stat);
pEntry = pEntry->pNext;
while (pEntry) {
wprintf(L"%s : %d \n", (pEntry->pszName), (pEntry->wType));
pDnsApiFree(pEntry->pszName);
PVOID p = pEntry;
pEntry = pEntry->pNext;
pDnsApiFree(p);
}
}
Upvotes: 2