使用 DnsGetCacheDataTable 时内存泄漏
Memory leak when using DnsGetCacheDataTable
以下代码展示了DNS客户端缓存的域名。有人可以帮我找到内存泄漏时的 int stat = DnsGetCacheDataTable(pEntry); 行吗?
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;
}
这段代码有几个问题。
考虑一下您在开始时调用了 LoadLibrary
而没有在结束时调用 FreeLibrary
。虽然从技术上讲不是内存泄漏,但它可能不是最聪明的主意...
考虑一下,在 循环之前直接移动到 pEntry->pNext
,您将跳过一个条目。当您分配 malloc
:
返回的值时,您的内存泄漏发生在同一行代码中
PDNSCACHEENTRY pEntry = (PDNSCACHEENTRY) malloc(sizeof(DNSCACHEENTRY));
/* ... */
pEntry = pEntry->pNext;
为此您甚至不需要 malloc
,但更糟糕的是,您应该只 free
值 malloc
returns,呈现此错误:
free(pEntry);
事实上,你不仅不需要malloc
(或free
),实际上你需要的是DnsRecordListFree
。
您的代码可能如下所示:
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);
尝试使用 Deleaker,因为乍一看代码看起来不错:
然后开始调试...当然!您释放的不是原始 pEntry,而是修改后的 pEntry。
这里是更正后的代码:
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);
}
更新:实际上您不需要分配任何内存,因为 DnsGetCacheDataTable 会自行分配内存。尝试使用 DnsRecordListFree 释放内存,但它似乎不起作用。仍然泄漏:
终于得到不泄露的代码:
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);
}
}
以下代码展示了DNS客户端缓存的域名。有人可以帮我找到内存泄漏时的 int stat = DnsGetCacheDataTable(pEntry); 行吗?
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;
}
这段代码有几个问题。
考虑一下您在开始时调用了 LoadLibrary
而没有在结束时调用 FreeLibrary
。虽然从技术上讲不是内存泄漏,但它可能不是最聪明的主意...
考虑一下,在 循环之前直接移动到 pEntry->pNext
,您将跳过一个条目。当您分配 malloc
:
PDNSCACHEENTRY pEntry = (PDNSCACHEENTRY) malloc(sizeof(DNSCACHEENTRY));
/* ... */
pEntry = pEntry->pNext;
为此您甚至不需要 malloc
,但更糟糕的是,您应该只 free
值 malloc
returns,呈现此错误:
free(pEntry);
事实上,你不仅不需要malloc
(或free
),实际上你需要的是DnsRecordListFree
。
您的代码可能如下所示:
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);
尝试使用 Deleaker,因为乍一看代码看起来不错:
然后开始调试...当然!您释放的不是原始 pEntry,而是修改后的 pEntry。
这里是更正后的代码:
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);
}
更新:实际上您不需要分配任何内存,因为 DnsGetCacheDataTable 会自行分配内存。尝试使用 DnsRecordListFree 释放内存,但它似乎不起作用。仍然泄漏:
终于得到不泄露的代码:
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);
}
}