kernel32: Reject an insufficiently sized buffer in FormatMessageA/W.
This commit is contained in:
parent
c0e7931954
commit
8b28efaed7
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue