https://git.reactos.org/?p=reactos.git;a=commitdiff;h=29d56f2b296402179cf99…
commit 29d56f2b296402179cf99ffd654c6cd76876aa2e
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Fri Mar 23 23:50:50 2018 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Sat Apr 7 18:48:13 2018 +0200
[USERSRV] Hard-error improvements 7/7
- Use a more descriptive "unknown hard error" string than Windows' one.
- Improve the computation of the buffer size for the hard error message
by using _vscwprintf() instead of just "guessing" which size the fully
printf'ed message could be.
---
win32ss/user/winsrv/usersrv/harderror.c | 317 ++++++++++++++++++++------------
1 file changed, 201 insertions(+), 116 deletions(-)
diff --git a/win32ss/user/winsrv/usersrv/harderror.c
b/win32ss/user/winsrv/usersrv/harderror.c
index 9248d60f92..62864ca695 100644
--- a/win32ss/user/winsrv/usersrv/harderror.c
+++ b/win32ss/user/winsrv/usersrv/harderror.c
@@ -61,6 +61,28 @@ RtlLoadUnicodeString(
}
+/*
+ * NOTE: _scwprintf() is NOT exported by ntdll.dll,
+ * only _vscwprintf() is, so we need to implement it here.
+ * Code comes from sdk/lib/crt/printf/_scwprintf.c .
+ */
+int
+__cdecl
+_scwprintf(
+ const wchar_t *format,
+ ...)
+{
+ int len;
+ va_list args;
+
+ va_start(args, format);
+ len = _vscwprintf(format, args);
+ va_end(args);
+
+ return len;
+}
+
+
/* FIXME */
int
WINAPI
@@ -349,9 +371,18 @@ UserpFormatMessages(
OUT PULONG pdwTimeout,
IN PHARDERROR_MSG Message)
{
+ /* Special hardcoded messages */
+ static const PCWSTR pszUnknownHardError =
+ L"Unknown Hard Error 0x%08lx\n"
+ L"Parameters: 0x%p 0x%p 0x%p 0x%p";
+ static const PCWSTR pszExceptionHardError =
+ L"Exception processing message 0x%08lx\n"
+ L"Parameters: 0x%p 0x%p 0x%p 0x%p";
+
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE hProcess;
+ ULONG Severity = (ULONG)(Message->Status) >> 30;
ULONG SizeOfStrings;
ULONG_PTR Parameters[MAXIMUM_HARDERROR_PARAMETERS] = {0};
ULONG_PTR CopyParameters[MAXIMUM_HARDERROR_PARAMETERS];
@@ -361,8 +392,6 @@ UserpFormatMessages(
PMESSAGE_RESOURCE_ENTRY MessageResource;
PWSTR FormatString, pszBuffer;
size_t cszBuffer;
- ULONG Severity = (ULONG)(Message->Status) >> 30;
- ULONG Size;
/* Open client process */
InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
@@ -379,6 +408,13 @@ UserpFormatMessages(
/* Capture all string parameters from the process memory */
UserpCaptureStringParameters(Parameters, &SizeOfStrings, Message, hProcess);
+ /* Initialize the output strings */
+ TextStringU->Length = 0;
+ TextStringU->Buffer[0] = UNICODE_NULL;
+
+ CaptionStringU->Length = 0;
+ CaptionStringU->Buffer[0] = UNICODE_NULL;
+
/*
* Check whether it is a service notification, in which case
* we format the parameters and take the short route.
@@ -395,29 +431,15 @@ UserpFormatMessages(
*/
*pdwType = (UINT)Parameters[2] & ~MB_SERVICE_NOTIFICATION;
- /* Duplicate the UNICODE text message */
+ /*
+ * Duplicate the UNICODE text message and caption.
+ * If no strings or invalid ones have been provided, keep
+ * the original buffers and reset the string lengths to zero.
+ */
if (Message->UnicodeStringParameterMask & 0x1)
- {
- /* A string has been provided: duplicate it */
UserpDuplicateParamStringToUnicodeString(TextStringU,
(PCWSTR)Parameters[0]);
- }
- else
- {
- /* No string (or invalid one) has been provided: keep the original buffer and
reset the string length to zero */
- TextStringU->Length = 0;
- }
-
- /* Duplicate the UNICODE caption */
if (Message->UnicodeStringParameterMask & 0x2)
- {
- /* A string has been provided: duplicate it */
UserpDuplicateParamStringToUnicodeString(CaptionStringU,
(PCWSTR)Parameters[1]);
- }
- else
- {
- /* No string (or invalid one) has been provided: keep the original buffer and
reset the string length to zero */
- CaptionStringU->Length = 0;
- }
/* Set the timeout */
if (Message->NumberOfParameters >= 4)
@@ -493,7 +515,8 @@ UserpFormatMessages(
FileNameU = g_SystemProcessU;
}
- /* Get text string of the error code */
+ /* Retrieve the description of the error code */
+ FormatA.Buffer = NULL;
Status = RtlFindMessage(GetModuleHandleW(L"ntdll"),
(ULONG_PTR)RT_MESSAGETABLE,
LANG_NEUTRAL,
@@ -511,41 +534,40 @@ UserpFormatMessages(
RtlInitAnsiString(&FormatA, (PSTR)MessageResource->Text);
/* Status = */ RtlAnsiStringToUnicodeString(&FormatU, &FormatA,
TRUE);
}
+ ASSERT(FormatU.Buffer);
}
else
{
/*
- * Fall back to hardcoded value.
+ * Fall back to unknown hard error format string.
* NOTE: The value used here is ReactOS-specific: it allows specifying
- * the exact hard error status value and the parameters. The version
- * used on Windows only says "Unknown Hard Error".
+ * the exact hard error status value and the parameters, contrary to
+ * the one on Windows which only says: "Unknown Hard Error".
*/
-#if 0
- RtlInitUnicodeString(&FormatU, L"Unknown Hard Error 0x%08lx\n"
- L"Parameters: 0x%p 0x%p 0x%p 0x%p");
-#else
- RtlInitUnicodeString(&FormatU, L"Unknown Hard Error 0x%08lx");
- CopyParameters[0] = Message->Status;
-#endif
+ RtlInitEmptyUnicodeString(&FormatU, NULL, 0);
FormatA.Buffer = NULL;
}
FormatString = FormatU.Buffer;
- /* Check whether a caption exists */
- if (FormatString[0] == L'{')
+ /* Check whether a caption is specified in the format string */
+ if (FormatString && FormatString[0] == L'{')
{
/* Set caption start */
TempStringU.Buffer = ++FormatString;
- /* Get size of the caption */
- for (Size = 0; *FormatString != UNICODE_NULL && *FormatString !=
L'}'; Size++)
- FormatString++;
+ /* Get the caption size and find where the format string really starts */
+ for (TempStringU.Length = 0;
+ *FormatString != UNICODE_NULL && *FormatString != L'}';
+ ++TempStringU.Length)
+ {
+ ++FormatString;
+ }
/* Skip '}', '\r', '\n' */
FormatString += 3;
- TempStringU.Length = (USHORT)(Size * sizeof(WCHAR));
+ TempStringU.Length *= sizeof(WCHAR);
TempStringU.MaximumLength = TempStringU.Length;
}
else
@@ -612,6 +634,7 @@ UserpFormatMessages(
}
}
CaptionStringU->Length = 0;
+ CaptionStringU->Buffer[0] = UNICODE_NULL;
/* Append the file name, the separator and the caption text */
RtlStringCbPrintfW(CaptionStringU->Buffer,
@@ -620,19 +643,22 @@ UserpFormatMessages(
&WindowTitleU, &FileNameU, &TempStringU);
CaptionStringU->Length = (USHORT)(wcslen(CaptionStringU->Buffer) *
sizeof(WCHAR));
- /* Free string buffers if needed */
+ /* Free the strings if needed */
if (WindowTitleU.Buffer) RtlFreeUnicodeString(&WindowTitleU);
if (hProcess) RtlFreeUnicodeString(&FileNameU);
- // FIXME: What is 42 == ??
- Size = 42;
+ Format2A.Buffer = NULL;
+
+ /* If we have an unknown hard error, skip the special cases handling */
+ if (!FormatString)
+ goto BuildMessage;
/* Check if this is an exception message */
if (Message->Status == STATUS_UNHANDLED_EXCEPTION)
{
ULONG ExceptionCode = CopyParameters[0];
- /* Get text string of the exception code */
+ /* Retrieve the description of the exception code */
Status = RtlFindMessage(GetModuleHandleW(L"ntdll"),
(ULONG_PTR)RT_MESSAGETABLE,
LANG_NEUTRAL,
@@ -650,10 +676,12 @@ UserpFormatMessages(
RtlInitAnsiString(&Format2A, (PSTR)MessageResource->Text);
/* Status = */ RtlAnsiStringToUnicodeString(&Format2U, &Format2A,
TRUE);
}
+ ASSERT(Format2U.Buffer);
/* Handle special cases */
if (ExceptionCode == STATUS_ACCESS_VIOLATION)
{
+ /* Use a new FormatString */
FormatString = Format2U.Buffer;
CopyParameters[0] = CopyParameters[1];
CopyParameters[1] = CopyParameters[3];
@@ -664,6 +692,7 @@ UserpFormatMessages(
}
else if (ExceptionCode == STATUS_IN_PAGE_ERROR)
{
+ /* Use a new FormatString */
FormatString = Format2U.Buffer;
CopyParameters[0] = CopyParameters[1];
CopyParameters[1] = CopyParameters[3];
@@ -702,24 +731,64 @@ UserpFormatMessages(
CopyParameters[1] = CopyParameters[0];
CopyParameters[0] = (ULONG_PTR)L"unknown software exception";
}
+ }
- /* Add explanation text for dialog buttons */
- if (Message->ValidResponseOptions == OptionOk ||
- Message->ValidResponseOptions == OptionOkCancel)
+BuildMessage:
+ /*
+ * Calculate buffer length for the text message. If FormatString
+ * is NULL this means we have an unknown hard error whose format
+ * string is in FormatU.
+ */
+ cszBuffer = 0;
+ /* Wrap in SEH to protect from invalid string parameters */
+ _SEH2_TRY
+ {
+ if (!FormatString)
{
- /* Reserve space for one newline and the OK-terminate-program string */
- Size += 1 + (g_OKTerminateU.Length / sizeof(WCHAR));
+ /* Fall back to unknown hard error format string, and use the original
parameters */
+ cszBuffer = _scwprintf(pszUnknownHardError,
+ Message->Status,
+ Parameters[0], Parameters[1],
+ Parameters[2], Parameters[3]);
+ cszBuffer *= sizeof(WCHAR);
}
- if (Message->ValidResponseOptions == OptionOkCancel)
+ else
{
- /* Reserve space for one newline and the CANCEL-debug-program string */
- Size += 1 + (g_CancelDebugU.Length / sizeof(WCHAR));
+ cszBuffer = _scwprintf(FormatString,
+ CopyParameters[0], CopyParameters[1],
+ CopyParameters[2], CopyParameters[3]);
+ cszBuffer *= sizeof(WCHAR);
+
+ /* Add a description for the dialog buttons */
+ if (Message->Status == STATUS_UNHANDLED_EXCEPTION)
+ {
+ if (Message->ValidResponseOptions == OptionOk ||
+ Message->ValidResponseOptions == OptionOkCancel)
+ {
+ /* Reserve space for one newline and the OK-terminate-program string
*/
+ cszBuffer += sizeof(WCHAR) + g_OKTerminateU.Length;
+ }
+ if (Message->ValidResponseOptions == OptionOkCancel)
+ {
+ /* Reserve space for one newline and the CANCEL-debug-program string
*/
+ cszBuffer += sizeof(WCHAR) + g_CancelDebugU.Length;
+ }
+ }
}
}
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* An exception occurred, use a default string with the original parameters */
+ cszBuffer = _scwprintf(pszExceptionHardError,
+ Message->Status,
+ Parameters[0], Parameters[1],
+ Parameters[2], Parameters[3]);
+ cszBuffer *= sizeof(WCHAR);
+ }
+ _SEH2_END;
+
+ cszBuffer += SizeOfStrings + sizeof(UNICODE_NULL);
- /* Calculate buffer length for the text message */
- cszBuffer = FormatU.Length + SizeOfStrings + Size * sizeof(WCHAR) +
- sizeof(UNICODE_NULL);
if (TextStringU->MaximumLength < cszBuffer)
{
/* Allocate a larger buffer for the text message */
@@ -737,6 +806,7 @@ UserpFormatMessages(
}
}
TextStringU->Length = 0;
+ TextStringU->Buffer[0] = UNICODE_NULL;
/* Wrap in SEH to protect from invalid string parameters */
_SEH2_TRY
@@ -744,32 +814,45 @@ UserpFormatMessages(
/* Print the string into the buffer */
pszBuffer = TextStringU->Buffer;
cszBuffer = TextStringU->MaximumLength;
- RtlStringCbPrintfExW(pszBuffer, cszBuffer,
- &pszBuffer, &cszBuffer,
- STRSAFE_IGNORE_NULLS,
- FormatString,
- CopyParameters[0], CopyParameters[1],
- CopyParameters[2], CopyParameters[3]);
-
- /* Add explanation text for dialog buttons */
- if (Message->Status == STATUS_UNHANDLED_EXCEPTION)
+
+ if (!FormatString)
{
- if (Message->ValidResponseOptions == OptionOk ||
- Message->ValidResponseOptions == OptionOkCancel)
- {
- RtlStringCbPrintfExW(pszBuffer, cszBuffer,
- &pszBuffer, &cszBuffer,
- STRSAFE_IGNORE_NULLS,
- L"\n%wZ",
- &g_OKTerminateU);
- }
- if (Message->ValidResponseOptions == OptionOkCancel)
+ /* Fall back to unknown hard error format string, and use the original
parameters */
+ RtlStringCbPrintfW(pszBuffer, cszBuffer,
+ pszUnknownHardError,
+ Message->Status,
+ Parameters[0], Parameters[1],
+ Parameters[2], Parameters[3]);
+ }
+ else
+ {
+ RtlStringCbPrintfExW(pszBuffer, cszBuffer,
+ &pszBuffer, &cszBuffer,
+ 0,
+ FormatString,
+ CopyParameters[0], CopyParameters[1],
+ CopyParameters[2], CopyParameters[3]);
+
+ /* Add a description for the dialog buttons */
+ if (Message->Status == STATUS_UNHANDLED_EXCEPTION)
{
- RtlStringCbPrintfExW(pszBuffer, cszBuffer,
- &pszBuffer, &cszBuffer,
- STRSAFE_IGNORE_NULLS,
- L"\n%wZ",
- &g_CancelDebugU);
+ if (Message->ValidResponseOptions == OptionOk ||
+ Message->ValidResponseOptions == OptionOkCancel)
+ {
+ RtlStringCbPrintfExW(pszBuffer, cszBuffer,
+ &pszBuffer, &cszBuffer,
+ 0,
+ L"\n%wZ",
+ &g_OKTerminateU);
+ }
+ if (Message->ValidResponseOptions == OptionOkCancel)
+ {
+ RtlStringCbPrintfExW(pszBuffer, cszBuffer,
+ &pszBuffer, &cszBuffer,
+ 0,
+ L"\n%wZ",
+ &g_CancelDebugU);
+ }
}
}
}
@@ -781,8 +864,7 @@ UserpFormatMessages(
RtlStringCbPrintfW(TextStringU->Buffer,
TextStringU->MaximumLength,
- L"Exception processing message 0x%08lx\n"
- L"Parameters: 0x%p 0x%p 0x%p 0x%p",
+ pszExceptionHardError,
Message->Status,
Parameters[0], Parameters[1],
Parameters[2], Parameters[3]);
@@ -791,12 +873,12 @@ UserpFormatMessages(
TextStringU->Length = (USHORT)(wcslen(TextStringU->Buffer) * sizeof(WCHAR));
- /* Free converted Unicode strings */
+ /* Free the converted UNICODE strings */
if (Format2A.Buffer) RtlFreeUnicodeString(&Format2U);
if (FormatA.Buffer) RtlFreeUnicodeString(&FormatU);
Quit:
- /* Final cleanup */
+ /* Free the captured parameters */
UserpFreeStringParameters(Parameters, Message);
}
@@ -850,40 +932,43 @@ GetRegInt(
static BOOL
UserpShowInformationBalloon(
- IN PCWSTR Text,
- IN PCWSTR Caption,
- IN UINT Type,
+ IN PUNICODE_STRING TextStringU,
+ IN PUNICODE_STRING CaptionStringU,
+ IN UINT Type,
IN PHARDERROR_MSG Message)
{
ULONG ShellErrorMode;
- HWND hwnd;
+ HWND hWndTaskman;
COPYDATASTRUCT CopyData;
PBALLOON_HARD_ERROR_DATA pdata;
DWORD dwSize, cbTextLen, cbTitleLen;
PWCHAR pText, pCaption;
- DWORD ret, dwResult;
+ DWORD ret;
+ DWORD_PTR dwResult;
/* Query the shell error mode value */
ShellErrorMode =
GetRegInt(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Windows",
L"ShellErrorMode", 0);
- /* Make the shell display the hard error message in balloon only if necessary */
+ /* Make the shell display the hard error message only if necessary */
if (ShellErrorMode != 1)
return FALSE;
- hwnd = GetTaskmanWindow();
- if (!hwnd)
+ /* Retrieve the shell task window */
+ hWndTaskman = GetTaskmanWindow();
+ if (!hWndTaskman)
{
DPRINT1("Failed to find shell task window (last error %lu)\n",
GetLastError());
return FALSE;
}
- cbTextLen = ((Text ? wcslen(Text) : 0) + 1) * sizeof(WCHAR);
- cbTitleLen = ((Caption ? wcslen(Caption) : 0) + 1) * sizeof(WCHAR);
+ cbTextLen = TextStringU->Length + sizeof(UNICODE_NULL);
+ cbTitleLen = CaptionStringU->Length + sizeof(UNICODE_NULL);
dwSize = sizeof(BALLOON_HARD_ERROR_DATA);
dwSize += cbTextLen + cbTitleLen;
+ /* Build the data buffer */
pdata = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
if (!pdata)
{
@@ -893,31 +978,27 @@ UserpShowInformationBalloon(
pdata->cbHeaderSize = sizeof(BALLOON_HARD_ERROR_DATA);
pdata->Status = Message->Status;
+ pdata->dwType = Type;
- if (NT_SUCCESS(Message->Status))
- pdata->dwType = MB_OK;
- else if (Message->Status == STATUS_SERVICE_NOTIFICATION)
- pdata->dwType = Type;
- else
- pdata->dwType = MB_ICONINFORMATION;
-
- pdata->TitleOffset = pdata->cbHeaderSize;
- pdata->MessageOffset = pdata->TitleOffset;
- pdata->MessageOffset += cbTitleLen;
+ pdata->TitleOffset = pdata->cbHeaderSize;
+ pdata->MessageOffset = pdata->TitleOffset + cbTitleLen;
pCaption = (PWCHAR)((ULONG_PTR)pdata + pdata->TitleOffset);
pText = (PWCHAR)((ULONG_PTR)pdata + pdata->MessageOffset);
- wcscpy(pCaption, Caption);
- wcscpy(pText, Text);
+ RtlStringCbCopyNW(pCaption, cbTitleLen, CaptionStringU->Buffer,
CaptionStringU->Length);
+ RtlStringCbCopyNW(pText, cbTextLen, TextStringU->Buffer, TextStringU->Length);
+
+ /* Send the message */
+ /* Retrieve a unique system-wide message to communicate hard error data with the
shell */
CopyData.dwData = RegisterWindowMessageW(L"HardError");
CopyData.cbData = dwSize;
CopyData.lpData = pdata;
dwResult = FALSE;
-
- ret = SendMessageTimeoutW(hwnd, WM_COPYDATA, 0, (LPARAM)&CopyData,
+ ret = SendMessageTimeoutW(hWndTaskman, WM_COPYDATA, 0, (LPARAM)&CopyData,
SMTO_NORMAL | SMTO_ABORTIFHUNG, 3000, &dwResult);
+ /* Free the buffer */
RtlFreeHeap(RtlGetProcessHeap(), 0, pdata);
return (ret && dwResult) ? TRUE : FALSE;
@@ -926,18 +1007,21 @@ UserpShowInformationBalloon(
static
HARDERROR_RESPONSE
UserpMessageBox(
- IN PCWSTR Text,
- IN PCWSTR Caption,
- IN UINT Type,
- IN ULONG Timeout)
+ IN PUNICODE_STRING TextStringU,
+ IN PUNICODE_STRING CaptionStringU,
+ IN UINT Type,
+ IN ULONG Timeout)
{
ULONG MessageBoxResponse;
DPRINT("Text = '%S', Caption = '%S', Type = 0x%lx\n",
- Text, Caption, Type);
+ TextStringU->Buffer, CaptionStringU->Buffer, Type);
/* Display a message box */
- MessageBoxResponse = MessageBoxTimeoutW(NULL, Text, Caption, Type, 0, Timeout);
+ MessageBoxResponse = MessageBoxTimeoutW(NULL,
+ TextStringU->Buffer,
+ CaptionStringU->Buffer,
+ Type, 0, Timeout);
/* Return response value */
switch (MessageBoxResponse)
@@ -1028,7 +1112,8 @@ UserServerHardError(
{
if (Message->NumberOfParameters < 3)
{
- DPRINT1("Invalid NumberOfParameters = %d for
STATUS_SERVICE_NOTIFICATION\n", Message->NumberOfParameters);
+ DPRINT1("Invalid NumberOfParameters = %d for
STATUS_SERVICE_NOTIFICATION\n",
+ Message->NumberOfParameters);
return; // STATUS_INVALID_PARAMETER;
}
// (Message->UnicodeStringParameterMask & 0x3)
@@ -1062,8 +1147,8 @@ UserServerHardError(
{
/* Display the balloon */
Message->Response = ResponseOk;
- if (UserpShowInformationBalloon(TextU.Buffer,
- CaptionU.Buffer,
+ if (UserpShowInformationBalloon(&TextU,
+ &CaptionU,
dwType,
Message))
{
@@ -1073,8 +1158,8 @@ UserServerHardError(
}
/* Display the message box */
- Message->Response = UserpMessageBox(TextU.Buffer,
- CaptionU.Buffer,
+ Message->Response = UserpMessageBox(&TextU,
+ &CaptionU,
dwType,
Timeout);