Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(179)

Side by Side Diff: components/breakpad/app/breakpad_win.cc

Issue 302033002: Refactor the breakpad Windows key/value stash, step one. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/breakpad/app/breakpad_win.h" 5 #include "components/breakpad/app/breakpad_win.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <shellapi.h> 8 #include <shellapi.h>
9 #include <tchar.h> 9 #include <tchar.h>
10 #include <userenv.h> 10 #include <userenv.h>
11 #include <winnt.h> 11 #include <winnt.h>
12 12
13 #include <algorithm> 13 #include <algorithm>
14 #include <map>
14 #include <vector> 15 #include <vector>
15 16
16 #include "base/base_switches.h" 17 #include "base/base_switches.h"
17 #include "base/basictypes.h" 18 #include "base/basictypes.h"
18 #include "base/command_line.h" 19 #include "base/command_line.h"
19 #include "base/debug/crash_logging.h" 20 #include "base/debug/crash_logging.h"
20 #include "base/debug/dump_without_crashing.h" 21 #include "base/debug/dump_without_crashing.h"
21 #include "base/environment.h" 22 #include "base/environment.h"
22 #include "base/memory/scoped_ptr.h" 23 #include "base/memory/scoped_ptr.h"
23 #include "base/strings/string16.h" 24 #include "base/strings/string16.h"
(...skipping 14 matching lines...) Expand all
38 #include "sandbox/win/src/sidestep/preamble_patcher.h" 39 #include "sandbox/win/src/sidestep/preamble_patcher.h"
39 40
40 // userenv.dll is required for GetProfileType(). 41 // userenv.dll is required for GetProfileType().
41 #pragma comment(lib, "userenv.lib") 42 #pragma comment(lib, "userenv.lib")
42 43
43 #pragma intrinsic(_AddressOfReturnAddress) 44 #pragma intrinsic(_AddressOfReturnAddress)
44 #pragma intrinsic(_ReturnAddress) 45 #pragma intrinsic(_ReturnAddress)
45 46
46 namespace breakpad { 47 namespace breakpad {
47 48
48 std::vector<google_breakpad::CustomInfoEntry>* g_custom_entries = NULL; 49 // Manages the breakpad key/value pair stash, there may only be one instance
50 // of this class per process at one time.
51 // Exposed for testing only.
52 class KeyValuePairKeeper {
Robert Sesek 2014/05/29 20:34:41 Not quite a fan of this name. Perhaps CustomInfoMa
Sigurður Ásgeirsson 2014/05/30 15:14:49 Yeah, me neither :/. You know of course that there
53 public:
54 KeyValuePairKeeper();
55 ~KeyValuePairKeeper();
56
57 // May only be called once.
58 google_breakpad::CustomClientInfo*
59 GetCustomInfo(const std::wstring& exe_path, const std::wstring& type);
60
61 void SetCrashKeyValue(const std::wstring& key, const std::wstring& value);
62 void ClearCrashKeyValue(const std::wstring& key);
63
64 static KeyValuePairKeeper* keeper() { return keeper_; }
65
66 private:
67 // Sets private
Robert Sesek 2014/05/29 20:34:41 Incomplete comment?
Sigurður Ásgeirsson 2014/05/30 15:14:49 Done.
68 void SetPluginPath(const std::wstring& path);
69 void SetBreakpadDumpPath();
70
71 // Must not be resized after GetCustomInfo is invoked.
72 std::vector<google_breakpad::CustomInfoEntry> custom_entries_;
73
74 typedef std::map<std::wstring, google_breakpad::CustomInfoEntry*>
75 DynamicEntriesMap;
76 base::Lock lock_;
77 // Keeps track of the next index for a new dynamic entry.
78 size_t dynamic_keys_offset_; // Under lock_.
79 // Maintains key->entry information for dynamic key/value entries
80 // in custom_entries_.
81 DynamicEntriesMap dynamic_entries_; // Under lock_.
82
83 // Stores the sole instance of this class allowed per process.
84 static KeyValuePairKeeper* keeper_;
85 };
86
87 KeyValuePairKeeper* KeyValuePairKeeper::keeper_;
88
89 KeyValuePairKeeper::KeyValuePairKeeper() : dynamic_keys_offset_(0) {
90 DCHECK_EQ(static_cast<KeyValuePairKeeper*>(NULL), keeper_);
91
Robert Sesek 2014/05/29 20:34:41 nit: remove blank line
Sigurður Ásgeirsson 2014/05/30 15:14:49 Done.
92 keeper_ = this;
93 }
94
95 KeyValuePairKeeper::~KeyValuePairKeeper() {
96 DCHECK_EQ(this, keeper_);
97 keeper_ = NULL;
98 }
49 99
50 namespace { 100 namespace {
51 101
52 // Minidump with stacks, PEB, TEB, and unloaded module list. 102 // Minidump with stacks, PEB, TEB, and unloaded module list.
53 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>( 103 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
54 MiniDumpWithProcessThreadData | // Get PEB and TEB. 104 MiniDumpWithProcessThreadData | // Get PEB and TEB.
55 MiniDumpWithUnloadedModules); // Get unloaded modules when available. 105 MiniDumpWithUnloadedModules); // Get unloaded modules when available.
56 106
57 // Minidump with all of the above, plus memory referenced from stack. 107 // Minidump with all of the above, plus memory referenced from stack.
58 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( 108 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>(
(...skipping 20 matching lines...) Expand all
79 google_breakpad::ExceptionHandler* g_dumphandler_no_crash = NULL; 129 google_breakpad::ExceptionHandler* g_dumphandler_no_crash = NULL;
80 130
81 EXCEPTION_POINTERS g_surrogate_exception_pointers = {0}; 131 EXCEPTION_POINTERS g_surrogate_exception_pointers = {0};
82 EXCEPTION_RECORD g_surrogate_exception_record = {0}; 132 EXCEPTION_RECORD g_surrogate_exception_record = {0};
83 CONTEXT g_surrogate_context = {0}; 133 CONTEXT g_surrogate_context = {0};
84 134
85 typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle, 135 typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle,
86 NTSTATUS ExitStatus); 136 NTSTATUS ExitStatus);
87 char* g_real_terminate_process_stub = NULL; 137 char* g_real_terminate_process_stub = NULL;
88 138
89 base::Lock* g_dynamic_entries_lock = NULL;
90 // Under *g_dynamic_entries_lock.
91 size_t g_dynamic_keys_offset = 0;
92 typedef std::map<std::wstring, google_breakpad::CustomInfoEntry*>
93 DynamicEntriesMap;
94 // Under *g_dynamic_entries_lock.
95 DynamicEntriesMap* g_dynamic_entries = NULL;
96 139
97 // Allow for 256 dynamic entries in addition to the fixed set of entries 140 // Allow for 256 dynamic entries in addition to the fixed set of entries
98 // set up in this file. 141 // set up in this file.
99 const size_t kMaxDynamicEntries = 256; 142 const size_t kMaxDynamicEntries = 256;
100 143
101 // Maximum length for plugin path to include in plugin crash reports. 144 // Maximum length for plugin path to include in plugin crash reports.
102 const size_t kMaxPluginPathLength = 256; 145 const size_t kMaxPluginPathLength = 256;
103 146
147 } // namespace
148
104 // Dumps the current process memory. 149 // Dumps the current process memory.
105 extern "C" void __declspec(dllexport) __cdecl DumpProcess() { 150 extern "C" void __declspec(dllexport) __cdecl DumpProcess() {
106 if (g_breakpad) { 151 if (g_breakpad) {
107 g_breakpad->WriteMinidump(); 152 g_breakpad->WriteMinidump();
108 } 153 }
109 } 154 }
110 155
111 // Used for dumping a process state when there is no crash. 156 // Used for dumping a process state when there is no crash.
112 extern "C" void __declspec(dllexport) __cdecl DumpProcessWithoutCrash() { 157 extern "C" void __declspec(dllexport) __cdecl DumpProcessWithoutCrash() {
113 if (g_dumphandler_no_crash) { 158 if (g_dumphandler_no_crash) {
114 g_dumphandler_no_crash->WriteMinidump(); 159 g_dumphandler_no_crash->WriteMinidump();
115 } 160 }
116 } 161 }
117 162
163 namespace {
164
118 // We need to prevent ICF from folding DumpForHangDebuggingThread() and 165 // We need to prevent ICF from folding DumpForHangDebuggingThread() and
119 // DumpProcessWithoutCrashThread() together, since that makes them 166 // DumpProcessWithoutCrashThread() together, since that makes them
120 // indistinguishable in crash dumps. We do this by making the function 167 // indistinguishable in crash dumps. We do this by making the function
121 // bodies unique, and prevent optimization from shuffling things around. 168 // bodies unique, and prevent optimization from shuffling things around.
122 MSVC_DISABLE_OPTIMIZE() 169 MSVC_DISABLE_OPTIMIZE()
123 MSVC_PUSH_DISABLE_WARNING(4748) 170 MSVC_PUSH_DISABLE_WARNING(4748)
124 171
125 DWORD WINAPI DumpProcessWithoutCrashThread(void*) { 172 DWORD WINAPI DumpProcessWithoutCrashThread(void*) {
126 DumpProcessWithoutCrash(); 173 DumpProcessWithoutCrash();
127 return 0; 174 return 0;
128 } 175 }
129 176
130 // The following two functions do exactly the same thing as the two above. But 177 // The following two functions do exactly the same thing as the two above. But
131 // we want the signatures to be different so that we can easily track them in 178 // we want the signatures to be different so that we can easily track them in
132 // crash reports. 179 // crash reports.
133 // TODO(yzshen): Remove when enough information is collected and the hang rate 180 // TODO(yzshen): Remove when enough information is collected and the hang rate
134 // of pepper/renderer processes is reduced. 181 // of pepper/renderer processes is reduced.
135 DWORD WINAPI DumpForHangDebuggingThread(void*) { 182 DWORD WINAPI DumpForHangDebuggingThread(void*) {
136 DumpProcessWithoutCrash(); 183 DumpProcessWithoutCrash();
137 VLOG(1) << "dumped for hang debugging"; 184 VLOG(1) << "dumped for hang debugging";
138 return 0; 185 return 0;
139 } 186 }
140 187
141 MSVC_POP_WARNING() 188 MSVC_POP_WARNING()
142 MSVC_ENABLE_OPTIMIZE() 189 MSVC_ENABLE_OPTIMIZE()
143 190
191 } // namespace
192
144 // Injects a thread into a remote process to dump state when there is no crash. 193 // Injects a thread into a remote process to dump state when there is no crash.
145 extern "C" HANDLE __declspec(dllexport) __cdecl 194 extern "C" HANDLE __declspec(dllexport) __cdecl
146 InjectDumpProcessWithoutCrash(HANDLE process) { 195 InjectDumpProcessWithoutCrash(HANDLE process) {
147 return CreateRemoteThread(process, NULL, 0, DumpProcessWithoutCrashThread, 196 return CreateRemoteThread(process, NULL, 0, DumpProcessWithoutCrashThread,
148 0, 0, NULL); 197 0, 0, NULL);
149 } 198 }
150 199
151 extern "C" HANDLE __declspec(dllexport) __cdecl 200 extern "C" HANDLE __declspec(dllexport) __cdecl
152 InjectDumpForHangDebugging(HANDLE process) { 201 InjectDumpForHangDebugging(HANDLE process) {
153 return CreateRemoteThread(process, NULL, 0, DumpForHangDebuggingThread, 202 return CreateRemoteThread(process, NULL, 0, DumpForHangDebuggingThread,
154 0, 0, NULL); 203 0, 0, NULL);
155 } 204 }
156 205
157 // Appends the plugin path to |g_custom_entries|. 206 // Appends the plugin path to |g_custom_entries|.
158 void SetPluginPath(const std::wstring& path) { 207 void KeyValuePairKeeper::SetPluginPath(const std::wstring& path) {
159 DCHECK(g_custom_entries);
160
161 if (path.size() > kMaxPluginPathLength) { 208 if (path.size() > kMaxPluginPathLength) {
162 // If the path is too long, truncate from the start rather than the end, 209 // If the path is too long, truncate from the start rather than the end,
163 // since we want to be able to recover the DLL name. 210 // since we want to be able to recover the DLL name.
164 SetPluginPath(path.substr(path.size() - kMaxPluginPathLength)); 211 SetPluginPath(path.substr(path.size() - kMaxPluginPathLength));
165 return; 212 return;
166 } 213 }
167 214
168 // The chunk size without terminator. 215 // The chunk size without terminator.
169 const size_t kChunkSize = static_cast<size_t>( 216 const size_t kChunkSize = static_cast<size_t>(
170 google_breakpad::CustomInfoEntry::kValueMaxLength - 1); 217 google_breakpad::CustomInfoEntry::kValueMaxLength - 1);
171 218
172 int chunk_index = 0; 219 int chunk_index = 0;
173 size_t chunk_start = 0; // Current position inside |path| 220 size_t chunk_start = 0; // Current position inside |path|
174 221
175 for (chunk_start = 0; chunk_start < path.size(); chunk_index++) { 222 for (chunk_start = 0; chunk_start < path.size(); chunk_index++) {
176 size_t chunk_length = std::min(kChunkSize, path.size() - chunk_start); 223 size_t chunk_length = std::min(kChunkSize, path.size() - chunk_start);
177 224
178 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( 225 custom_entries_.push_back(google_breakpad::CustomInfoEntry(
179 base::StringPrintf(L"plugin-path-chunk-%i", chunk_index + 1).c_str(), 226 base::StringPrintf(L"plugin-path-chunk-%i", chunk_index + 1).c_str(),
180 path.substr(chunk_start, chunk_length).c_str())); 227 path.substr(chunk_start, chunk_length).c_str()));
181 228
182 chunk_start += chunk_length; 229 chunk_start += chunk_length;
183 } 230 }
184 } 231 }
185 232
186 // Appends the breakpad dump path to |g_custom_entries|. 233 // Appends the breakpad dump path to |g_custom_entries|.
187 void SetBreakpadDumpPath() { 234 void KeyValuePairKeeper::SetBreakpadDumpPath() {
188 DCHECK(g_custom_entries);
189 base::FilePath crash_dumps_dir_path; 235 base::FilePath crash_dumps_dir_path;
190 if (GetBreakpadClient()->GetAlternativeCrashDumpLocation( 236 if (GetBreakpadClient()->GetAlternativeCrashDumpLocation(
191 &crash_dumps_dir_path)) { 237 &crash_dumps_dir_path)) {
192 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( 238 custom_entries_.push_back(google_breakpad::CustomInfoEntry(
193 L"breakpad-dump-location", crash_dumps_dir_path.value().c_str())); 239 L"breakpad-dump-location", crash_dumps_dir_path.value().c_str()));
194 } 240 }
195 } 241 }
196 242
197 // Returns a string containing a list of all modifiers for the loaded profile. 243 // Returns a string containing a list of all modifiers for the loaded profile.
198 std::wstring GetProfileType() { 244 std::wstring GetProfileType() {
199 std::wstring profile_type; 245 std::wstring profile_type;
200 DWORD profile_bits = 0; 246 DWORD profile_bits = 0;
201 if (::GetProfileType(&profile_bits)) { 247 if (::GetProfileType(&profile_bits)) {
202 static const struct { 248 static const struct {
(...skipping 15 matching lines...) Expand all
218 } 264 }
219 } else { 265 } else {
220 DWORD last_error = ::GetLastError(); 266 DWORD last_error = ::GetLastError();
221 base::SStringPrintf(&profile_type, L"error %u", last_error); 267 base::SStringPrintf(&profile_type, L"error %u", last_error);
222 } 268 }
223 return profile_type; 269 return profile_type;
224 } 270 }
225 271
226 // Returns the custom info structure based on the dll in parameter and the 272 // Returns the custom info structure based on the dll in parameter and the
227 // process type. 273 // process type.
228 google_breakpad::CustomClientInfo* GetCustomInfo(const std::wstring& exe_path, 274 google_breakpad::CustomClientInfo*
229 const std::wstring& type) { 275 KeyValuePairKeeper::GetCustomInfo(const std::wstring& exe_path,
276 const std::wstring& type) {
230 base::string16 version, product; 277 base::string16 version, product;
231 base::string16 special_build; 278 base::string16 special_build;
232 base::string16 channel_name; 279 base::string16 channel_name;
233 GetBreakpadClient()->GetProductNameAndVersion( 280 GetBreakpadClient()->GetProductNameAndVersion(
234 base::FilePath(exe_path), 281 base::FilePath(exe_path),
235 &product, 282 &product,
236 &version, 283 &version,
237 &special_build, 284 &special_build,
238 &channel_name); 285 &channel_name);
239 286
240 // We only expect this method to be called once per process. 287 // We only expect this method to be called once per process.
241 DCHECK(!g_custom_entries); 288 // Common enties
242 g_custom_entries = new std::vector<google_breakpad::CustomInfoEntry>; 289 custom_entries_.push_back(
243
244 // Common g_custom_entries.
245 g_custom_entries->push_back(
246 google_breakpad::CustomInfoEntry(L"ver", 290 google_breakpad::CustomInfoEntry(L"ver",
247 base::UTF16ToWide(version).c_str())); 291 base::UTF16ToWide(version).c_str()));
248 g_custom_entries->push_back( 292 custom_entries_.push_back(
249 google_breakpad::CustomInfoEntry(L"prod", 293 google_breakpad::CustomInfoEntry(L"prod",
250 base::UTF16ToWide(product).c_str())); 294 base::UTF16ToWide(product).c_str()));
251 g_custom_entries->push_back( 295 custom_entries_.push_back(
252 google_breakpad::CustomInfoEntry(L"plat", L"Win32")); 296 google_breakpad::CustomInfoEntry(L"plat", L"Win32"));
253 g_custom_entries->push_back( 297 custom_entries_.push_back(
254 google_breakpad::CustomInfoEntry(L"ptype", type.c_str())); 298 google_breakpad::CustomInfoEntry(L"ptype", type.c_str()));
255 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( 299 custom_entries_.push_back(google_breakpad::CustomInfoEntry(
256 L"pid", base::StringPrintf(L"%d", ::GetCurrentProcessId()).c_str())); 300 L"pid", base::StringPrintf(L"%d", ::GetCurrentProcessId()).c_str()));
257 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( 301 custom_entries_.push_back(google_breakpad::CustomInfoEntry(
258 L"channel", base::UTF16ToWide(channel_name).c_str())); 302 L"channel", base::UTF16ToWide(channel_name).c_str()));
259 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( 303 custom_entries_.push_back(google_breakpad::CustomInfoEntry(
260 L"profile-type", GetProfileType().c_str())); 304 L"profile-type", GetProfileType().c_str()));
261 305
262 if (!special_build.empty()) 306 if (!special_build.empty())
263 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( 307 custom_entries_.push_back(google_breakpad::CustomInfoEntry(
264 L"special", base::UTF16ToWide(special_build).c_str())); 308 L"special", base::UTF16ToWide(special_build).c_str()));
265 309
266 if (type == L"plugin" || type == L"ppapi") { 310 if (type == L"plugin" || type == L"ppapi") {
267 std::wstring plugin_path = 311 std::wstring plugin_path =
268 CommandLine::ForCurrentProcess()->GetSwitchValueNative("plugin-path"); 312 CommandLine::ForCurrentProcess()->GetSwitchValueNative("plugin-path");
269 if (!plugin_path.empty()) 313 if (!plugin_path.empty())
270 SetPluginPath(plugin_path); 314 SetPluginPath(plugin_path);
271 } 315 }
272 316
273 // Check whether configuration management controls crash reporting. 317 // Check whether configuration management controls crash reporting.
274 bool crash_reporting_enabled = true; 318 bool crash_reporting_enabled = true;
275 bool controlled_by_policy = GetBreakpadClient()->ReportingIsEnforcedByPolicy( 319 bool controlled_by_policy = GetBreakpadClient()->ReportingIsEnforcedByPolicy(
276 &crash_reporting_enabled); 320 &crash_reporting_enabled);
277 const CommandLine& command = *CommandLine::ForCurrentProcess(); 321 const CommandLine& command = *CommandLine::ForCurrentProcess();
278 bool use_crash_service = 322 bool use_crash_service =
279 !controlled_by_policy && (command.HasSwitch(switches::kNoErrorDialogs) || 323 !controlled_by_policy && (command.HasSwitch(switches::kNoErrorDialogs) ||
280 GetBreakpadClient()->IsRunningUnattended()); 324 GetBreakpadClient()->IsRunningUnattended());
281 if (use_crash_service) 325 if (use_crash_service)
282 SetBreakpadDumpPath(); 326 SetBreakpadDumpPath();
283 327
284 // Create space for dynamic ad-hoc keys. The names and values are set using 328 // Create space for dynamic ad-hoc keys. The names and values are set using
285 // the API defined in base/debug/crash_logging.h. 329 // the API defined in base/debug/crash_logging.h.
286 g_dynamic_keys_offset = g_custom_entries->size(); 330 dynamic_keys_offset_ = custom_entries_.size();
287 for (size_t i = 0; i < kMaxDynamicEntries; ++i) { 331 for (size_t i = 0; i < kMaxDynamicEntries; ++i) {
288 // The names will be mutated as they are set. Un-numbered since these are 332 // The names will be mutated as they are set. Un-numbered since these are
289 // merely placeholders. The name cannot be empty because Breakpad's 333 // merely placeholders. The name cannot be empty because Breakpad's
290 // HTTPUpload will interpret that as an invalid parameter. 334 // HTTPUpload will interpret that as an invalid parameter.
291 g_custom_entries->push_back( 335 custom_entries_.push_back(
292 google_breakpad::CustomInfoEntry(L"unspecified-crash-key", L"")); 336 google_breakpad::CustomInfoEntry(L"unspecified-crash-key", L""));
293 } 337 }
294 338
295 g_dynamic_entries_lock = new base::Lock;
296 g_dynamic_entries = new DynamicEntriesMap;
297
298 static google_breakpad::CustomClientInfo custom_client_info; 339 static google_breakpad::CustomClientInfo custom_client_info;
299 custom_client_info.entries = &g_custom_entries->front(); 340 custom_client_info.entries = &custom_entries_.front();
300 custom_client_info.count = g_custom_entries->size(); 341 custom_client_info.count = custom_entries_.size();
301 342
302 return &custom_client_info; 343 return &custom_client_info;
303 } 344 }
304 345
346 namespace {
347
305 // This callback is used when we want to get a dump without crashing the 348 // This callback is used when we want to get a dump without crashing the
306 // process. 349 // process.
307 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*, 350 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*,
308 EXCEPTION_POINTERS* ex_info, 351 EXCEPTION_POINTERS* ex_info,
309 MDRawAssertionInfo*, bool) { 352 MDRawAssertionInfo*, bool) {
310 return true; 353 return true;
311 } 354 }
312 355
313 // This callback is executed when the browser process has crashed, after 356 // This callback is executed when the browser process has crashed, after
314 // the crash dump has been created. We need to minimize the amount of work 357 // the crash dump has been created. We need to minimize the amount of work
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 } 427 }
385 428
386 // Exception filter for the service process used when breakpad is not enabled. 429 // Exception filter for the service process used when breakpad is not enabled.
387 // We just display the "Do you want to restart" message and then die 430 // We just display the "Do you want to restart" message and then die
388 // (without calling the previous filter). 431 // (without calling the previous filter).
389 long WINAPI ServiceExceptionFilter(EXCEPTION_POINTERS* info) { 432 long WINAPI ServiceExceptionFilter(EXCEPTION_POINTERS* info) {
390 DumpDoneCallback(NULL, NULL, NULL, info, NULL, false); 433 DumpDoneCallback(NULL, NULL, NULL, info, NULL, false);
391 return EXCEPTION_EXECUTE_HANDLER; 434 return EXCEPTION_EXECUTE_HANDLER;
392 } 435 }
393 436
394 // NOTE: This function is used by SyzyASAN to annotate crash reports. If you 437 } // namespace
395 // change the name or signature of this function you will break SyzyASAN
396 // instrumented releases of Chrome. Please contact syzygy-team@chromium.org
397 // before doing so!
398 extern "C" void __declspec(dllexport) __cdecl SetCrashKeyValueImpl(
399 const wchar_t* key, const wchar_t* value) {
400 if (!g_dynamic_entries)
401 return;
402 438
439 void KeyValuePairKeeper::SetCrashKeyValue(
440 const std::wstring& key, const std::wstring& value) {
403 // CustomInfoEntry limits the length of key and value. If they exceed 441 // CustomInfoEntry limits the length of key and value. If they exceed
404 // their maximum length the underlying string handling functions raise 442 // their maximum length the underlying string handling functions raise
405 // an exception and prematurely trigger a crash. Truncate here. 443 // an exception and prematurely trigger a crash. Truncate here.
406 std::wstring safe_key(std::wstring(key).substr( 444 std::wstring safe_key(std::wstring(key).substr(
407 0, google_breakpad::CustomInfoEntry::kNameMaxLength - 1)); 445 0, google_breakpad::CustomInfoEntry::kNameMaxLength - 1));
408 std::wstring safe_value(std::wstring(value).substr( 446 std::wstring safe_value(std::wstring(value).substr(
409 0, google_breakpad::CustomInfoEntry::kValueMaxLength - 1)); 447 0, google_breakpad::CustomInfoEntry::kValueMaxLength - 1));
410 448
411 // If we already have a value for this key, update it; otherwise, insert 449 // If we already have a value for this key, update it; otherwise, insert
412 // the new value if we have not exhausted the pre-allocated slots for dynamic 450 // the new value if we have not exhausted the pre-allocated slots for dynamic
413 // entries. 451 // entries.
414 DCHECK(g_dynamic_entries_lock); 452 base::AutoLock lock(lock_);
415 base::AutoLock lock(*g_dynamic_entries_lock);
416 453
417 DynamicEntriesMap::iterator it = g_dynamic_entries->find(safe_key); 454 DynamicEntriesMap::iterator it = dynamic_entries_.find(safe_key);
418 google_breakpad::CustomInfoEntry* entry = NULL; 455 google_breakpad::CustomInfoEntry* entry = NULL;
419 if (it == g_dynamic_entries->end()) { 456 if (it == dynamic_entries_.end()) {
420 if (g_dynamic_entries->size() >= kMaxDynamicEntries) 457 if (dynamic_entries_.size() >= kMaxDynamicEntries)
421 return; 458 return;
422 entry = &(*g_custom_entries)[g_dynamic_keys_offset++]; 459 entry = &custom_entries_[dynamic_keys_offset_++];
423 g_dynamic_entries->insert(std::make_pair(safe_key, entry)); 460 dynamic_entries_.insert(std::make_pair(safe_key, entry));
424 } else { 461 } else {
425 entry = it->second; 462 entry = it->second;
426 } 463 }
427 464
428 entry->set(safe_key.data(), safe_value.data()); 465 entry->set(safe_key.data(), safe_value.data());
429 } 466 }
430 467
431 extern "C" void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl( 468 // NOTE: This function is used by SyzyASAN to annotate crash reports. If you
432 const wchar_t* key) { 469 // change the name or signature of this function you will break SyzyASAN
433 if (!g_dynamic_entries) 470 // instrumented releases of Chrome. Please contact syzygy-team@chromium.org
471 // before doing so!
472 extern "C" void __declspec(dllexport) __cdecl SetCrashKeyValueImpl(
473 const wchar_t* key, const wchar_t* value) {
474 KeyValuePairKeeper* keeper = KeyValuePairKeeper::keeper();
475 if (!keeper)
434 return; 476 return;
435 477
436 DCHECK(g_dynamic_entries_lock); 478 // TODO(siggi): This doesn't look quite right - there's NULL deref potential
437 base::AutoLock lock(*g_dynamic_entries_lock); 479 // here, and an implicit std::wstring conversion. Fixme.
480 keeper->SetCrashKeyValue(key, value);
481 }
482
483 void KeyValuePairKeeper::ClearCrashKeyValue(const std::wstring& key) {
484 base::AutoLock lock(lock_);
438 485
439 std::wstring key_string(key); 486 std::wstring key_string(key);
440 DynamicEntriesMap::iterator it = g_dynamic_entries->find(key_string); 487 DynamicEntriesMap::iterator it = dynamic_entries_.find(key_string);
441 if (it == g_dynamic_entries->end()) 488 if (it == dynamic_entries_.end())
442 return; 489 return;
443 490
444 it->second->set_value(NULL); 491 it->second->set_value(NULL);
445 } 492 }
446 493
447 } // namespace 494 extern "C" void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl(
495 const wchar_t* key) {
496 KeyValuePairKeeper* keeper = KeyValuePairKeeper::keeper();
497 if (!keeper)
498 return;
499
500 // TODO(siggi): This doesn't look quite right - there's NULL deref potential
501 // here, and an implicit std::wstring conversion. Fixme.
Robert Sesek 2014/05/29 20:34:41 Where's the NULL deref potential?
Sigurður Ásgeirsson 2014/05/30 15:14:49 If there's NULL on the input, std::string will try
502 keeper->ClearCrashKeyValue(key);
503 }
448 504
449 static bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption, 505 static bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption,
450 UINT flags, bool* exit_now) { 506 UINT flags, bool* exit_now) {
451 // We wrap the call to MessageBoxW with a SEH handler because it some 507 // We wrap the call to MessageBoxW with a SEH handler because it some
452 // machines with CursorXP, PeaDict or with FontExplorer installed it crashes 508 // machines with CursorXP, PeaDict or with FontExplorer installed it crashes
453 // uncontrollably here. Being this a best effort deal we better go away. 509 // uncontrollably here. Being this a best effort deal we better go away.
454 __try { 510 __try {
455 *exit_now = (IDOK != ::MessageBoxW(NULL, text, caption, flags)); 511 *exit_now = (IDOK != ::MessageBoxW(NULL, text, caption, flags));
456 } __except(EXCEPTION_EXECUTE_HANDLER) { 512 } __except(EXCEPTION_EXECUTE_HANDLER) {
457 // Its not safe to continue executing, exit silently here. 513 // Its not safe to continue executing, exit silently here.
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
648 if (process_type.empty()) 704 if (process_type.empty())
649 process_type = L"browser"; 705 process_type = L"browser";
650 706
651 wchar_t exe_path[MAX_PATH]; 707 wchar_t exe_path[MAX_PATH];
652 exe_path[0] = 0; 708 exe_path[0] = 0;
653 GetModuleFileNameW(NULL, exe_path, MAX_PATH); 709 GetModuleFileNameW(NULL, exe_path, MAX_PATH);
654 710
655 bool is_per_user_install = 711 bool is_per_user_install =
656 GetBreakpadClient()->GetIsPerUserInstall(base::FilePath(exe_path)); 712 GetBreakpadClient()->GetIsPerUserInstall(base::FilePath(exe_path));
657 713
714 // This is intentionally leaked.
715 KeyValuePairKeeper* keeper = new KeyValuePairKeeper();
716
658 google_breakpad::CustomClientInfo* custom_info = 717 google_breakpad::CustomClientInfo* custom_info =
659 GetCustomInfo(exe_path, process_type); 718 keeper->GetCustomInfo(exe_path, process_type);
660 719
661 google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL; 720 google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL;
662 LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL; 721 LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL;
663 // We install the post-dump callback only for the browser and service 722 // We install the post-dump callback only for the browser and service
664 // processes. It spawns a new browser/service process. 723 // processes. It spawns a new browser/service process.
665 if (process_type == L"browser") { 724 if (process_type == L"browser") {
666 callback = &DumpDoneCallback; 725 callback = &DumpDoneCallback;
667 default_filter = &ChromeExceptionFilter; 726 default_filter = &ChromeExceptionFilter;
668 } else if (process_type == L"service") { 727 } else if (process_type == L"service") {
669 callback = &DumpDoneCallback; 728 callback = &DumpDoneCallback;
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
736 if (process_type != L"browser" && 795 if (process_type != L"browser" &&
737 !GetBreakpadClient()->IsRunningUnattended()) { 796 !GetBreakpadClient()->IsRunningUnattended()) {
738 // Initialize the hook TerminateProcess to catch unexpected exits. 797 // Initialize the hook TerminateProcess to catch unexpected exits.
739 InitTerminateProcessHooks(); 798 InitTerminateProcessHooks();
740 } 799 }
741 #endif 800 #endif
742 } 801 }
743 } 802 }
744 803
745 } // namespace breakpad 804 } // namespace breakpad
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698