获取 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;
}