summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorcpu@google.com <cpu@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-19 18:24:38 +0000
committercpu@google.com <cpu@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-19 18:24:38 +0000
commitf38b16fd2753b2d603e0a2a137227a132c77057b (patch)
tree47196cdec0752b96c5669830ba4ebc2bbad2c9ec /chrome
parent45aa74cc70c63a3a904007f9c84c1f73d9c2a35f (diff)
downloadchromium_src-f38b16fd2753b2d603e0a2a137227a132c77057b.zip
chromium_src-f38b16fd2753b2d603e0a2a137227a132c77057b.tar.gz
chromium_src-f38b16fd2753b2d603e0a2a137227a132c77057b.tar.bz2
Adds 'hard error' message box support
- Initially just the two failed to delay-load bind exceptions - Shows the same error dialog as the OS shows so no localization required TEST= hard to test, but I'll give some pointers on the bug BUG = 11919 Review URL: http://codereview.chromium.org/113492 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16391 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/app/breakpad_win.cc6
-rw-r--r--chrome/app/chrome_exe.vcproj8
-rw-r--r--chrome/app/hard_error_handler_win.cc122
-rw-r--r--chrome/app/hard_error_handler_win.h36
-rw-r--r--chrome/chrome.gyp2
5 files changed, 174 insertions, 0 deletions
diff --git a/chrome/app/breakpad_win.cc b/chrome/app/breakpad_win.cc
index 725b9a7..b2644ba 100644
--- a/chrome/app/breakpad_win.cc
+++ b/chrome/app/breakpad_win.cc
@@ -16,6 +16,7 @@
#include "base/string_util.h"
#include "base/win_util.h"
#include "chrome/app/google_update_client.h"
+#include "chrome/app/hard_error_handler_win.h"
#include "chrome/common/env_vars.h"
#include "chrome/installer/util/install_util.h"
#include "chrome/installer/util/google_update_settings.h"
@@ -119,6 +120,11 @@ struct CrashReporterInfo {
bool DumpDoneCallback(const wchar_t*, const wchar_t*, void*,
EXCEPTION_POINTERS* ex_info,
MDRawAssertionInfo*, bool) {
+ // If the exception is because there was a problem loading a delay-loaded
+ // module, then show the user a dialog explaining the problem and then exit.
+ if (DelayLoadFailureExceptionMessageBox(ex_info))
+ return true;
+
// We set CHROME_CRASHED env var. If the CHROME_RESTART is present.
// This signals the child process to show the 'chrome has crashed' dialog.
if (!::GetEnvironmentVariableW(env_vars::kRestartInfo, NULL, 0))
diff --git a/chrome/app/chrome_exe.vcproj b/chrome/app/chrome_exe.vcproj
index 7ac9ab4..d873dbb 100644
--- a/chrome/app/chrome_exe.vcproj
+++ b/chrome/app/chrome_exe.vcproj
@@ -223,6 +223,14 @@
>
</File>
<File
+ RelativePath=".\hard_error_handler_win.cc"
+ >
+ </File>
+ <File
+ RelativePath=".\hard_error_handler_win.h"
+ >
+ </File>
+ <File
RelativePath="..\common\result_codes.h"
>
</File>
diff --git a/chrome/app/hard_error_handler_win.cc b/chrome/app/hard_error_handler_win.cc
new file mode 100644
index 0000000..77a8f81
--- /dev/null
+++ b/chrome/app/hard_error_handler_win.cc
@@ -0,0 +1,122 @@
+// 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"
+
+#include <delayimp.h>
+#include <ntsecapi.h>
+#include <string>
+
+#include "base/basictypes.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;
+ uint32 str_size_bytes = str.size() * sizeof(wchar_t);
+ nt_string->Length = str_size_bytes;
+ nt_string->MaximumLength = 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;
+}
+
diff --git a/chrome/app/hard_error_handler_win.h b/chrome/app/hard_error_handler_win.h
new file mode 100644
index 0000000..51b16b45
--- /dev/null
+++ b/chrome/app/hard_error_handler_win.h
@@ -0,0 +1,36 @@
+// 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.
+
+// The routines in this file are windows-specific helper functions to deal
+// with critical errors which the user can do something about.
+
+#ifndef CHROME_APP_HARD_ERROR_HANDLER_WIN_H_
+#define CHROME_APP_HARD_ERROR_HANDLER_WIN_H_
+
+#include <windows.h>
+
+// Two exceptions can be thrown when delay-laoding DLLs:
+// - Failed to load a DLL. The common reason is because it cannot be found.
+// - Failed to bind to an entry point. Typically because the DLL is too old.
+// These exceptions cause the termination of the program, but it is desirable
+// to first inform the user the name of the module or the name of the entry
+// point so he or she can get help.
+// This function does exactly that. When an exception is captured and passed
+// to this function, it will display a message box with the relevant
+// information and return true if the exception is generated by the delay-load
+// feature or else do nothing and return false.
+bool DelayLoadFailureExceptionMessageBox(EXCEPTION_POINTERS* ex_info);
+
+// Generates a Popup dialog indicating that the entry point |entry| could
+// not be found in dll |module|. The dialog is generated by CSRSS so this
+// function can be called inside an exception handler.
+void EntryPointNotFoundHardError(const char* entry, const char* module);
+
+// Generates a Popup dialog indicating that the dll |module| could not be found.
+// The dialog is generated by CSRSS so this function can be called inside an
+// exception handler.
+void ModuleNotFoundHardError(const char* module);
+
+#endif // CHROME_APP_HARD_ERROR_HANDLER_WIN_H_
+
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 1ff13ed..be84b6a 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -1899,6 +1899,8 @@
'app/client_util.h',
'app/google_update_client.cc',
'app/google_update_client.h',
+ 'app/hard_error_handler_win.cc',
+ 'app/hard_error_handler_win.h',
'app/keystone_glue.h',
'app/keystone_glue.m',
'app/scoped_ole_initializer.h',