Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory leak when using DnsGetCacheDataTable

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;
}
like image 972
mazkopolo Avatar asked Oct 15 '25 07:10

mazkopolo


2 Answers

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);
like image 102
autistic Avatar answered Oct 17 '25 19:10

autistic


Tried with Deleaker because at the first glance the code looked well: leaks

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:

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);
    }
}
like image 44
Artem Razin Avatar answered Oct 17 '25 21:10

Artem Razin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!