security/sandbox/chromium/base/logging.cc

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

michael@0 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
michael@0 2 // Use of this source code is governed by a BSD-style license that can be
michael@0 3 // found in the LICENSE file.
michael@0 4
michael@0 5 #include "base/logging.h"
michael@0 6
michael@0 7 #if defined(OS_WIN)
michael@0 8 #include <io.h>
michael@0 9 #include <windows.h>
michael@0 10 typedef HANDLE FileHandle;
michael@0 11 typedef HANDLE MutexHandle;
michael@0 12 // Windows warns on using write(). It prefers _write().
michael@0 13 #define write(fd, buf, count) _write(fd, buf, static_cast<unsigned int>(count))
michael@0 14 // Windows doesn't define STDERR_FILENO. Define it here.
michael@0 15 #define STDERR_FILENO 2
michael@0 16 #elif defined(OS_MACOSX)
michael@0 17 #include <mach/mach.h>
michael@0 18 #include <mach/mach_time.h>
michael@0 19 #include <mach-o/dyld.h>
michael@0 20 #elif defined(OS_POSIX)
michael@0 21 #if defined(OS_NACL)
michael@0 22 #include <sys/time.h> // timespec doesn't seem to be in <time.h>
michael@0 23 #else
michael@0 24 #include <sys/syscall.h>
michael@0 25 #endif
michael@0 26 #include <time.h>
michael@0 27 #endif
michael@0 28
michael@0 29 #if defined(OS_POSIX)
michael@0 30 #include <errno.h>
michael@0 31 #include <pthread.h>
michael@0 32 #include <stdio.h>
michael@0 33 #include <stdlib.h>
michael@0 34 #include <string.h>
michael@0 35 #include <unistd.h>
michael@0 36 #define MAX_PATH PATH_MAX
michael@0 37 typedef FILE* FileHandle;
michael@0 38 typedef pthread_mutex_t* MutexHandle;
michael@0 39 #endif
michael@0 40
michael@0 41 #include <algorithm>
michael@0 42 #include <cstring>
michael@0 43 #include <ctime>
michael@0 44 #include <iomanip>
michael@0 45 #include <ostream>
michael@0 46
michael@0 47 #include "base/base_switches.h"
michael@0 48 #include "base/command_line.h"
michael@0 49 #include "base/debug/alias.h"
michael@0 50 #include "base/debug/debugger.h"
michael@0 51 #include "base/debug/stack_trace.h"
michael@0 52 #include "base/posix/eintr_wrapper.h"
michael@0 53 #include "base/strings/string_piece.h"
michael@0 54 #include "base/strings/utf_string_conversions.h"
michael@0 55 #include "base/synchronization/lock_impl.h"
michael@0 56 #include "base/threading/platform_thread.h"
michael@0 57 #include "base/vlog.h"
michael@0 58 #if defined(OS_POSIX)
michael@0 59 #include "base/safe_strerror_posix.h"
michael@0 60 #endif
michael@0 61
michael@0 62 #if defined(OS_ANDROID)
michael@0 63 #include <android/log.h>
michael@0 64 #endif
michael@0 65
michael@0 66 namespace logging {
michael@0 67
michael@0 68 DcheckState g_dcheck_state = DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
michael@0 69
michael@0 70 DcheckState get_dcheck_state() {
michael@0 71 return g_dcheck_state;
michael@0 72 }
michael@0 73
michael@0 74 void set_dcheck_state(DcheckState state) {
michael@0 75 g_dcheck_state = state;
michael@0 76 }
michael@0 77
michael@0 78 namespace {
michael@0 79
michael@0 80 VlogInfo* g_vlog_info = NULL;
michael@0 81 VlogInfo* g_vlog_info_prev = NULL;
michael@0 82
michael@0 83 const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
michael@0 84 "INFO", "WARNING", "ERROR", "ERROR_REPORT", "FATAL" };
michael@0 85
michael@0 86 int min_log_level = 0;
michael@0 87
michael@0 88 LoggingDestination logging_destination = LOG_DEFAULT;
michael@0 89
michael@0 90 // For LOG_ERROR and above, always print to stderr.
michael@0 91 const int kAlwaysPrintErrorLevel = LOG_ERROR;
michael@0 92
michael@0 93 // Which log file to use? This is initialized by InitLogging or
michael@0 94 // will be lazily initialized to the default value when it is
michael@0 95 // first needed.
michael@0 96 #if defined(OS_WIN)
michael@0 97 typedef std::wstring PathString;
michael@0 98 #else
michael@0 99 typedef std::string PathString;
michael@0 100 #endif
michael@0 101 PathString* log_file_name = NULL;
michael@0 102
michael@0 103 // this file is lazily opened and the handle may be NULL
michael@0 104 FileHandle log_file = NULL;
michael@0 105
michael@0 106 // what should be prepended to each message?
michael@0 107 bool log_process_id = false;
michael@0 108 bool log_thread_id = false;
michael@0 109 bool log_timestamp = true;
michael@0 110 bool log_tickcount = false;
michael@0 111
michael@0 112 // Should we pop up fatal debug messages in a dialog?
michael@0 113 bool show_error_dialogs = false;
michael@0 114
michael@0 115 // An assert handler override specified by the client to be called instead of
michael@0 116 // the debug message dialog and process termination.
michael@0 117 LogAssertHandlerFunction log_assert_handler = NULL;
michael@0 118 // An report handler override specified by the client to be called instead of
michael@0 119 // the debug message dialog.
michael@0 120 LogReportHandlerFunction log_report_handler = NULL;
michael@0 121 // A log message handler that gets notified of every log message we process.
michael@0 122 LogMessageHandlerFunction log_message_handler = NULL;
michael@0 123
michael@0 124 // Helper functions to wrap platform differences.
michael@0 125
michael@0 126 int32 CurrentProcessId() {
michael@0 127 #if defined(OS_WIN)
michael@0 128 return GetCurrentProcessId();
michael@0 129 #elif defined(OS_POSIX)
michael@0 130 return getpid();
michael@0 131 #endif
michael@0 132 }
michael@0 133
michael@0 134 uint64 TickCount() {
michael@0 135 #if defined(OS_WIN)
michael@0 136 return GetTickCount();
michael@0 137 #elif defined(OS_MACOSX)
michael@0 138 return mach_absolute_time();
michael@0 139 #elif defined(OS_NACL)
michael@0 140 // NaCl sadly does not have _POSIX_TIMERS enabled in sys/features.h
michael@0 141 // So we have to use clock() for now.
michael@0 142 return clock();
michael@0 143 #elif defined(OS_POSIX)
michael@0 144 struct timespec ts;
michael@0 145 clock_gettime(CLOCK_MONOTONIC, &ts);
michael@0 146
michael@0 147 uint64 absolute_micro =
michael@0 148 static_cast<int64>(ts.tv_sec) * 1000000 +
michael@0 149 static_cast<int64>(ts.tv_nsec) / 1000;
michael@0 150
michael@0 151 return absolute_micro;
michael@0 152 #endif
michael@0 153 }
michael@0 154
michael@0 155 void DeleteFilePath(const PathString& log_name) {
michael@0 156 #if defined(OS_WIN)
michael@0 157 DeleteFile(log_name.c_str());
michael@0 158 #elif defined (OS_NACL)
michael@0 159 // Do nothing; unlink() isn't supported on NaCl.
michael@0 160 #else
michael@0 161 unlink(log_name.c_str());
michael@0 162 #endif
michael@0 163 }
michael@0 164
michael@0 165 PathString GetDefaultLogFile() {
michael@0 166 #if defined(OS_WIN)
michael@0 167 // On Windows we use the same path as the exe.
michael@0 168 wchar_t module_name[MAX_PATH];
michael@0 169 GetModuleFileName(NULL, module_name, MAX_PATH);
michael@0 170
michael@0 171 PathString log_file = module_name;
michael@0 172 PathString::size_type last_backslash =
michael@0 173 log_file.rfind('\\', log_file.size());
michael@0 174 if (last_backslash != PathString::npos)
michael@0 175 log_file.erase(last_backslash + 1);
michael@0 176 log_file += L"debug.log";
michael@0 177 return log_file;
michael@0 178 #elif defined(OS_POSIX)
michael@0 179 // On other platforms we just use the current directory.
michael@0 180 return PathString("debug.log");
michael@0 181 #endif
michael@0 182 }
michael@0 183
michael@0 184 // This class acts as a wrapper for locking the logging files.
michael@0 185 // LoggingLock::Init() should be called from the main thread before any logging
michael@0 186 // is done. Then whenever logging, be sure to have a local LoggingLock
michael@0 187 // instance on the stack. This will ensure that the lock is unlocked upon
michael@0 188 // exiting the frame.
michael@0 189 // LoggingLocks can not be nested.
michael@0 190 class LoggingLock {
michael@0 191 public:
michael@0 192 LoggingLock() {
michael@0 193 LockLogging();
michael@0 194 }
michael@0 195
michael@0 196 ~LoggingLock() {
michael@0 197 UnlockLogging();
michael@0 198 }
michael@0 199
michael@0 200 static void Init(LogLockingState lock_log, const PathChar* new_log_file) {
michael@0 201 if (initialized)
michael@0 202 return;
michael@0 203 lock_log_file = lock_log;
michael@0 204 if (lock_log_file == LOCK_LOG_FILE) {
michael@0 205 #if defined(OS_WIN)
michael@0 206 if (!log_mutex) {
michael@0 207 std::wstring safe_name;
michael@0 208 if (new_log_file)
michael@0 209 safe_name = new_log_file;
michael@0 210 else
michael@0 211 safe_name = GetDefaultLogFile();
michael@0 212 // \ is not a legal character in mutex names so we replace \ with /
michael@0 213 std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
michael@0 214 std::wstring t(L"Global\\");
michael@0 215 t.append(safe_name);
michael@0 216 log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
michael@0 217
michael@0 218 if (log_mutex == NULL) {
michael@0 219 #if DEBUG
michael@0 220 // Keep the error code for debugging
michael@0 221 int error = GetLastError(); // NOLINT
michael@0 222 base::debug::BreakDebugger();
michael@0 223 #endif
michael@0 224 // Return nicely without putting initialized to true.
michael@0 225 return;
michael@0 226 }
michael@0 227 }
michael@0 228 #endif
michael@0 229 } else {
michael@0 230 log_lock = new base::internal::LockImpl();
michael@0 231 }
michael@0 232 initialized = true;
michael@0 233 }
michael@0 234
michael@0 235 private:
michael@0 236 static void LockLogging() {
michael@0 237 if (lock_log_file == LOCK_LOG_FILE) {
michael@0 238 #if defined(OS_WIN)
michael@0 239 ::WaitForSingleObject(log_mutex, INFINITE);
michael@0 240 // WaitForSingleObject could have returned WAIT_ABANDONED. We don't
michael@0 241 // abort the process here. UI tests might be crashy sometimes,
michael@0 242 // and aborting the test binary only makes the problem worse.
michael@0 243 // We also don't use LOG macros because that might lead to an infinite
michael@0 244 // loop. For more info see http://crbug.com/18028.
michael@0 245 #elif defined(OS_POSIX)
michael@0 246 pthread_mutex_lock(&log_mutex);
michael@0 247 #endif
michael@0 248 } else {
michael@0 249 // use the lock
michael@0 250 log_lock->Lock();
michael@0 251 }
michael@0 252 }
michael@0 253
michael@0 254 static void UnlockLogging() {
michael@0 255 if (lock_log_file == LOCK_LOG_FILE) {
michael@0 256 #if defined(OS_WIN)
michael@0 257 ReleaseMutex(log_mutex);
michael@0 258 #elif defined(OS_POSIX)
michael@0 259 pthread_mutex_unlock(&log_mutex);
michael@0 260 #endif
michael@0 261 } else {
michael@0 262 log_lock->Unlock();
michael@0 263 }
michael@0 264 }
michael@0 265
michael@0 266 // The lock is used if log file locking is false. It helps us avoid problems
michael@0 267 // with multiple threads writing to the log file at the same time. Use
michael@0 268 // LockImpl directly instead of using Lock, because Lock makes logging calls.
michael@0 269 static base::internal::LockImpl* log_lock;
michael@0 270
michael@0 271 // When we don't use a lock, we are using a global mutex. We need to do this
michael@0 272 // because LockFileEx is not thread safe.
michael@0 273 #if defined(OS_WIN)
michael@0 274 static MutexHandle log_mutex;
michael@0 275 #elif defined(OS_POSIX)
michael@0 276 static pthread_mutex_t log_mutex;
michael@0 277 #endif
michael@0 278
michael@0 279 static bool initialized;
michael@0 280 static LogLockingState lock_log_file;
michael@0 281 };
michael@0 282
michael@0 283 // static
michael@0 284 bool LoggingLock::initialized = false;
michael@0 285 // static
michael@0 286 base::internal::LockImpl* LoggingLock::log_lock = NULL;
michael@0 287 // static
michael@0 288 LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE;
michael@0 289
michael@0 290 #if defined(OS_WIN)
michael@0 291 // static
michael@0 292 MutexHandle LoggingLock::log_mutex = NULL;
michael@0 293 #elif defined(OS_POSIX)
michael@0 294 pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER;
michael@0 295 #endif
michael@0 296
michael@0 297 // Called by logging functions to ensure that debug_file is initialized
michael@0 298 // and can be used for writing. Returns false if the file could not be
michael@0 299 // initialized. debug_file will be NULL in this case.
michael@0 300 bool InitializeLogFileHandle() {
michael@0 301 if (log_file)
michael@0 302 return true;
michael@0 303
michael@0 304 if (!log_file_name) {
michael@0 305 // Nobody has called InitLogging to specify a debug log file, so here we
michael@0 306 // initialize the log file name to a default.
michael@0 307 log_file_name = new PathString(GetDefaultLogFile());
michael@0 308 }
michael@0 309
michael@0 310 if ((logging_destination & LOG_TO_FILE) != 0) {
michael@0 311 #if defined(OS_WIN)
michael@0 312 log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE,
michael@0 313 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
michael@0 314 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
michael@0 315 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
michael@0 316 // try the current directory
michael@0 317 log_file = CreateFile(L".\\debug.log", GENERIC_WRITE,
michael@0 318 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
michael@0 319 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
michael@0 320 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
michael@0 321 log_file = NULL;
michael@0 322 return false;
michael@0 323 }
michael@0 324 }
michael@0 325 SetFilePointer(log_file, 0, 0, FILE_END);
michael@0 326 #elif defined(OS_POSIX)
michael@0 327 log_file = fopen(log_file_name->c_str(), "a");
michael@0 328 if (log_file == NULL)
michael@0 329 return false;
michael@0 330 #endif
michael@0 331 }
michael@0 332
michael@0 333 return true;
michael@0 334 }
michael@0 335
michael@0 336 void CloseFile(FileHandle log) {
michael@0 337 #if defined(OS_WIN)
michael@0 338 CloseHandle(log);
michael@0 339 #else
michael@0 340 fclose(log);
michael@0 341 #endif
michael@0 342 }
michael@0 343
michael@0 344 void CloseLogFileUnlocked() {
michael@0 345 if (!log_file)
michael@0 346 return;
michael@0 347
michael@0 348 CloseFile(log_file);
michael@0 349 log_file = NULL;
michael@0 350 }
michael@0 351
michael@0 352 } // namespace
michael@0 353
michael@0 354 LoggingSettings::LoggingSettings()
michael@0 355 : logging_dest(LOG_DEFAULT),
michael@0 356 log_file(NULL),
michael@0 357 lock_log(LOCK_LOG_FILE),
michael@0 358 delete_old(APPEND_TO_OLD_LOG_FILE),
michael@0 359 dcheck_state(DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS) {}
michael@0 360
michael@0 361 bool BaseInitLoggingImpl(const LoggingSettings& settings) {
michael@0 362 #if defined(OS_NACL)
michael@0 363 // Can log only to the system debug log.
michael@0 364 CHECK_EQ(settings.logging_dest & ~LOG_TO_SYSTEM_DEBUG_LOG, 0);
michael@0 365 #endif
michael@0 366 g_dcheck_state = settings.dcheck_state;
michael@0 367 CommandLine* command_line = CommandLine::ForCurrentProcess();
michael@0 368 // Don't bother initializing g_vlog_info unless we use one of the
michael@0 369 // vlog switches.
michael@0 370 if (command_line->HasSwitch(switches::kV) ||
michael@0 371 command_line->HasSwitch(switches::kVModule)) {
michael@0 372 // NOTE: If g_vlog_info has already been initialized, it might be in use
michael@0 373 // by another thread. Don't delete the old VLogInfo, just create a second
michael@0 374 // one. We keep track of both to avoid memory leak warnings.
michael@0 375 CHECK(!g_vlog_info_prev);
michael@0 376 g_vlog_info_prev = g_vlog_info;
michael@0 377
michael@0 378 g_vlog_info =
michael@0 379 new VlogInfo(command_line->GetSwitchValueASCII(switches::kV),
michael@0 380 command_line->GetSwitchValueASCII(switches::kVModule),
michael@0 381 &min_log_level);
michael@0 382 }
michael@0 383
michael@0 384 logging_destination = settings.logging_dest;
michael@0 385
michael@0 386 // ignore file options unless logging to file is set.
michael@0 387 if ((logging_destination & LOG_TO_FILE) == 0)
michael@0 388 return true;
michael@0 389
michael@0 390 LoggingLock::Init(settings.lock_log, settings.log_file);
michael@0 391 LoggingLock logging_lock;
michael@0 392
michael@0 393 // Calling InitLogging twice or after some log call has already opened the
michael@0 394 // default log file will re-initialize to the new options.
michael@0 395 CloseLogFileUnlocked();
michael@0 396
michael@0 397 if (!log_file_name)
michael@0 398 log_file_name = new PathString();
michael@0 399 *log_file_name = settings.log_file;
michael@0 400 if (settings.delete_old == DELETE_OLD_LOG_FILE)
michael@0 401 DeleteFilePath(*log_file_name);
michael@0 402
michael@0 403 return InitializeLogFileHandle();
michael@0 404 }
michael@0 405
michael@0 406 void SetMinLogLevel(int level) {
michael@0 407 min_log_level = std::min(LOG_ERROR_REPORT, level);
michael@0 408 }
michael@0 409
michael@0 410 int GetMinLogLevel() {
michael@0 411 return min_log_level;
michael@0 412 }
michael@0 413
michael@0 414 int GetVlogVerbosity() {
michael@0 415 return std::max(-1, LOG_INFO - GetMinLogLevel());
michael@0 416 }
michael@0 417
michael@0 418 int GetVlogLevelHelper(const char* file, size_t N) {
michael@0 419 DCHECK_GT(N, 0U);
michael@0 420 // Note: g_vlog_info may change on a different thread during startup
michael@0 421 // (but will always be valid or NULL).
michael@0 422 VlogInfo* vlog_info = g_vlog_info;
michael@0 423 return vlog_info ?
michael@0 424 vlog_info->GetVlogLevel(base::StringPiece(file, N - 1)) :
michael@0 425 GetVlogVerbosity();
michael@0 426 }
michael@0 427
michael@0 428 void SetLogItems(bool enable_process_id, bool enable_thread_id,
michael@0 429 bool enable_timestamp, bool enable_tickcount) {
michael@0 430 log_process_id = enable_process_id;
michael@0 431 log_thread_id = enable_thread_id;
michael@0 432 log_timestamp = enable_timestamp;
michael@0 433 log_tickcount = enable_tickcount;
michael@0 434 }
michael@0 435
michael@0 436 void SetShowErrorDialogs(bool enable_dialogs) {
michael@0 437 show_error_dialogs = enable_dialogs;
michael@0 438 }
michael@0 439
michael@0 440 void SetLogAssertHandler(LogAssertHandlerFunction handler) {
michael@0 441 log_assert_handler = handler;
michael@0 442 }
michael@0 443
michael@0 444 void SetLogReportHandler(LogReportHandlerFunction handler) {
michael@0 445 log_report_handler = handler;
michael@0 446 }
michael@0 447
michael@0 448 void SetLogMessageHandler(LogMessageHandlerFunction handler) {
michael@0 449 log_message_handler = handler;
michael@0 450 }
michael@0 451
michael@0 452 LogMessageHandlerFunction GetLogMessageHandler() {
michael@0 453 return log_message_handler;
michael@0 454 }
michael@0 455
michael@0 456 // MSVC doesn't like complex extern templates and DLLs.
michael@0 457 #if !defined(COMPILER_MSVC)
michael@0 458 // Explicit instantiations for commonly used comparisons.
michael@0 459 template std::string* MakeCheckOpString<int, int>(
michael@0 460 const int&, const int&, const char* names);
michael@0 461 template std::string* MakeCheckOpString<unsigned long, unsigned long>(
michael@0 462 const unsigned long&, const unsigned long&, const char* names);
michael@0 463 template std::string* MakeCheckOpString<unsigned long, unsigned int>(
michael@0 464 const unsigned long&, const unsigned int&, const char* names);
michael@0 465 template std::string* MakeCheckOpString<unsigned int, unsigned long>(
michael@0 466 const unsigned int&, const unsigned long&, const char* names);
michael@0 467 template std::string* MakeCheckOpString<std::string, std::string>(
michael@0 468 const std::string&, const std::string&, const char* name);
michael@0 469 #endif
michael@0 470
michael@0 471 // Displays a message box to the user with the error message in it.
michael@0 472 // Used for fatal messages, where we close the app simultaneously.
michael@0 473 // This is for developers only; we don't use this in circumstances
michael@0 474 // (like release builds) where users could see it, since users don't
michael@0 475 // understand these messages anyway.
michael@0 476 void DisplayDebugMessageInDialog(const std::string& str) {
michael@0 477 if (str.empty())
michael@0 478 return;
michael@0 479
michael@0 480 if (!show_error_dialogs)
michael@0 481 return;
michael@0 482
michael@0 483 #if defined(OS_WIN)
michael@0 484 // For Windows programs, it's possible that the message loop is
michael@0 485 // messed up on a fatal error, and creating a MessageBox will cause
michael@0 486 // that message loop to be run. Instead, we try to spawn another
michael@0 487 // process that displays its command line. We look for "Debug
michael@0 488 // Message.exe" in the same directory as the application. If it
michael@0 489 // exists, we use it, otherwise, we use a regular message box.
michael@0 490 wchar_t prog_name[MAX_PATH];
michael@0 491 GetModuleFileNameW(NULL, prog_name, MAX_PATH);
michael@0 492 wchar_t* backslash = wcsrchr(prog_name, '\\');
michael@0 493 if (backslash)
michael@0 494 backslash[1] = 0;
michael@0 495 wcscat_s(prog_name, MAX_PATH, L"debug_message.exe");
michael@0 496
michael@0 497 std::wstring cmdline = UTF8ToWide(str);
michael@0 498 if (cmdline.empty())
michael@0 499 return;
michael@0 500
michael@0 501 STARTUPINFO startup_info;
michael@0 502 memset(&startup_info, 0, sizeof(startup_info));
michael@0 503 startup_info.cb = sizeof(startup_info);
michael@0 504
michael@0 505 PROCESS_INFORMATION process_info;
michael@0 506 if (CreateProcessW(prog_name, &cmdline[0], NULL, NULL, false, 0, NULL,
michael@0 507 NULL, &startup_info, &process_info)) {
michael@0 508 WaitForSingleObject(process_info.hProcess, INFINITE);
michael@0 509 CloseHandle(process_info.hThread);
michael@0 510 CloseHandle(process_info.hProcess);
michael@0 511 } else {
michael@0 512 // debug process broken, let's just do a message box
michael@0 513 MessageBoxW(NULL, &cmdline[0], L"Fatal error",
michael@0 514 MB_OK | MB_ICONHAND | MB_TOPMOST);
michael@0 515 }
michael@0 516 #else
michael@0 517 // We intentionally don't implement a dialog on other platforms.
michael@0 518 // You can just look at stderr.
michael@0 519 #endif
michael@0 520 }
michael@0 521
michael@0 522 #if defined(OS_WIN)
michael@0 523 LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {
michael@0 524 }
michael@0 525
michael@0 526 LogMessage::SaveLastError::~SaveLastError() {
michael@0 527 ::SetLastError(last_error_);
michael@0 528 }
michael@0 529 #endif // defined(OS_WIN)
michael@0 530
michael@0 531 LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
michael@0 532 int ctr)
michael@0 533 : severity_(severity), file_(file), line_(line) {
michael@0 534 Init(file, line);
michael@0 535 }
michael@0 536
michael@0 537 LogMessage::LogMessage(const char* file, int line)
michael@0 538 : severity_(LOG_INFO), file_(file), line_(line) {
michael@0 539 Init(file, line);
michael@0 540 }
michael@0 541
michael@0 542 LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
michael@0 543 : severity_(severity), file_(file), line_(line) {
michael@0 544 Init(file, line);
michael@0 545 }
michael@0 546
michael@0 547 LogMessage::LogMessage(const char* file, int line, std::string* result)
michael@0 548 : severity_(LOG_FATAL), file_(file), line_(line) {
michael@0 549 Init(file, line);
michael@0 550 stream_ << "Check failed: " << *result;
michael@0 551 delete result;
michael@0 552 }
michael@0 553
michael@0 554 LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
michael@0 555 std::string* result)
michael@0 556 : severity_(severity), file_(file), line_(line) {
michael@0 557 Init(file, line);
michael@0 558 stream_ << "Check failed: " << *result;
michael@0 559 delete result;
michael@0 560 }
michael@0 561
michael@0 562 LogMessage::~LogMessage() {
michael@0 563 #if !defined(NDEBUG) && !defined(OS_NACL)
michael@0 564 if (severity_ == LOG_FATAL) {
michael@0 565 // Include a stack trace on a fatal.
michael@0 566 base::debug::StackTrace trace;
michael@0 567 stream_ << std::endl; // Newline to separate from log message.
michael@0 568 trace.OutputToStream(&stream_);
michael@0 569 }
michael@0 570 #endif
michael@0 571 stream_ << std::endl;
michael@0 572 std::string str_newline(stream_.str());
michael@0 573
michael@0 574 // Give any log message handler first dibs on the message.
michael@0 575 if (log_message_handler &&
michael@0 576 log_message_handler(severity_, file_, line_,
michael@0 577 message_start_, str_newline)) {
michael@0 578 // The handler took care of it, no further processing.
michael@0 579 return;
michael@0 580 }
michael@0 581
michael@0 582 if ((logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) {
michael@0 583 #if defined(OS_WIN)
michael@0 584 OutputDebugStringA(str_newline.c_str());
michael@0 585 #elif defined(OS_ANDROID)
michael@0 586 android_LogPriority priority =
michael@0 587 (severity_ < 0) ? ANDROID_LOG_VERBOSE : ANDROID_LOG_UNKNOWN;
michael@0 588 switch (severity_) {
michael@0 589 case LOG_INFO:
michael@0 590 priority = ANDROID_LOG_INFO;
michael@0 591 break;
michael@0 592 case LOG_WARNING:
michael@0 593 priority = ANDROID_LOG_WARN;
michael@0 594 break;
michael@0 595 case LOG_ERROR:
michael@0 596 case LOG_ERROR_REPORT:
michael@0 597 priority = ANDROID_LOG_ERROR;
michael@0 598 break;
michael@0 599 case LOG_FATAL:
michael@0 600 priority = ANDROID_LOG_FATAL;
michael@0 601 break;
michael@0 602 }
michael@0 603 __android_log_write(priority, "chromium", str_newline.c_str());
michael@0 604 #endif
michael@0 605 fprintf(stderr, "%s", str_newline.c_str());
michael@0 606 fflush(stderr);
michael@0 607 } else if (severity_ >= kAlwaysPrintErrorLevel) {
michael@0 608 // When we're only outputting to a log file, above a certain log level, we
michael@0 609 // should still output to stderr so that we can better detect and diagnose
michael@0 610 // problems with unit tests, especially on the buildbots.
michael@0 611 fprintf(stderr, "%s", str_newline.c_str());
michael@0 612 fflush(stderr);
michael@0 613 }
michael@0 614
michael@0 615 // write to log file
michael@0 616 if ((logging_destination & LOG_TO_FILE) != 0) {
michael@0 617 // We can have multiple threads and/or processes, so try to prevent them
michael@0 618 // from clobbering each other's writes.
michael@0 619 // If the client app did not call InitLogging, and the lock has not
michael@0 620 // been created do it now. We do this on demand, but if two threads try
michael@0 621 // to do this at the same time, there will be a race condition to create
michael@0 622 // the lock. This is why InitLogging should be called from the main
michael@0 623 // thread at the beginning of execution.
michael@0 624 LoggingLock::Init(LOCK_LOG_FILE, NULL);
michael@0 625 LoggingLock logging_lock;
michael@0 626 if (InitializeLogFileHandle()) {
michael@0 627 #if defined(OS_WIN)
michael@0 628 SetFilePointer(log_file, 0, 0, SEEK_END);
michael@0 629 DWORD num_written;
michael@0 630 WriteFile(log_file,
michael@0 631 static_cast<const void*>(str_newline.c_str()),
michael@0 632 static_cast<DWORD>(str_newline.length()),
michael@0 633 &num_written,
michael@0 634 NULL);
michael@0 635 #else
michael@0 636 fprintf(log_file, "%s", str_newline.c_str());
michael@0 637 fflush(log_file);
michael@0 638 #endif
michael@0 639 }
michael@0 640 }
michael@0 641
michael@0 642 if (severity_ == LOG_FATAL) {
michael@0 643 // Ensure the first characters of the string are on the stack so they
michael@0 644 // are contained in minidumps for diagnostic purposes.
michael@0 645 char str_stack[1024];
michael@0 646 str_newline.copy(str_stack, arraysize(str_stack));
michael@0 647 base::debug::Alias(str_stack);
michael@0 648
michael@0 649 // display a message or break into the debugger on a fatal error
michael@0 650 if (base::debug::BeingDebugged()) {
michael@0 651 base::debug::BreakDebugger();
michael@0 652 } else {
michael@0 653 if (log_assert_handler) {
michael@0 654 // make a copy of the string for the handler out of paranoia
michael@0 655 log_assert_handler(std::string(stream_.str()));
michael@0 656 } else {
michael@0 657 // Don't use the string with the newline, get a fresh version to send to
michael@0 658 // the debug message process. We also don't display assertions to the
michael@0 659 // user in release mode. The enduser can't do anything with this
michael@0 660 // information, and displaying message boxes when the application is
michael@0 661 // hosed can cause additional problems.
michael@0 662 #ifndef NDEBUG
michael@0 663 DisplayDebugMessageInDialog(stream_.str());
michael@0 664 #endif
michael@0 665 // Crash the process to generate a dump.
michael@0 666 base::debug::BreakDebugger();
michael@0 667 }
michael@0 668 }
michael@0 669 } else if (severity_ == LOG_ERROR_REPORT) {
michael@0 670 // We are here only if the user runs with --enable-dcheck in release mode.
michael@0 671 if (log_report_handler) {
michael@0 672 log_report_handler(std::string(stream_.str()));
michael@0 673 } else {
michael@0 674 DisplayDebugMessageInDialog(stream_.str());
michael@0 675 }
michael@0 676 }
michael@0 677 }
michael@0 678
michael@0 679 // writes the common header info to the stream
michael@0 680 void LogMessage::Init(const char* file, int line) {
michael@0 681 base::StringPiece filename(file);
michael@0 682 size_t last_slash_pos = filename.find_last_of("\\/");
michael@0 683 if (last_slash_pos != base::StringPiece::npos)
michael@0 684 filename.remove_prefix(last_slash_pos + 1);
michael@0 685
michael@0 686 // TODO(darin): It might be nice if the columns were fixed width.
michael@0 687
michael@0 688 stream_ << '[';
michael@0 689 if (log_process_id)
michael@0 690 stream_ << CurrentProcessId() << ':';
michael@0 691 if (log_thread_id)
michael@0 692 stream_ << base::PlatformThread::CurrentId() << ':';
michael@0 693 if (log_timestamp) {
michael@0 694 time_t t = time(NULL);
michael@0 695 struct tm local_time = {0};
michael@0 696 #if _MSC_VER >= 1400
michael@0 697 localtime_s(&local_time, &t);
michael@0 698 #else
michael@0 699 localtime_r(&t, &local_time);
michael@0 700 #endif
michael@0 701 struct tm* tm_time = &local_time;
michael@0 702 stream_ << std::setfill('0')
michael@0 703 << std::setw(2) << 1 + tm_time->tm_mon
michael@0 704 << std::setw(2) << tm_time->tm_mday
michael@0 705 << '/'
michael@0 706 << std::setw(2) << tm_time->tm_hour
michael@0 707 << std::setw(2) << tm_time->tm_min
michael@0 708 << std::setw(2) << tm_time->tm_sec
michael@0 709 << ':';
michael@0 710 }
michael@0 711 if (log_tickcount)
michael@0 712 stream_ << TickCount() << ':';
michael@0 713 if (severity_ >= 0)
michael@0 714 stream_ << log_severity_names[severity_];
michael@0 715 else
michael@0 716 stream_ << "VERBOSE" << -severity_;
michael@0 717
michael@0 718 stream_ << ":" << filename << "(" << line << ")] ";
michael@0 719
michael@0 720 message_start_ = stream_.tellp();
michael@0 721 }
michael@0 722
michael@0 723 #if defined(OS_WIN)
michael@0 724 // This has already been defined in the header, but defining it again as DWORD
michael@0 725 // ensures that the type used in the header is equivalent to DWORD. If not,
michael@0 726 // the redefinition is a compile error.
michael@0 727 typedef DWORD SystemErrorCode;
michael@0 728 #endif
michael@0 729
michael@0 730 SystemErrorCode GetLastSystemErrorCode() {
michael@0 731 #if defined(OS_WIN)
michael@0 732 return ::GetLastError();
michael@0 733 #elif defined(OS_POSIX)
michael@0 734 return errno;
michael@0 735 #else
michael@0 736 #error Not implemented
michael@0 737 #endif
michael@0 738 }
michael@0 739
michael@0 740 #if defined(OS_WIN)
michael@0 741 Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
michael@0 742 int line,
michael@0 743 LogSeverity severity,
michael@0 744 SystemErrorCode err,
michael@0 745 const char* module)
michael@0 746 : err_(err),
michael@0 747 module_(module),
michael@0 748 log_message_(file, line, severity) {
michael@0 749 }
michael@0 750
michael@0 751 Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
michael@0 752 int line,
michael@0 753 LogSeverity severity,
michael@0 754 SystemErrorCode err)
michael@0 755 : err_(err),
michael@0 756 module_(NULL),
michael@0 757 log_message_(file, line, severity) {
michael@0 758 }
michael@0 759
michael@0 760 Win32ErrorLogMessage::~Win32ErrorLogMessage() {
michael@0 761 const int error_message_buffer_size = 256;
michael@0 762 char msgbuf[error_message_buffer_size];
michael@0 763 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
michael@0 764 HMODULE hmod;
michael@0 765 if (module_) {
michael@0 766 hmod = GetModuleHandleA(module_);
michael@0 767 if (hmod) {
michael@0 768 flags |= FORMAT_MESSAGE_FROM_HMODULE;
michael@0 769 } else {
michael@0 770 // This makes a nested Win32ErrorLogMessage. It will have module_ of NULL
michael@0 771 // so it will not call GetModuleHandle, so recursive errors are
michael@0 772 // impossible.
michael@0 773 DPLOG(WARNING) << "Couldn't open module " << module_
michael@0 774 << " for error message query";
michael@0 775 }
michael@0 776 } else {
michael@0 777 hmod = NULL;
michael@0 778 }
michael@0 779 DWORD len = FormatMessageA(flags,
michael@0 780 hmod,
michael@0 781 err_,
michael@0 782 0,
michael@0 783 msgbuf,
michael@0 784 sizeof(msgbuf) / sizeof(msgbuf[0]),
michael@0 785 NULL);
michael@0 786 if (len) {
michael@0 787 while ((len > 0) &&
michael@0 788 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
michael@0 789 msgbuf[--len] = 0;
michael@0 790 }
michael@0 791 stream() << ": " << msgbuf;
michael@0 792 } else {
michael@0 793 stream() << ": Error " << GetLastError() << " while retrieving error "
michael@0 794 << err_;
michael@0 795 }
michael@0 796 // We're about to crash (CHECK). Put |err_| on the stack (by placing it in a
michael@0 797 // field) and use Alias in hopes that it makes it into crash dumps.
michael@0 798 DWORD last_error = err_;
michael@0 799 base::debug::Alias(&last_error);
michael@0 800 }
michael@0 801 #elif defined(OS_POSIX)
michael@0 802 ErrnoLogMessage::ErrnoLogMessage(const char* file,
michael@0 803 int line,
michael@0 804 LogSeverity severity,
michael@0 805 SystemErrorCode err)
michael@0 806 : err_(err),
michael@0 807 log_message_(file, line, severity) {
michael@0 808 }
michael@0 809
michael@0 810 ErrnoLogMessage::~ErrnoLogMessage() {
michael@0 811 stream() << ": " << safe_strerror(err_);
michael@0 812 }
michael@0 813 #endif // OS_WIN
michael@0 814
michael@0 815 void CloseLogFile() {
michael@0 816 LoggingLock logging_lock;
michael@0 817 CloseLogFileUnlocked();
michael@0 818 }
michael@0 819
michael@0 820 void RawLog(int level, const char* message) {
michael@0 821 if (level >= min_log_level) {
michael@0 822 size_t bytes_written = 0;
michael@0 823 const size_t message_len = strlen(message);
michael@0 824 int rv;
michael@0 825 while (bytes_written < message_len) {
michael@0 826 rv = HANDLE_EINTR(
michael@0 827 write(STDERR_FILENO, message + bytes_written,
michael@0 828 message_len - bytes_written));
michael@0 829 if (rv < 0) {
michael@0 830 // Give up, nothing we can do now.
michael@0 831 break;
michael@0 832 }
michael@0 833 bytes_written += rv;
michael@0 834 }
michael@0 835
michael@0 836 if (message_len > 0 && message[message_len - 1] != '\n') {
michael@0 837 do {
michael@0 838 rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1));
michael@0 839 if (rv < 0) {
michael@0 840 // Give up, nothing we can do now.
michael@0 841 break;
michael@0 842 }
michael@0 843 } while (rv != 1);
michael@0 844 }
michael@0 845 }
michael@0 846
michael@0 847 if (level == LOG_FATAL)
michael@0 848 base::debug::BreakDebugger();
michael@0 849 }
michael@0 850
michael@0 851 // This was defined at the beginning of this file.
michael@0 852 #undef write
michael@0 853
michael@0 854 #if defined(OS_WIN)
michael@0 855 std::wstring GetLogFileFullPath() {
michael@0 856 if (log_file_name)
michael@0 857 return *log_file_name;
michael@0 858 return std::wstring();
michael@0 859 }
michael@0 860 #endif
michael@0 861
michael@0 862 } // namespace logging
michael@0 863
michael@0 864 std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
michael@0 865 return out << WideToUTF8(std::wstring(wstr));
michael@0 866 }

mercurial