(In)Security of MultiByteToWideChar and WideCharToMultiByte (Part 2)

Part 1 of this installment discussed the unsafe nature of MultiByteToWideChar and WideCharToMultiByte.  They do not guarantee terminating strings properly.  In this installment, I want to focus on the count parameters.  There are three count parameters that warrant your attention in order to use these two functions properly.

Since these two functions deal with conversion, the size of MultiByte and WideChar buffers are expected.  In addition, upon successful return, the number of converted characters is also returned.  These three counts must be carefully provided in order to ensure security.

Rules of thumb
1. MultiByte parameters always expect byte counts, the number of bytes in the corresponding buffer
2. WideChar parameters always expect character counts, the number of wide characters in the corresponding buffer
3. Return value follows rule #1 or #2, depending the type of output

Let’s study a bad example to illustrate some common errors.

wchar_t wstrTest1[] = L"123456789";
char strTest1[9];

    int result = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wstrTest1, sizeof(wstrTest1), strTest1, sizeof(strTest1), NULL, NULL);

Using sizeof() seems reasonable for both parameters, as WideCharToMultiByte expects size of the corresponding buffers.  sizeof() returns the byte count of a buffer.  Following the rules of thumb, let’s find the bug. 

The bug lies in the count of wstrTest1.   It expects the number of wchar_t characters, rather than the byte count.  The proper value should be character count, not byte count, therefore, sizeof(wstrTest1)/sizeof(wchar_t).

The correct call should be as follows:

int result = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wstrTest1,
sizeof(wstrTest1)/sizeof(wchar_t),
strTest1, sizeof(strTest1), NULL, NULL);

What is so bad about getting the count wrong?  It is possible to cause buffer overflows.  Considering MultiByteToWideChar, destination count is expected to be the count of wchar_t.  If the actual size is used, destination size erroneously doubles.  MultiByteToWideChar would gladly copy data up to double the size of the valid buffer.  As a result, buffer overflow occurs.