简体   繁体   English

使用DnsGetCacheDataTable时发生内存泄漏

[英]Memory leak when using DnsGetCacheDataTable

The following code shows cached domain names in DNS client. 以下代码显示DNS客户端中的缓存域名。 Could somebody please help me to find the memory leak when it hits int stat = DnsGetCacheDataTable(pEntry); 当有人遇到int stat = DnsGetCacheDataTable(pEntry);时,有人可以帮我找到内存泄漏吗? line? 线?
PS: please use DNSAPI.lib while compiling the code. PS:请在编译代码时使用DNSAPI.lib。

#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;
}

There are several problems with this code. 此代码存在几个问题。

Consider that you're calling LoadLibrary at the beginning without calling FreeLibrary at the end. 考虑到您是在开始时调用LoadLibrary而不在结束时调用FreeLibrary 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. 考虑到通过在循环之前直接移到pEntry->pNext ,可以跳过一个条目。 Your memory leak occurs in that very same line of code, when you assign over the value returned by malloc : 当您分配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: 您甚至不需要malloc ,但更糟糕的是,您应该只free malloc返回的值,从而导致以下错误:

free(pEntry);

In fact, not only do you not need malloc (or free ) for this, but what do you need is actually DnsRecordListFree . 实际上,您不仅不需要malloc (或free ),而且实际上需要的是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);

Tried with Deleaker because at the first glance the code looked well: 与Deleaker一起尝试过,因为乍一看代码看起来不错: 泄漏

Then started debugging... and of course! 然后开始调试……当然! You free not original pEntry but modified one. 您不能释放原始的pEntry,而可以修改一个。

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. 更新:实际上,您不需要分配任何内存,因为DnsGetCacheDataTable本身已分配了它。 Tried to free the memory using DnsRecordListFree but it seems it doesn't work. 试图使用DnsRecordListFree释放内存,但似乎不起作用。 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);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM