kernel32: Reject an insufficiently sized buffer in FormatMessageA/W.

This commit is contained in:
Andrew Nguyen 2010-04-18 09:08:54 -05:00 committed by Alexandre Julliard
parent c0e7931954
commit 8b28efaed7
2 changed files with 119 additions and 9 deletions

View file

@ -570,13 +570,20 @@ DWORD WINAPI FormatMessageA(
*((LPVOID*)lpBuffer) = LocalAlloc(LMEM_ZEROINIT,max(nSize, talloced));
memcpy(*(LPSTR*)lpBuffer,target,talloced);
} else {
lstrcpynA(lpBuffer,target,nSize);
if (nSize < talloced)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
goto failure;
}
strcpy(lpBuffer, target);
}
ret = talloced - 1; /* null terminator */
failure:
HeapFree(GetProcessHeap(),0,target);
HeapFree(GetProcessHeap(),0,from);
if (!(dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)) HeapFree( GetProcessHeap(), 0, format_args.args );
ret = (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ? strlen(*(LPSTR*)lpBuffer) : strlen(lpBuffer);
TRACE("-- returning %d\n", ret);
TRACE("-- returning %u\n", ret);
return ret;
}
#undef ADD_TO_T
@ -595,6 +602,7 @@ DWORD WINAPI FormatMessageW(
__ms_va_list* args )
{
struct format_args format_args;
DWORD ret = 0;
LPWSTR target,t;
DWORD talloced;
LPWSTR from;
@ -741,21 +749,29 @@ DWORD WINAPI FormatMessageW(
*t='\0';
}
talloced = strlenW(target)+1;
TRACE("-- %s\n",debugstr_w(target));
if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) {
/* nSize is the MINIMUM size */
DWORD len = strlenW(target) + 1;
*((LPVOID*)lpBuffer) = LocalAlloc(LMEM_ZEROINIT,len*sizeof(WCHAR));
strcpyW(*(LPWSTR*)lpBuffer, target);
}
else lstrcpynW(lpBuffer, target, nSize);
else
{
if (nSize < talloced)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
goto failure;
}
strcpyW(lpBuffer, target);
}
ret = talloced - 1; /* null terminator */
failure:
HeapFree(GetProcessHeap(),0,target);
HeapFree(GetProcessHeap(),0,from);
if (!(dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)) HeapFree( GetProcessHeap(), 0, format_args.args );
TRACE("ret=%s\n", wine_dbgstr_w((dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
*(LPWSTR*)lpBuffer : lpBuffer));
return (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) ?
strlenW(*(LPWSTR*)lpBuffer):
strlenW(lpBuffer);
TRACE("-- returning %u\n", ret);
return ret;
}
#undef ADD_TO_T

View file

@ -638,6 +638,98 @@ static void test_message_from_string(void)
ok(r==2,"failed: r=%d\n",r);
}
static void test_message_insufficient_buffer(void)
{
static const char init_buf[] = {'x', 'x', 'x', 'x', 'x'};
static const char expected_buf[] = {'x', 'x', 'x', 'x', 'x'};
DWORD ret;
CHAR out[5];
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test", 0, 0, out, 0, NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n",
GetLastError());
ok(!memcmp(expected_buf, out, sizeof(expected_buf)),
"Expected the buffer to be untouched\n");
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test", 0, 0, out, 1, NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n",
GetLastError());
ok(!memcmp(expected_buf, out, sizeof(expected_buf)),
"Expected the buffer to be untouched\n");
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING, "test", 0, 0, out, sizeof(out)/sizeof(out[0]) - 1, NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n",
GetLastError());
ok(!memcmp(expected_buf, out, sizeof(expected_buf)),
"Expected the buffer to be untouched\n");
}
static void test_message_insufficient_buffer_wide(void)
{
static const WCHAR test[] = {'t','e','s','t',0};
static const WCHAR init_buf[] = {'x', 'x', 'x', 'x', 'x'};
static const WCHAR expected_buf[] = {'x', 'x', 'x', 'x', 'x'};
static const WCHAR broken_buf[] = {0, 'x', 'x', 'x', 'x'};
static const WCHAR broken2_buf[] = {'t','e','s',0,'x'};
DWORD ret;
WCHAR out[5];
SetLastError(0xdeadbeef);
ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, NULL, 0, 0, NULL, 0, NULL);
if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
{
win_skip("FormatMessageW is not implemented\n");
return;
}
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, test, 0, 0, out, 0, NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n",
GetLastError());
ok(!memcmp(expected_buf, out, sizeof(expected_buf)),
"Expected the buffer to be untouched\n");
/* Windows Server 2003 and newer report failure but copy a
* truncated string to the buffer for non-zero buffer sizes. */
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, test, 0, 0, out, 1, NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n",
GetLastError());
ok(!memcmp(expected_buf, out, sizeof(expected_buf)) ||
broken(!memcmp(broken_buf, out, sizeof(broken_buf))), /* W2K3+ */
"Expected the buffer to be untouched\n");
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING, test, 0, 0, out, sizeof(out)/sizeof(out[0]) - 1, NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected GetLastError() to return ERROR_INSUFFICIENT_BUFFER, got %u\n",
GetLastError());
ok(!memcmp(expected_buf, out, sizeof(expected_buf)) ||
broken(!memcmp(broken2_buf, out, sizeof(broken2_buf))), /* W2K3+ */
"Expected the buffer to be untouched\n");
}
static void test_message_null_buffer(void)
{
DWORD ret, error;
@ -727,6 +819,8 @@ START_TEST(format_msg)
{
test_message_from_string();
test_message_from_string_wide();
test_message_insufficient_buffer();
test_message_insufficient_buffer_wide();
test_message_null_buffer();
test_message_from_hmodule();
}