summaryrefslogtreecommitdiffstats
path: root/chrome/app/hard_error_handler_win.cc
blob: 77a8f81d5145a0c85c7d53c80e235cab938675c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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;
}