| // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/app/hard_error_handler_win.h" |
| |
| #if defined(_WIN32_WINNT_WIN8) |
| // The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h. |
| #undef FACILITY_VISUALCPP |
| #endif |
| #include <DelayIMP.h> |
| |
| #include <ntsecapi.h> |
| #include <string> |
| |
| #include "base/basictypes.h" |
| #include "base/logging.h" |
| #include "base/string_piece.h" |
| #include "base/sys_string_conversions.h" |
| |
| namespace { |
| |
| const int32 kExceptionModuleNotFound = VcppException(ERROR_SEVERITY_ERROR, |
| ERROR_MOD_NOT_FOUND); |
| const int32 kExceptionEntryPtNotFound = VcppException(ERROR_SEVERITY_ERROR, |
| ERROR_PROC_NOT_FOUND); |
| |
| const int32 NT_STATUS_ENTRYPOINT_NOT_FOUND = 0xC0000139; |
| const int32 NT_STATUS_DLL_NOT_FOUND = 0xC0000135; |
| |
| bool MakeNTUnicodeString(const std::wstring& str, |
| UNICODE_STRING* nt_string) { |
| if (str.empty()) |
| return false; |
| size_t str_size_bytes = str.size() * sizeof(wchar_t); |
| if (kuint16max < str_size_bytes) { |
| // The string is too long - nt_string->Length is USHORT |
| NOTREACHED() << "The string is too long"; |
| return false; |
| } |
| nt_string->Length = static_cast<USHORT>(str_size_bytes); |
| nt_string->MaximumLength = static_cast<USHORT>(str_size_bytes); |
| nt_string->Buffer = const_cast<wchar_t*>(str.c_str()); |
| return true; |
| } |
| |
| // NT-level function (not a win32 api) used to tell CSRSS of a critical error |
| // in the program which results in a message box dialog. |
| // The |exception| parameter is a standard exception code, the |param_count| |
| // indicates the number of items in |payload_params|. |payload_params| is |
| // dependent on the |exception| type but is typically an array to pointers to |
| // strings. |error_mode| indicates the kind of dialog buttons to show. |
| typedef LONG (WINAPI *NtRaiseHardErrorPF)(LONG exception, |
| ULONG param_count, |
| ULONG undocumented, |
| PVOID payload_params, |
| UINT error_mode, |
| PULONG response); |
| |
| // Helper function to call NtRaiseHardError(). It takes the exception code |
| // and one or two strings which are dependent on the exception code. No |
| // effort is done to validate that they match. |
| void RaiseHardErrorMsg(int32 exception, const std::wstring& text1, |
| const std::wstring& text2) { |
| // Bind the entry point. We can do it here since this function is really |
| // called at most once per session. Usually never called. |
| NtRaiseHardErrorPF NtRaiseHardError = |
| reinterpret_cast<NtRaiseHardErrorPF>( |
| ::GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtRaiseHardError")); |
| if (!NtRaiseHardError) |
| return; |
| |
| UNICODE_STRING uni_str1; |
| UNICODE_STRING uni_str2; |
| // A message needs to be displayed or else it would be confusing to the user. |
| if (!MakeNTUnicodeString(text1, &uni_str1)) |
| return; |
| int num_params = 1; |
| // The second string is optional. |
| if (MakeNTUnicodeString(text2, &uni_str2)) |
| num_params = 2; |
| |
| UNICODE_STRING* args[] = {&uni_str1, &uni_str2}; |
| uint32 undoc_value = 3; // Display message to user. |
| uint32 error_mode = 1; // Display OK button only. |
| ULONG response; // What user clicked in the dialog. Discarded. |
| NtRaiseHardError(exception, num_params, 3, args, error_mode, &response); |
| } |
| |
| } // namespace. |
| |
| // Using RaiseHardErrorMsg(), it generates the same message box that is seen |
| // when the loader cannot find a DLL that a module depends on. |module| is the |
| // DLL name and it cannot be empty. The Message box only has an 'ok' button. |
| void ModuleNotFoundHardError(const char* module) { |
| if (!module) |
| return; |
| std::wstring mod_name(base::SysMultiByteToWide(module, CP_ACP)); |
| RaiseHardErrorMsg(NT_STATUS_DLL_NOT_FOUND, mod_name, std::wstring()); |
| } |
| |
| // Using RaiseHardErrorMsg(), it generates the same message box that seen |
| // when the loader cannot find an import a module depends on. |module| is the |
| // DLL name and it cannot be empty. |entry| is the name of the method that |
| // could not be found. The Message box only has an 'ok' button. |
| void EntryPointNotFoundHardError(const char* entry, const char* module) { |
| if (!module || !entry) |
| return; |
| std::wstring entry_point(base::SysMultiByteToWide(entry, CP_ACP)); |
| std::wstring mod_name(base::SysMultiByteToWide(module, CP_ACP)); |
| RaiseHardErrorMsg(NT_STATUS_ENTRYPOINT_NOT_FOUND, entry_point, mod_name); |
| } |
| |
| bool DelayLoadFailureExceptionMessageBox(EXCEPTION_POINTERS* ex_info) { |
| if (!ex_info) |
| return false; |
| DelayLoadInfo* dli = reinterpret_cast<DelayLoadInfo*>( |
| ex_info->ExceptionRecord->ExceptionInformation[0]); |
| if (!dli) |
| return false; |
| if (ex_info->ExceptionRecord->ExceptionCode == kExceptionModuleNotFound) { |
| ModuleNotFoundHardError(dli->szDll); |
| return true; |
| } |
| if (ex_info->ExceptionRecord->ExceptionCode == kExceptionEntryPtNotFound) { |
| if (dli->dlp.fImportByName) { |
| EntryPointNotFoundHardError(dli->dlp.szProcName, dli->szDll); |
| return true; |
| } |
| } |
| return false; |
| } |
| |