1
votes
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;
}

When program runs to free(buffer), it will crash, but I don't know why.
If modify bufLen to a constant value, or remove MultiByteToWideChar function, it won't crash, I also don't know why. This is the call stack when crash:

msvcr100d.dll!_free_dbg_nolock(void * pUserData, int nBlockUse) Line 1376 + 0x3b bytes C++
msvcr100d.dll!_free_dbg(void * pUserData, int nBlockUse) Line 1265 + 0xd bytes C++
msvcr100d.dll!free(void * pUserData) Line 49 + 0xb bytes C++
New.exe!gb2Utf8(const char * source, int sourceLen, void * target, int targetLen) Line 156 + 0xc bytes C++
New.exe!wWinMain(HINSTANCE__ * hInstance, HINSTANCE__ * hPrevInstance, wchar_t * lpCmdLine, int nCmdShow) Line 29 + 0x11 bytes C++
New.exe!__tmainCRTStartup() Line 547 + 0x2c bytes C
New.exe!wWinMainCRTStartup() Line 371 C
kernel32.dll!7509339a()
[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]
ntdll.dll!77979ef2()
ntdll.dll!77979ec5()

4
Tank all of you for help, there are two errors in this function. - user805627

4 Answers

3
votes

Perhaps for the buffer, you need to allocate memory for the NULL terminator too:

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

You need not assume the buffer size your self, when you pass 0 as the last parameter to the function MultiByteToWideChar it returns the buffer size including the terminal null character. Then you can create buffer with the returned size and use it.

try this

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) ;
1
votes

The last parameter for MultiByteToWideChar() is the number of characters in the widechar buffer and not the number of bytes. You pass the number of bytes, the function probably writes over the actual buffer and free() checks for that when compiled in debug mode.

And as Jeeva mentioned, the proper way to call this function is by calling it once with NULL output buffer, allocate the buffer with the requested size and then call it again.

1
votes

First, let's look at :

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

if malloc function failed, it returned NULL, and then buffer was assigned the value NULL, then the program turned to label RETURN due to goto RETURN , then free function was called and free(buffer) means to free(NULL), which is an illegal behavior.

Second, by declaring int bufLen = strlen(source) * 2;, you've assumed that bufLen will always be positive, however, it will be 0 if strlen(source)==0. malloc(0) is a undefined behavior in ANSI-C, so different platform might return different result.

Moreover, you'd better look up the usage of function MultiByteToWideChar carefully. Here is the link in MSDN: MultiByteToWideChar function