获取 MAC 地址的代码似乎破坏了内存,但仅在 Release 版本中,而不是 Debug 版本中
Code to get MAC address seems to corrupt memory, but only in Release build, not Debug build
以下代码在 Embarcadero C++ Builder 2009 'Release' 构建中使用时似乎正在破坏内存:
String MyCode::MacAddress(bool Dashes, DWORD *Index)
{
// Dashes to build the string with dashes or not: 00-14-22-01-23-45 vs. 001422012345
// Index is Input and Output.
// If NULL or Index==0 the first Mac address is requested.
// If > 0 that mac address is requested (0 based index)
// The return value, if !NULL, is always the count of available mac addresses
String Address ;
DWORD (*MyGetAdaptersInfo)(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen) = NULL ;
HMODULE khand = NULL ;
DWORD GetIndex = (Index)?(*Index):(0) ;
if (Index) *Index = 0 ;
if (!khand)
{
khand = LoadLibrary(TEXT("Iphlpapi.dll")) ;
if (khand)
{
MyGetAdaptersInfo = (DWORD (*)(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)) GetProcAddress(khand, "GetAdaptersInfo") ;
}
}
if (MyGetAdaptersInfo)
{
DWORD MacBufLen = 0 ;
IP_ADAPTER_INFO IPInfo ;
MyGetAdaptersInfo(&IPInfo, &MacBufLen) ;
if (MacBufLen)
{
BYTE *Buffer = new BYTE[MacBufLen] ;
if (Buffer)
{
IP_ADAPTER_INFO *IPInfo = (IP_ADAPTER_INFO*)Buffer ;
if (MyGetAdaptersInfo(IPInfo, &MacBufLen) == ERROR_SUCCESS)
{
DWORD Cnt = (MacBufLen / sizeof(IP_ADAPTER_INFO)) ;
if (Index) *Index = Cnt ;
if (GetIndex < Cnt)
{
IPInfo = (IP_ADAPTER_INFO*) &Buffer[(GetIndex * sizeof(IP_ADAPTER_INFO))] ;
for (DWORD x = 0 ; x < IPInfo->AddressLength ; x++)
{
if (!Dashes || x == (IPInfo->AddressLength - 1))
{
Address += String().sprintf(L"%.2X", (int)IPInfo->Address[x]) ;
}
else
{
Address += String().sprintf(L"%.2X-", (int)IPInfo->Address[x]) ;
}
}
}
}
}
delete[] Buffer ;
}
}
FreeLibrary(khand) ;
return Address ;
}
你能看到我目前看不到的东西吗?
我在调试版本中使用这段代码已经有一段时间了,没有出现任何问题。所以我从不怀疑它的正确功能。但是现在我使用 Embarcadero c++ Builder 2009 构建了一个发布版本,它似乎破坏了之后调用的其他功能的内存,最终导致异常错误。
当我从代码中删除 MacAddress() 调用时,一切都再次正常工作。
在调试模式下,CodeGuard 也从未触发。
感谢您的意见
您没有为 MyGetAdaptersInfo
变量声明调用约定,因此使用编译器的默认值(通常是 __cdecl
)。但是 GetAdaptersInfo()
函数(以及大多数 Win32 API)使用 __stdcall
调用约定,因此您需要在声明中包含它。
此外,您也不应该依赖 sizeof(IP_ADAPTER_INFO)
。它的大小可以从一个 OS 版本更改为另一个版本,并且没有选项可以知道给定版本实际使用的大小。 IP_ADAPTER_INFO
被实现为链表(即使它被分配为单个连续的内存缓冲区),您需要使用 IP_ADAPTER_INFO::Next
字段正确遍历列表。
试试像这样的东西:
String MyCode::MacAddress(bool Dashes, DWORD *Index)
{
// Dashes to build the string with dashes or not: 00-14-22-01-23-45 vs. 001422012345
// Index is Input and Output.
// If NULL or Index==0 the first Mac address is requested.
// If > 0 that mac address is requested (0 based index)
// The return value, if !NULL, is always the count of available mac addresses
String Address;
typedef DWORD (WINAPI *LPFN_GetAdaptersInfo)(PIP_ADAPTER_INFO, PULONG);
DWORD GetIndex = (Index) ? *Index : 0;
if (Index) *Index = 0;
HMODULE khand = LoadLibrary(TEXT("Iphlpapi.dll"));
if (khand)
{
LPFN_GetAdaptersInfo MyGetAdaptersInfo = (LPFN_GetAdaptersInfo) GetProcAddress(khand, "GetAdaptersInfo");
if (MyGetAdaptersInfo)
{
DWORD MacBufLen = 0;
if ((MyGetAdaptersInfo(NULL, &MacBufLen) == ERROR_BUFFER_OVERFLOW)
&& (MacBufLen > 0))
{
DynamicArray<BYTE> Buffer; // or std::vector<BYTE>
Buffer.Length = MacBufLen;
PIP_ADAPTER_INFO IPInfo = (PIP_ADAPTER_INFO) &Buffer[0];
if (MyGetAdaptersInfo(IPInfo, &MacBufLen) == ERROR_SUCCESS)
{
DWORD Cnt = 0;
do
{
if (GetIndex == Cnt)
{
for (DWORD x = 0; x < IPInfo->AddressLength; ++x)
{
if (!Dashes || (x == (IPInfo->AddressLength - 1)))
{
Address += String().sprintf(L"%.2X", (int) IPInfo->Address[x]);
}
else
{
Address += String().sprintf(L"%.2X-", (int) IPInfo->Address[x]) ;
}
}
}
++Cnt;
IPInfo = IPInfo->Next;
}
while (IPInfo != NULL);
if (Index) *Index = Cnt;
}
}
}
FreeLibrary(khand);
}
return Address;
}
以下代码在 Embarcadero C++ Builder 2009 'Release' 构建中使用时似乎正在破坏内存:
String MyCode::MacAddress(bool Dashes, DWORD *Index)
{
// Dashes to build the string with dashes or not: 00-14-22-01-23-45 vs. 001422012345
// Index is Input and Output.
// If NULL or Index==0 the first Mac address is requested.
// If > 0 that mac address is requested (0 based index)
// The return value, if !NULL, is always the count of available mac addresses
String Address ;
DWORD (*MyGetAdaptersInfo)(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen) = NULL ;
HMODULE khand = NULL ;
DWORD GetIndex = (Index)?(*Index):(0) ;
if (Index) *Index = 0 ;
if (!khand)
{
khand = LoadLibrary(TEXT("Iphlpapi.dll")) ;
if (khand)
{
MyGetAdaptersInfo = (DWORD (*)(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)) GetProcAddress(khand, "GetAdaptersInfo") ;
}
}
if (MyGetAdaptersInfo)
{
DWORD MacBufLen = 0 ;
IP_ADAPTER_INFO IPInfo ;
MyGetAdaptersInfo(&IPInfo, &MacBufLen) ;
if (MacBufLen)
{
BYTE *Buffer = new BYTE[MacBufLen] ;
if (Buffer)
{
IP_ADAPTER_INFO *IPInfo = (IP_ADAPTER_INFO*)Buffer ;
if (MyGetAdaptersInfo(IPInfo, &MacBufLen) == ERROR_SUCCESS)
{
DWORD Cnt = (MacBufLen / sizeof(IP_ADAPTER_INFO)) ;
if (Index) *Index = Cnt ;
if (GetIndex < Cnt)
{
IPInfo = (IP_ADAPTER_INFO*) &Buffer[(GetIndex * sizeof(IP_ADAPTER_INFO))] ;
for (DWORD x = 0 ; x < IPInfo->AddressLength ; x++)
{
if (!Dashes || x == (IPInfo->AddressLength - 1))
{
Address += String().sprintf(L"%.2X", (int)IPInfo->Address[x]) ;
}
else
{
Address += String().sprintf(L"%.2X-", (int)IPInfo->Address[x]) ;
}
}
}
}
}
delete[] Buffer ;
}
}
FreeLibrary(khand) ;
return Address ;
}
你能看到我目前看不到的东西吗?
我在调试版本中使用这段代码已经有一段时间了,没有出现任何问题。所以我从不怀疑它的正确功能。但是现在我使用 Embarcadero c++ Builder 2009 构建了一个发布版本,它似乎破坏了之后调用的其他功能的内存,最终导致异常错误。
当我从代码中删除 MacAddress() 调用时,一切都再次正常工作。
在调试模式下,CodeGuard 也从未触发。
感谢您的意见
您没有为 MyGetAdaptersInfo
变量声明调用约定,因此使用编译器的默认值(通常是 __cdecl
)。但是 GetAdaptersInfo()
函数(以及大多数 Win32 API)使用 __stdcall
调用约定,因此您需要在声明中包含它。
此外,您也不应该依赖 sizeof(IP_ADAPTER_INFO)
。它的大小可以从一个 OS 版本更改为另一个版本,并且没有选项可以知道给定版本实际使用的大小。 IP_ADAPTER_INFO
被实现为链表(即使它被分配为单个连续的内存缓冲区),您需要使用 IP_ADAPTER_INFO::Next
字段正确遍历列表。
试试像这样的东西:
String MyCode::MacAddress(bool Dashes, DWORD *Index)
{
// Dashes to build the string with dashes or not: 00-14-22-01-23-45 vs. 001422012345
// Index is Input and Output.
// If NULL or Index==0 the first Mac address is requested.
// If > 0 that mac address is requested (0 based index)
// The return value, if !NULL, is always the count of available mac addresses
String Address;
typedef DWORD (WINAPI *LPFN_GetAdaptersInfo)(PIP_ADAPTER_INFO, PULONG);
DWORD GetIndex = (Index) ? *Index : 0;
if (Index) *Index = 0;
HMODULE khand = LoadLibrary(TEXT("Iphlpapi.dll"));
if (khand)
{
LPFN_GetAdaptersInfo MyGetAdaptersInfo = (LPFN_GetAdaptersInfo) GetProcAddress(khand, "GetAdaptersInfo");
if (MyGetAdaptersInfo)
{
DWORD MacBufLen = 0;
if ((MyGetAdaptersInfo(NULL, &MacBufLen) == ERROR_BUFFER_OVERFLOW)
&& (MacBufLen > 0))
{
DynamicArray<BYTE> Buffer; // or std::vector<BYTE>
Buffer.Length = MacBufLen;
PIP_ADAPTER_INFO IPInfo = (PIP_ADAPTER_INFO) &Buffer[0];
if (MyGetAdaptersInfo(IPInfo, &MacBufLen) == ERROR_SUCCESS)
{
DWORD Cnt = 0;
do
{
if (GetIndex == Cnt)
{
for (DWORD x = 0; x < IPInfo->AddressLength; ++x)
{
if (!Dashes || (x == (IPInfo->AddressLength - 1)))
{
Address += String().sprintf(L"%.2X", (int) IPInfo->Address[x]);
}
else
{
Address += String().sprintf(L"%.2X-", (int) IPInfo->Address[x]) ;
}
}
}
++Cnt;
IPInfo = IPInfo->Next;
}
while (IPInfo != NULL);
if (Index) *Index = Cnt;
}
}
}
FreeLibrary(khand);
}
return Address;
}