Commit f50198f6 authored by Andrew Nguyen's avatar Andrew Nguyen Committed by Alexandre Julliard

kernel32: Improve flag error handling in FormatMessageA/W.

parent 9df55f06
......@@ -393,14 +393,16 @@ DWORD WINAPI FormatMessageA(
TRACE("(0x%x,%p,%d,0x%x,%p,%d,%p)\n",
dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
if ((dwFlags & FORMAT_MESSAGE_FROM_STRING)
&&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)
|| (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0;
if ((dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER) && !lpBuffer)
if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
if (!lpBuffer)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
else
*(LPSTR *)lpBuffer = NULL;
}
if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
......@@ -425,13 +427,19 @@ DWORD WINAPI FormatMessageA(
from = HeapAlloc( GetProcessHeap(), 0, length * sizeof(WCHAR) );
MultiByteToWideChar(CP_ACP, 0, lpSource, -1, from, length);
}
else {
else if (dwFlags & (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM))
{
if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE)
from = load_message( (HMODULE)lpSource, dwMessageId, dwLanguageId );
if (!from && (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM))
from = load_message( kernel32_handle, dwMessageId, dwLanguageId );
if (!from) return 0;
}
else
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
target = format_message( FALSE, dwFlags, from, &format_args );
if (!target)
......@@ -483,9 +491,6 @@ DWORD WINAPI FormatMessageW(
TRACE("(0x%x,%p,%d,0x%x,%p,%d,%p)\n",
dwFlags,lpSource,dwMessageId,dwLanguageId,lpBuffer,nSize,args);
if ((dwFlags & FORMAT_MESSAGE_FROM_STRING)
&&((dwFlags & FORMAT_MESSAGE_FROM_SYSTEM)
|| (dwFlags & FORMAT_MESSAGE_FROM_HMODULE))) return 0;
if (!lpBuffer)
{
......@@ -493,6 +498,9 @@ DWORD WINAPI FormatMessageW(
return 0;
}
if (dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER)
*(LPWSTR *)lpBuffer = NULL;
if (dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY)
{
format_args.args = (ULONG_PTR *)args;
......@@ -514,13 +522,19 @@ DWORD WINAPI FormatMessageW(
sizeof(WCHAR) );
strcpyW( from, lpSource );
}
else {
else if (dwFlags & (FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_FROM_SYSTEM))
{
if (dwFlags & FORMAT_MESSAGE_FROM_HMODULE)
from = load_message( (HMODULE)lpSource, dwMessageId, dwLanguageId );
if (!from && (dwFlags & FORMAT_MESSAGE_FROM_SYSTEM))
from = load_message( kernel32_handle, dwMessageId, dwLanguageId );
if (!from) return 0;
}
else
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
target = format_message( TRUE, dwFlags, from, &format_args );
if (!target)
......
......@@ -1112,6 +1112,185 @@ static void test_message_from_hmodule(void)
"last error %u\n", error);
}
static void test_message_invalid_flags(void)
{
static const char init_buf[] = {'x', 'x', 'x', 'x', 'x'};
DWORD ret;
CHAR out[5];
char *ptr;
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageA(0, "test", 0, 0, out, sizeof(out)/sizeof(CHAR), NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(!memcmp(out, init_buf, sizeof(init_buf)),
"Expected the output buffer to be untouched\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
GetLastError());
SetLastError(0xdeadbeef);
ptr = (char *)0xdeadbeef;
ret = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER, "test", 0, 0, (char *)&ptr, 0, NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(ptr == NULL ||
broken(ptr == (char *)0xdeadbeef), /* Win9x */
"Expected output pointer to be initialized to NULL, got %p\n", ptr);
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
GetLastError());
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS, "test", 0, 0, out, sizeof(out)/sizeof(CHAR), NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(!memcmp(out, init_buf, sizeof(init_buf)),
"Expected the output buffer to be untouched\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
GetLastError());
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageA(FORMAT_MESSAGE_ARGUMENT_ARRAY, "test", 0, 0, out, sizeof(out)/sizeof(CHAR), NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(!memcmp(out, init_buf, sizeof(init_buf)),
"Expected the output buffer to be untouched\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
GetLastError());
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageA(FORMAT_MESSAGE_MAX_WIDTH_MASK, "test", 0, 0, out, sizeof(out)/sizeof(CHAR), NULL);
ok(ret == 0, "Expected FormatMessageA to return 0, got %u\n", ret);
ok(!memcmp(out, init_buf, sizeof(init_buf)),
"Expected the output buffer to be untouched\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
GetLastError());
/* Simultaneously setting FORMAT_MESSAGE_FROM_STRING with other source
* flags is apparently permissible, and FORMAT_MESSAGE_FROM_STRING takes
* precedence in this case. */
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_FROM_SYSTEM,
"test", 0, 0, out, sizeof(out)/sizeof(CHAR), NULL);
ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret);
ok(!strcmp("test", out),
"Expected the output buffer to be untouched\n");
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_FROM_HMODULE,
"test", 0, 0, out, sizeof(out)/sizeof(CHAR), NULL);
ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret);
ok(!strcmp("test", out),
"Expected the output buffer to be untouched\n");
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageA(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_FROM_SYSTEM, "test", 0, 0, out,
sizeof(out)/sizeof(CHAR), NULL);
ok(ret == 4, "Expected FormatMessageA to return 4, got %u\n", ret);
ok(!strcmp("test", out),
"Expected the output buffer to be untouched\n");
}
static void test_message_invalid_flags_wide(void)
{
static const WCHAR init_buf[] = {'x', 'x', 'x', 'x', 'x'};
static const WCHAR test[] = {'t','e','s','t',0};
DWORD ret;
WCHAR out[5];
WCHAR *ptr;
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(0, test, 0, 0, out, sizeof(out)/sizeof(WCHAR), NULL);
ok(ret == 0, "Expected FormatMessageW to return 0, got %u\n", ret);
ok(!memcmp(out, init_buf, sizeof(init_buf)),
"Expected the output buffer to be untouched\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
GetLastError());
SetLastError(0xdeadbeef);
ptr = (WCHAR *)0xdeadbeef;
ret = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER, test, 0, 0, (WCHAR *)&ptr, 0, NULL);
ok(ret == 0, "Expected FormatMessageW to return 0, got %u\n", ret);
ok(ptr == NULL, "Expected output pointer to be initialized to NULL, got %p\n", ptr);
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
GetLastError());
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS, test, 0, 0, out, sizeof(out)/sizeof(WCHAR), NULL);
ok(ret == 0, "Expected FormatMessageW to return 0, got %u\n", ret);
ok(!memcmp(out, init_buf, sizeof(init_buf)),
"Expected the output buffer to be untouched\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
GetLastError());
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageW(FORMAT_MESSAGE_ARGUMENT_ARRAY, test, 0, 0, out, sizeof(out)/sizeof(WCHAR), NULL);
ok(ret == 0, "Expected FormatMessageW to return 0, got %u\n", ret);
ok(!memcmp(out, init_buf, sizeof(init_buf)),
"Expected the output buffer to be untouched\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
GetLastError());
SetLastError(0xdeadbeef);
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageW(FORMAT_MESSAGE_MAX_WIDTH_MASK, test, 0, 0, out, sizeof(out)/sizeof(WCHAR), NULL);
ok(ret == 0, "Expected FormatMessageW to return 0, got %u\n", ret);
ok(!memcmp(out, init_buf, sizeof(init_buf)),
"Expected the output buffer to be untouched\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER,
"Expected GetLastError() to return ERROR_INVALID_PARAMETER, got %u\n",
GetLastError());
/* Simultaneously setting FORMAT_MESSAGE_FROM_STRING with other source
* flags is apparently permissible, and FORMAT_MESSAGE_FROM_STRING takes
* precedence in this case. */
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_FROM_SYSTEM,
test, 0, 0, out, sizeof(out)/sizeof(WCHAR), NULL);
ok(ret == 4, "Expected FormatMessageW to return 4, got %u\n", ret);
ok(!lstrcmpW(test, out),
"Expected the output buffer to be untouched\n");
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_FROM_HMODULE,
test, 0, 0, out, sizeof(out)/sizeof(WCHAR), NULL);
ok(ret == 4, "Expected FormatMessageW to return 4, got %u\n", ret);
ok(!lstrcmpW(test, out),
"Expected the output buffer to be untouched\n");
memcpy(out, init_buf, sizeof(init_buf));
ret = FormatMessageW(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_FROM_SYSTEM, test, 0, 0, out,
sizeof(out)/sizeof(WCHAR), NULL);
ok(ret == 4, "Expected FormatMessageW to return 4, got %u\n", ret);
ok(!lstrcmpW(test, out),
"Expected the output buffer to be untouched\n");
}
START_TEST(format_msg)
{
test_message_from_string();
......@@ -1123,4 +1302,6 @@ START_TEST(format_msg)
test_message_allocate_buffer();
test_message_allocate_buffer_wide();
test_message_from_hmodule();
test_message_invalid_flags();
test_message_invalid_flags_wide();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment