【问题标题】:Why does this function always crash when free memory?为什么释放内存时这个函数总是崩溃?
【发布时间】:2012-07-18 05:44:32
【问题描述】:
int gb2Utf8(const char* source, int sourceLen, void *target, int targetLen)
{
    int result = 0;
    int bufLen = strlen(source) * 2;
    wchar_t *buffer = (wchar_t *)malloc(bufLen);
    if (!buffer)
    {
        result = 1;
        goto RETURN;
    }

    //GB18030 code page: 54936
    int m2wResult = MultiByteToWideChar(54936, MB_ERR_INVALID_CHARS, source, -1, buffer, bufLen);
    if (!m2wResult)
    {
        result = 2;
        goto RETURN;
    }

    int w2mResult = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, buffer, -1, (char *)target, targetLen, NULL, NULL);
    if (!w2mResult)
    {
        result = 3;
        goto RETURN;
    }

    RETURN:
    free(buffer);
    return result;
}

程序运行到free(buffer)会崩溃,但不知道为什么。
如果修改bufLen为常量,或者去掉MultiByteToWideChar函数,不会崩溃,我也不知道为什么。 这是崩溃时的调用堆栈:

msvcr100d.dll!_free_dbg_nolock(void * pUserData, int nBlockUse) 第 1376 行 + 0x3b 字节 C++
msvcr100d.dll!_free_dbg(void * pUserData, int nBlockUse) 第 1265 行 + 0xd 字节 C++
msvcr100d.dll!free(void * pUserData) 第 49 行 + 0xb 字节 C++
New.exe!gb2Utf8(const char * source, int sourceLen, void * target, int targetLen) 第 156 行 + 0xc 字节 C++
New.exe!wWinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, wchar_t * lpCmdLine, int nCmdShow) 第 29 行 + 0x11 字节 C++
New.exe!__tmainCRTStartup() 第 547 行 + 0x2c 字节 C
New.exe!wWinMainCRTStartup() 第 371 行 C
kernel32.dll!7509339a()
[下面的帧可能不正确和/或丢失,没有为 kernel32.dll 加载符号]
ntdll.dll!77979ef2()
ntdll.dll!77979ec5()

【问题讨论】:

  • 请大家帮忙,这个函数有两个错误。

标签: c winapi memory-management


【解决方案1】:

首先,我们来看看:

if (!buffer)
{
    result = 1;
    goto RETURN;
}

如果malloc函数失败,它返回NULL,然后buffer被赋值为NULL,然后程序由于goto RETURN而转向标签RETURN,然后调用free函数并@987654328 @表示free(NULL),属于违法行为。

其次,通过声明int bufLen = strlen(source) * 2;,您假设bufLen 始终为正数,但是,如果strlen(source)==0,它将为0。 malloc(0) 是 ANSI-C 中未定义的行为,因此不同的平台可能返回不同的结果。

另外,你最好仔细查看函数MultiByteToWideChar的用法。这是 MSDN 中的链接:MultiByteToWideChar function

【讨论】:

  • 谢谢,但是释放 NULL 指针是合法的行为。 'free() 函数释放 ptr 指向的内存分配。如果 ptr 是 NULL 指针,则不执行任何操作。 - 来自手册页
  • 抱歉我的错误。在检查了 C99 文档后,我意识到 free(NULL) 是合法的。然而,很久以前我的老师教我这个,我只是相信他而不去检查。再次抱歉。
  • 这里是C99文档中的描述:free函数使ptr指向的空间被释放,即可以进一步分配。如果 ptr 是空指针,则不会发生任何操作。否则,如果参数与 calloc、malloc 或 realloc 函数先前返回的指针不匹配,或者如果空间已通过调用 free 或 realloc 释放,则行为未定义。
【解决方案2】:

您不需要自己假设缓冲区大小,当您将 0 作为最后一个参数传递给函数 MultiByteToWideChar 时,它会返回包括终端空字符在内的缓冲区大小。然后您可以使用返回的大小创建缓冲区并使用它。

试试这个

int wchars_num =  MultiByteToWideChar( CP_UTF8 , 0 , source , -1, NULL , 0 );
wchar_t* buffer = (wchar_t *)malloc(wchars_num);

MultiByteToWideChar( CP_UTF8 , 0 , source  , -1, buffer , wchars_num );
// do whatever with buffer 
free(buffer) ;

【讨论】:

  • 我应该用 malloc 和 free 更改 new 和 delete 吗?
  • malloc 的参数是字节数,而不是元素(它甚至不知道元素类型是什么)。
【解决方案3】:

也许对于缓冲区,你也需要为 NULL 终止符分配内存:

int bufLen = strlen(source) * 2 + 2;

【讨论】:

  • 更好的是,使用sizeof (WCHAR)
【解决方案4】:

MultiByteToWideChar() 的最后一个参数是宽字符缓冲区中的字符 数,而不是字节数。您传递字节数,该函数可能会覆盖实际缓冲区,free() 在调试模式下编译时会检查它。

正如 Jeeva 所提到的,调用此函数的正确方法是使用 NULL 输出缓冲区调用它一次,分配具有请求大小的缓冲区,然后再次调用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多