From 8c3dd6d83df467f3b8e53b6c97545eabf07768be Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 18 Jun 2020 13:23:12 +0200 Subject: Upgrade Google libraries Upgrades Glog from 0.3.5 to 0.4.0, and Gtest from 0.8.0 to 0.10.0. Hopefully this will solve compilation error on MSVC with C++17. --- extern/glog/src/config.h | 4 - extern/glog/src/config_mac.h | 6 +- extern/glog/src/demangle.cc | 64 +++++++- extern/glog/src/logging.cc | 130 ++++++++++++--- extern/glog/src/raw_logging.cc | 16 +- extern/glog/src/signalhandler.cc | 44 ++++- extern/glog/src/stacktrace.h | 3 +- extern/glog/src/stacktrace_windows-inl.h | 50 ++++++ extern/glog/src/stacktrace_x86-inl.h | 15 +- extern/glog/src/symbolize.cc | 249 +++++++++++++++++++---------- extern/glog/src/symbolize.h | 15 +- extern/glog/src/utilities.cc | 42 ++++- extern/glog/src/utilities.h | 16 +- extern/glog/src/vlog_is_on.cc | 6 + extern/glog/src/windows/glog/logging.h | 35 ++-- extern/glog/src/windows/glog/raw_logging.h | 5 - extern/glog/src/windows/port.cc | 13 +- extern/glog/src/windows/port.h | 23 ++- extern/glog/src/windows/preprocess.sh | 2 +- 19 files changed, 543 insertions(+), 195 deletions(-) create mode 100644 extern/glog/src/stacktrace_windows-inl.h (limited to 'extern/glog/src') diff --git a/extern/glog/src/config.h b/extern/glog/src/config.h index 2703b7ba9dd..e4cde736d65 100644 --- a/extern/glog/src/config.h +++ b/extern/glog/src/config.h @@ -1,7 +1,3 @@ -/* src/config.h. Generated from config.h.in by configure. */ -/* src/config.h.in. Generated from configure.ac by autoheader. */ - -/* Namespace for Google classes */ #if defined(__APPLE__) #include "config_mac.h" #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) diff --git a/extern/glog/src/config_mac.h b/extern/glog/src/config_mac.h index 4f008b5f67c..57cc64a0a74 100644 --- a/extern/glog/src/config_mac.h +++ b/extern/glog/src/config_mac.h @@ -5,7 +5,7 @@ #define GOOGLE_NAMESPACE google /* Define if you have the `dladdr' function */ -/* #undef HAVE_DLADDR */ +#define HAVE_DLADDR /* Define if you have the `snprintf' function */ #define HAVE_SNPRINTF @@ -65,7 +65,7 @@ #define HAVE_PWRITE /* define if the compiler implements pthread_rwlock_* */ -/* #undef HAVE_RWLOCK */ +#define HAVE_RWLOCK /* Define if you have the 'sigaction' function */ #define HAVE_SIGACTION @@ -104,7 +104,7 @@ #define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ -#define HAVE_SYS_UCONTEXT_H 1 +/* #undef HAVE_SYS_UCONTEXT_H */ /* Define to 1 if you have the header file. */ #define HAVE_SYS_UTSNAME_H diff --git a/extern/glog/src/demangle.cc b/extern/glog/src/demangle.cc index e858181a68f..9369f9a65c2 100644 --- a/extern/glog/src/demangle.cc +++ b/extern/glog/src/demangle.cc @@ -30,15 +30,22 @@ // Author: Satoru Takabayashi // // For reference check out: -// http://www.codesourcery.com/public/cxx-abi/abi.html#mangling +// http://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling // // Note that we only have partial C++0x support yet. #include // for NULL +#include "utilities.h" #include "demangle.h" +#if defined(OS_WINDOWS) +#include +#pragma comment(lib, "dbghelp") +#endif + _START_GOOGLE_NAMESPACE_ +#if !defined(OS_WINDOWS) typedef struct { const char *abbrev; const char *real_name; @@ -416,6 +423,8 @@ static bool ParseNumber(State *state, int *number_out); static bool ParseFloatNumber(State *state); static bool ParseSeqId(State *state); static bool ParseIdentifier(State *state, int length); +static bool ParseAbiTags(State *state); +static bool ParseAbiTag(State *state); static bool ParseOperatorName(State *state); static bool ParseSpecialName(State *state); static bool ParseCallOffset(State *state); @@ -587,13 +596,13 @@ static bool ParsePrefix(State *state) { // ::= // ::= -// ::= -// ::= +// ::= [] +// ::= [] static bool ParseUnqualifiedName(State *state) { return (ParseOperatorName(state) || ParseCtorDtorName(state) || - ParseSourceName(state) || - ParseLocalSourceName(state)); + (ParseSourceName(state) && Optional(ParseAbiTags(state))) || + (ParseLocalSourceName(state) && Optional(ParseAbiTags(state)))); } // ::= @@ -696,6 +705,23 @@ static bool ParseIdentifier(State *state, int length) { return true; } +// ::= [] +static bool ParseAbiTags(State *state) { + State copy = *state; + DisableAppend(state); + if (OneOrMore(ParseAbiTag, state)) { + RestoreAppend(state, copy.append); + return true; + } + *state = copy; + return false; +} + +// ::= B +static bool ParseAbiTag(State *state) { + return ParseOneCharToken(state, 'B') && ParseSourceName(state); +} + // ::= nw, and other two letters cases // ::= cv # (cast) // ::= v # vendor extended operator @@ -1090,10 +1116,11 @@ static bool ParseTemplateArgs(State *state) { // ::= // ::= // ::= I * E # argument pack +// ::= J * E # argument pack // ::= X E static bool ParseTemplateArg(State *state) { State copy = *state; - if (ParseOneCharToken(state, 'I') && + if ((ParseOneCharToken(state, 'I') || ParseOneCharToken(state, 'J')) && ZeroOrMore(ParseTemplateArg, state) && ParseOneCharToken(state, 'E')) { return true; @@ -1293,12 +1320,37 @@ static bool ParseTopLevelMangledName(State *state) { } return false; } +#endif // The demangler entry point. bool Demangle(const char *mangled, char *out, int out_size) { +#if defined(OS_WINDOWS) + // When built with incremental linking, the Windows debugger + // library provides a more complicated `Symbol->Name` with the + // Incremental Linking Table offset, which looks like + // `@ILT+1105(?func@Foo@@SAXH@Z)`. However, the demangler expects + // only the mangled symbol, `?func@Foo@@SAXH@Z`. Fortunately, the + // mangled symbol is guaranteed not to have parentheses, + // so we search for `(` and extract up to `)`. + // + // Since we may be in a signal handler here, we cannot use `std::string`. + char buffer[1024]; // Big enough for a sane symbol. + const char *lparen = strchr(mangled, '('); + if (lparen) { + // Extract the string `(?...)` + const char *rparen = strchr(lparen, ')'); + size_t length = rparen - lparen - 1; + strncpy(buffer, lparen + 1, length); + buffer[length] = '\0'; + mangled = buffer; + } // Else the symbol wasn't inside a set of parentheses + // We use the ANSI version to ensure the string type is always `char *`. + return UnDecorateSymbolName(mangled, out, out_size, UNDNAME_COMPLETE); +#else State state; InitState(&state, mangled, out, out_size); return ParseTopLevelMangledName(&state) && !state.overflowed; +#endif } _END_GOOGLE_NAMESPACE_ diff --git a/extern/glog/src/logging.cc b/extern/glog/src/logging.cc index 3e8f48e814d..0c86cf62296 100644 --- a/extern/glog/src/logging.cc +++ b/extern/glog/src/logging.cc @@ -114,11 +114,6 @@ GLOG_DEFINE_bool(drop_log_memory, true, "Drop in-memory buffers of log contents. "Logs can grow very quickly and they are rarely read before they " "need to be evicted from memory. Instead, drop them from memory " "as soon as they are flushed to disk."); -_START_GOOGLE_NAMESPACE_ -namespace logging { -static const int64 kPageSize = getpagesize(); -} -_END_GOOGLE_NAMESPACE_ #endif // By default, errors (including fatal errors) get logged to stderr as @@ -188,7 +183,7 @@ GLOG_DEFINE_string(log_backtrace_at, "", #ifndef HAVE_PREAD #if defined(OS_WINDOWS) -#include +#include #define ssize_t SSIZE_T #endif static ssize_t pread(int fd, void* buf, size_t count, off_t offset) { @@ -304,7 +299,7 @@ static GLogColor SeverityToColor(LogSeverity severity) { #ifdef OS_WINDOWS // Returns the character attribute for the given color. -WORD GetColorAttribute(GLogColor color) { +static WORD GetColorAttribute(GLogColor color) { switch (color) { case COLOR_RED: return FOREGROUND_RED; case COLOR_GREEN: return FOREGROUND_GREEN; @@ -316,7 +311,7 @@ WORD GetColorAttribute(GLogColor color) { #else // Returns the ANSI color code for the given color. -const char* GetAnsiColorCode(GLogColor color) { +static const char* GetAnsiColorCode(GLogColor color) { switch (color) { case COLOR_RED: return "1"; case COLOR_GREEN: return "2"; @@ -441,6 +436,7 @@ class LogFileObject : public base::Logger { FILE* file_; LogSeverity severity_; uint32 bytes_since_flush_; + uint32 dropped_mem_length_; uint32 file_length_; unsigned int rollover_attempt_; int64 next_flush_time_; // cycle count at which to flush log @@ -842,6 +838,7 @@ LogFileObject::LogFileObject(LogSeverity severity, file_(NULL), severity_(severity), bytes_since_flush_(0), + dropped_mem_length_(0), file_length_(0), rollover_attempt_(kRolloverAttemptFrequency-1), next_flush_time_(0) { @@ -979,7 +976,7 @@ void LogFileObject::Write(bool force_flush, PidHasChanged()) { if (file_ != NULL) fclose(file_); file_ = NULL; - file_length_ = bytes_since_flush_ = 0; + file_length_ = bytes_since_flush_ = dropped_mem_length_ = 0; rollover_attempt_ = kRolloverAttemptFrequency-1; } @@ -1119,11 +1116,17 @@ void LogFileObject::Write(bool force_flush, (CycleClock_Now() >= next_flush_time_) ) { FlushUnlocked(); #ifdef OS_LINUX - if (FLAGS_drop_log_memory) { - if (file_length_ >= logging::kPageSize) { - // don't evict the most recent page - uint32 len = file_length_ & ~(logging::kPageSize - 1); - posix_fadvise(fileno(file_), 0, len, POSIX_FADV_DONTNEED); + // Only consider files >= 3MiB + if (FLAGS_drop_log_memory && file_length_ >= (3 << 20)) { + // Don't evict the most recent 1-2MiB so as not to impact a tailer + // of the log file and to avoid page rounding issue on linux < 4.7 + uint32 total_drop_length = (file_length_ & ~((1 << 20) - 1)) - (1 << 20); + uint32 this_drop_length = total_drop_length - dropped_mem_length_; + if (this_drop_length >= (2 << 20)) { + // Only advise when >= 2MiB to drop + posix_fadvise(fileno(file_), dropped_mem_length_, this_drop_length, + POSIX_FADV_DONTNEED); + dropped_mem_length_ = total_drop_length; } } #endif @@ -1145,6 +1148,22 @@ static bool fatal_msg_exclusive = true; static LogMessage::LogMessageData fatal_msg_data_exclusive; static LogMessage::LogMessageData fatal_msg_data_shared; +#ifdef GLOG_THREAD_LOCAL_STORAGE +// Static thread-local log data space to use, because typically at most one +// LogMessageData object exists (in this case glog makes zero heap memory +// allocations). +static GLOG_THREAD_LOCAL_STORAGE bool thread_data_available = true; + +#ifdef HAVE_ALIGNED_STORAGE +static GLOG_THREAD_LOCAL_STORAGE + std::aligned_storage::type thread_msg_data; +#else +static GLOG_THREAD_LOCAL_STORAGE + char thread_msg_data[sizeof(void*) + sizeof(LogMessage::LogMessageData)]; +#endif // HAVE_ALIGNED_STORAGE +#endif // defined(GLOG_THREAD_LOCAL_STORAGE) + LogMessage::LogMessageData::LogMessageData() : stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) { } @@ -1201,8 +1220,28 @@ void LogMessage::Init(const char* file, void (LogMessage::*send_method)()) { allocated_ = NULL; if (severity != GLOG_FATAL || !exit_on_dfatal) { +#ifdef GLOG_THREAD_LOCAL_STORAGE + // No need for locking, because this is thread local. + if (thread_data_available) { + thread_data_available = false; +#ifdef HAVE_ALIGNED_STORAGE + data_ = new (&thread_msg_data) LogMessageData; +#else + const uintptr_t kAlign = sizeof(void*) - 1; + + char* align_ptr = + reinterpret_cast(reinterpret_cast(thread_msg_data + kAlign) & ~kAlign); + data_ = new (align_ptr) LogMessageData; + assert(reinterpret_cast(align_ptr) % sizeof(void*) == 0); +#endif + } else { + allocated_ = new LogMessageData(); + data_ = allocated_; + } +#else // !defined(GLOG_THREAD_LOCAL_STORAGE) allocated_ = new LogMessageData(); data_ = allocated_; +#endif // defined(GLOG_THREAD_LOCAL_STORAGE) data_->first_fatal_ = false; } else { MutexLock l(&fatal_msg_lock); @@ -1227,7 +1266,6 @@ void LogMessage::Init(const char* file, data_->timestamp_ = static_cast(now); localtime_r(&data_->timestamp_, &data_->tm_time_); int usecs = static_cast((now - data_->timestamp_) * 1000000); - RawLog__SetLastTime(data_->tm_time_, usecs); data_->num_chars_to_log_ = 0; data_->num_chars_to_syslog_ = 0; @@ -1271,7 +1309,17 @@ void LogMessage::Init(const char* file, LogMessage::~LogMessage() { Flush(); +#ifdef GLOG_THREAD_LOCAL_STORAGE + if (data_ == static_cast(&thread_msg_data)) { + data_->~LogMessageData(); + thread_data_available = true; + } + else { + delete allocated_; + } +#else // !defined(GLOG_THREAD_LOCAL_STORAGE) delete allocated_; +#endif // defined(GLOG_THREAD_LOCAL_STORAGE) } int LogMessage::preserved_errno() const { @@ -1466,16 +1514,13 @@ void LogMessage::RecordCrashReason( # define ATTRIBUTE_NORETURN #endif +#if defined(OS_WINDOWS) +__declspec(noreturn) +#endif static void logging_fail() ATTRIBUTE_NORETURN; static void logging_fail() { -#if defined(_DEBUG) && defined(_MSC_VER) - // When debugging on windows, avoid the obnoxious dialog and make - // it possible to continue past a LOG(FATAL) in the debugger - __debugbreak(); -#else abort(); -#endif } typedef void (*logging_fail_func_t)() ATTRIBUTE_NORETURN; @@ -1681,6 +1726,7 @@ void LogToStderr() { namespace base { namespace internal { +bool GetExitOnDFatal(); bool GetExitOnDFatal() { MutexLock l(&log_mutex); return exit_on_dfatal; @@ -1696,6 +1742,7 @@ bool GetExitOnDFatal() { // and the stack trace is not recorded. The LOG(FATAL) *will* still // exit the program. Since this function is used only in testing, // these differences are acceptable. +void SetExitOnDFatal(bool value); void SetExitOnDFatal(bool value) { MutexLock l(&log_mutex); exit_on_dfatal = value; @@ -1704,6 +1751,42 @@ void SetExitOnDFatal(bool value) { } // namespace internal } // namespace base +// Shell-escaping as we need to shell out ot /bin/mail. +static const char kDontNeedShellEscapeChars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+-_.=/:,@"; + +static string ShellEscape(const string& src) { + string result; + if (!src.empty() && // empty string needs quotes + src.find_first_not_of(kDontNeedShellEscapeChars) == string::npos) { + // only contains chars that don't need quotes; it's fine + result.assign(src); + } else if (src.find_first_of('\'') == string::npos) { + // no single quotes; just wrap it in single quotes + result.assign("'"); + result.append(src); + result.append("'"); + } else { + // needs double quote escaping + result.assign("\""); + for (size_t i = 0; i < src.size(); ++i) { + switch (src[i]) { + case '\\': + case '$': + case '"': + case '`': + result.append("\\"); + } + result.append(src, i, 1); + } + result.append("\""); + } + return result; +} + + // use_logging controls whether the logging functions LOG/VLOG are used // to log errors. It should be set to false when the caller holds the // log_mutex. @@ -1719,7 +1802,10 @@ static bool SendEmailInternal(const char*dest, const char *subject, } string cmd = - FLAGS_logmailer + " -s\"" + subject + "\" " + dest; + FLAGS_logmailer + " -s" + + ShellEscape(subject) + " " + ShellEscape(dest); + VLOG(4) << "Mailing command: " << cmd; + FILE* pipe = popen(cmd.c_str(), "w"); if (pipe != NULL) { // Add the body if we have one diff --git a/extern/glog/src/raw_logging.cc b/extern/glog/src/raw_logging.cc index 7a7409bbf34..3bbfda31868 100644 --- a/extern/glog/src/raw_logging.cc +++ b/extern/glog/src/raw_logging.cc @@ -68,17 +68,6 @@ _START_GOOGLE_NAMESPACE_ -// Data for RawLog__ below. We simply pick up the latest -// time data created by a normal log message to avoid calling -// localtime_r which can allocate memory. -static struct ::tm last_tm_time_for_raw_log; -static int last_usecs_for_raw_log; - -void RawLog__SetLastTime(const struct ::tm& t, int usecs) { - memcpy(&last_tm_time_for_raw_log, &t, sizeof(last_tm_time_for_raw_log)); - last_usecs_for_raw_log = usecs; -} - // CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths // that invoke malloc() and getenv() that might acquire some locks. // If this becomes a problem we should reimplement a subset of vsnprintf @@ -120,16 +109,13 @@ void RawLog__(LogSeverity severity, const char* file, int line, return; // this stderr log message is suppressed } // can't call localtime_r here: it can allocate - struct ::tm& t = last_tm_time_for_raw_log; char buffer[kLogBufSize]; char* buf = buffer; int size = sizeof(buffer); // NOTE: this format should match the specification in base/logging.h - DoRawLog(&buf, &size, "%c%02d%02d %02d:%02d:%02d.%06d %5u %s:%d] RAW: ", + DoRawLog(&buf, &size, "%c0000 00:00:00.000000 %5u %s:%d] RAW: ", LogSeverityNames[severity][0], - 1 + t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, - last_usecs_for_raw_log, static_cast(GetTID()), const_basename(const_cast(file)), line); diff --git a/extern/glog/src/signalhandler.cc b/extern/glog/src/signalhandler.cc index a7aef8b99d2..961ee965196 100644 --- a/extern/glog/src/signalhandler.cc +++ b/extern/glog/src/signalhandler.cc @@ -48,9 +48,6 @@ _START_GOOGLE_NAMESPACE_ -// TOOD(hamaji): Use signal instead of sigaction? -#ifdef HAVE_SIGACTION - namespace { // We'll install the failure signal handler for these signals. We could @@ -66,10 +63,14 @@ const struct { { SIGILL, "SIGILL" }, { SIGFPE, "SIGFPE" }, { SIGABRT, "SIGABRT" }, +#if !defined(OS_WINDOWS) { SIGBUS, "SIGBUS" }, +#endif { SIGTERM, "SIGTERM" }, }; +static bool kFailureSignalHandlerInstalled = false; + // Returns the program counter from signal context, NULL if unknown. void* GetPC(void* ucontext_in_void) { #if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT) @@ -92,7 +93,7 @@ class MinimalFormatter { } // Returns the number of bytes written in the buffer. - int num_bytes_written() const { return cursor_ - buffer_; } + int num_bytes_written() const { return (int) (cursor_ - buffer_); } // Appends string from "str" and updates the internal cursor. void AppendString(const char* str) { @@ -168,6 +169,9 @@ void DumpTimeInfo() { g_failure_writer(buf, formatter.num_bytes_written()); } +// TOOD(hamaji): Use signal instead of sigaction? +#ifdef HAVE_SIGACTION + // Dumps information about the signal to STDERR. void DumpSignalInfo(int signal_number, siginfo_t *siginfo) { // Get the signal name. @@ -213,6 +217,8 @@ void DumpSignalInfo(int signal_number, siginfo_t *siginfo) { g_failure_writer(buf, formatter.num_bytes_written()); } +#endif // HAVE_SIGACTION + // Dumps information about the stack frame to STDERR. void DumpStackFrameInfo(const char* prefix, void* pc) { // Get the symbol name. @@ -240,12 +246,17 @@ void DumpStackFrameInfo(const char* prefix, void* pc) { // Invoke the default signal handler. void InvokeDefaultSignalHandler(int signal_number) { +#ifdef HAVE_SIGACTION struct sigaction sig_action; memset(&sig_action, 0, sizeof(sig_action)); sigemptyset(&sig_action.sa_mask); sig_action.sa_handler = SIG_DFL; sigaction(signal_number, &sig_action, NULL); kill(getpid(), signal_number); +#elif defined(OS_WINDOWS) + signal(signal_number, SIG_DFL); + raise(signal_number); +#endif } // This variable is used for protecting FailureSignalHandler() from @@ -256,9 +267,14 @@ static pthread_t* g_entered_thread_id_pointer = NULL; // Dumps signal and stack frame information, and invokes the default // signal handler once our job is done. +#if defined(OS_WINDOWS) +void FailureSignalHandler(int signal_number) +#else void FailureSignalHandler(int signal_number, siginfo_t *signal_info, - void *ucontext) { + void *ucontext) +#endif +{ // First check if we've already entered the function. We use an atomic // compare and swap operation for platforms that support it. For other // platforms, we use a naive method that could lead to a subtle race. @@ -298,16 +314,20 @@ void FailureSignalHandler(int signal_number, // First dump time info. DumpTimeInfo(); +#if !defined(OS_WINDOWS) // Get the program counter from ucontext. void *pc = GetPC(ucontext); DumpStackFrameInfo("PC: ", pc); +#endif #ifdef HAVE_STACKTRACE // Get the stack traces. void *stack[32]; // +1 to exclude this function. const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1); +# ifdef HAVE_SIGACTION DumpSignalInfo(signal_number, signal_info); +# endif // Dump the stack traces. for (int i = 0; i < depth; ++i) { DumpStackFrameInfo(" ", stack[i]); @@ -333,18 +353,19 @@ void FailureSignalHandler(int signal_number, } // namespace -#endif // HAVE_SIGACTION - namespace glog_internal_namespace_ { bool IsFailureSignalHandlerInstalled() { #ifdef HAVE_SIGACTION + // TODO(andschwa): Return kFailureSignalHandlerInstalled? struct sigaction sig_action; memset(&sig_action, 0, sizeof(sig_action)); sigemptyset(&sig_action.sa_mask); sigaction(SIGABRT, NULL, &sig_action); if (sig_action.sa_sigaction == &FailureSignalHandler) return true; +#elif defined(OS_WINDOWS) + return kFailureSignalHandlerInstalled; #endif // HAVE_SIGACTION return false; } @@ -363,11 +384,18 @@ void InstallFailureSignalHandler() { for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) { CHECK_ERR(sigaction(kFailureSignals[i].number, &sig_action, NULL)); } + kFailureSignalHandlerInstalled = true; +#elif defined(OS_WINDOWS) + for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) { + CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler), + SIG_ERR); + } + kFailureSignalHandlerInstalled = true; #endif // HAVE_SIGACTION } void InstallFailureWriter(void (*writer)(const char* data, int size)) { -#ifdef HAVE_SIGACTION +#if defined(HAVE_SIGACTION) || defined(OS_WINDOWS) g_failure_writer = writer; #endif // HAVE_SIGACTION } diff --git a/extern/glog/src/stacktrace.h b/extern/glog/src/stacktrace.h index 8c3e8fe8f8d..cb64b33a688 100644 --- a/extern/glog/src/stacktrace.h +++ b/extern/glog/src/stacktrace.h @@ -34,6 +34,7 @@ #define BASE_STACKTRACE_H_ #include "config.h" +#include "glog/logging.h" _START_GOOGLE_NAMESPACE_ @@ -53,7 +54,7 @@ _START_GOOGLE_NAMESPACE_ // .... ... // // "result" must not be NULL. -extern int GetStackTrace(void** result, int max_depth, int skip_count); +GOOGLE_GLOG_DLL_DECL int GetStackTrace(void** result, int max_depth, int skip_count); _END_GOOGLE_NAMESPACE_ diff --git a/extern/glog/src/stacktrace_windows-inl.h b/extern/glog/src/stacktrace_windows-inl.h new file mode 100644 index 00000000000..726318879d8 --- /dev/null +++ b/extern/glog/src/stacktrace_windows-inl.h @@ -0,0 +1,50 @@ +// Copyright (c) 2000 - 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Andrew Schwartzmeyer +// +// Windows implementation - just use CaptureStackBackTrace + +#include "config.h" +#include "port.h" +#include "stacktrace.h" +#include + +_START_GOOGLE_NAMESPACE_ + +int GetStackTrace(void** result, int max_depth, int skip_count) { + if (max_depth > 64) { + max_depth = 64; + } + skip_count++; // we want to skip the current frame as well + // This API is thread-safe (moreover it walks only the current thread). + return CaptureStackBackTrace(skip_count, max_depth, result, NULL); +} + +_END_GOOGLE_NAMESPACE_ diff --git a/extern/glog/src/stacktrace_x86-inl.h b/extern/glog/src/stacktrace_x86-inl.h index cfd31f783e3..3b8d5a8282d 100644 --- a/extern/glog/src/stacktrace_x86-inl.h +++ b/extern/glog/src/stacktrace_x86-inl.h @@ -93,16 +93,23 @@ static void **NextStackFrame(void **old_sp) { // If you change this function, also change GetStackFrames below. int GetStackTrace(void** result, int max_depth, int skip_count) { void **sp; -#ifdef __i386__ + +#ifdef __GNUC__ +#if __GNUC__ * 100 + __GNUC_MINOR__ >= 402 +#define USE_BUILTIN_FRAME_ADDRESS +#endif +#endif + +#ifdef USE_BUILTIN_FRAME_ADDRESS + sp = reinterpret_cast(__builtin_frame_address(0)); +#elif defined(__i386__) // Stack frame format: // sp[0] pointer to previous frame // sp[1] caller address // sp[2] first argument // ... sp = (void **)&result - 2; -#endif - -#ifdef __x86_64__ +#elif defined(__x86_64__) // __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8 unsigned long rbp; // Move the value of the register %rbp into the local variable rbp. diff --git a/extern/glog/src/symbolize.cc b/extern/glog/src/symbolize.cc index f83c309738e..1ffc6079a2a 100644 --- a/extern/glog/src/symbolize.cc +++ b/extern/glog/src/symbolize.cc @@ -56,6 +56,9 @@ #if defined(HAVE_SYMBOLIZE) +#include + +#include #include #include "symbolize.h" @@ -134,17 +137,20 @@ _END_GOOGLE_NAMESPACE_ _START_GOOGLE_NAMESPACE_ -// Read up to "count" bytes from file descriptor "fd" into the buffer -// starting at "buf" while handling short reads and EINTR. On -// success, return the number of bytes read. Otherwise, return -1. -static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) { +// Read up to "count" bytes from "offset" in the file pointed by file +// descriptor "fd" into the buffer starting at "buf" while handling short reads +// and EINTR. On success, return the number of bytes read. Otherwise, return +// -1. +static ssize_t ReadFromOffset(const int fd, void *buf, const size_t count, + const off_t offset) { SAFE_ASSERT(fd >= 0); SAFE_ASSERT(count <= std::numeric_limits::max()); char *buf0 = reinterpret_cast(buf); ssize_t num_bytes = 0; while (num_bytes < count) { ssize_t len; - NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes)); + NO_INTR(len = pread(fd, buf0 + num_bytes, count - num_bytes, + offset + num_bytes)); if (len < 0) { // There was an error other than EINTR. return -1; } @@ -157,18 +163,6 @@ static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) { return num_bytes; } -// Read up to "count" bytes from "offset" in the file pointed by file -// descriptor "fd" into the buffer starting at "buf". On success, -// return the number of bytes read. Otherwise, return -1. -static ssize_t ReadFromOffset(const int fd, void *buf, - const size_t count, const off_t offset) { - off_t off = lseek(fd, offset, SEEK_SET); - if (off == (off_t)-1) { - return -1; - } - return ReadPersistent(fd, buf, count); -} - // Try reading exactly "count" bytes from "offset" bytes in a file // pointed by "fd" into the buffer starting at "buf" while handling // short reads and EINTR. On success, return true. Otherwise, return @@ -207,6 +201,9 @@ GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const off_t sh_offset, (sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf); const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read, sh_offset + i * sizeof(buf[0])); + if (len == -1) { + return false; + } SAFE_ASSERT(len % sizeof(buf[0]) == 0); const ssize_t num_headers_in_buf = len / sizeof(buf[0]); SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0])); @@ -296,10 +293,12 @@ FindSymbol(uint64_t pc, const int fd, char *out, int out_size, // Read at most NUM_SYMBOLS symbols at once to save read() calls. ElfW(Sym) buf[NUM_SYMBOLS]; - const ssize_t len = ReadFromOffset(fd, &buf, sizeof(buf), offset); + int num_symbols_to_read = std::min(NUM_SYMBOLS, num_symbols - i); + const ssize_t len = + ReadFromOffset(fd, &buf, sizeof(buf[0]) * num_symbols_to_read, offset); SAFE_ASSERT(len % sizeof(buf[0]) == 0); const ssize_t num_symbols_in_buf = len / sizeof(buf[0]); - SAFE_ASSERT(num_symbols_in_buf <= sizeof(buf)/sizeof(buf[0])); + SAFE_ASSERT(num_symbols_in_buf <= num_symbols_to_read); for (int j = 0; j < num_symbols_in_buf; ++j) { const ElfW(Sym)& symbol = buf[j]; uint64_t start_address = symbol.st_value; @@ -325,41 +324,17 @@ FindSymbol(uint64_t pc, const int fd, char *out, int out_size, // both regular and dynamic symbol tables if necessary. On success, // write the symbol name to "out" and return true. Otherwise, return // false. -static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, - char *out, int out_size, - uint64_t map_base_address) { +static bool GetSymbolFromObjectFile(const int fd, + uint64_t pc, + char* out, + int out_size, + uint64_t base_address) { // Read the ELF header. ElfW(Ehdr) elf_header; if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) { return false; } - uint64_t symbol_offset = 0; - if (elf_header.e_type == ET_DYN) { // DSO needs offset adjustment. - ElfW(Phdr) phdr; - // We need to find the PT_LOAD segment corresponding to the read-execute - // file mapping in order to correctly perform the offset adjustment. - for (unsigned i = 0; i != elf_header.e_phnum; ++i) { - if (!ReadFromOffsetExact(fd, &phdr, sizeof(phdr), - elf_header.e_phoff + i * sizeof(phdr))) - return false; - if (phdr.p_type == PT_LOAD && - (phdr.p_flags & (PF_R | PF_X)) == (PF_R | PF_X)) { - // Find the mapped address corresponding to virtual address zero. We do - // this by first adding p_offset. This gives us the mapped address of - // the start of the segment, or in other words the mapped address - // corresponding to the virtual address of the segment. (Note that this - // is distinct from the start address, as p_offset is not guaranteed to - // be page aligned.) We then subtract p_vaddr, which takes us to virtual - // address zero. - symbol_offset = map_base_address + phdr.p_offset - phdr.p_vaddr; - break; - } - } - if (symbol_offset == 0) - return false; - } - ElfW(Shdr) symtab, strtab; // Consult a regular symbol table first. @@ -369,8 +344,7 @@ static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, symtab.sh_link * sizeof(symtab))) { return false; } - if (FindSymbol(pc, fd, out, out_size, symbol_offset, - &strtab, &symtab)) { + if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) { return true; // Found the symbol in a regular symbol table. } } @@ -382,8 +356,7 @@ static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, symtab.sh_link * sizeof(symtab))) { return false; } - if (FindSymbol(pc, fd, out, out_size, symbol_offset, - &strtab, &symtab)) { + if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) { return true; // Found the symbol in a dynamic symbol table. } } @@ -416,9 +389,14 @@ struct FileDescriptor { // and snprintf(). class LineReader { public: - explicit LineReader(int fd, char *buf, int buf_len) : fd_(fd), - buf_(buf), buf_len_(buf_len), bol_(buf), eol_(buf), eod_(buf) { - } + explicit LineReader(int fd, char *buf, int buf_len, off_t offset) + : fd_(fd), + buf_(buf), + buf_len_(buf_len), + offset_(offset), + bol_(buf), + eol_(buf), + eod_(buf) {} // Read '\n'-terminated line from file. On success, modify "bol" // and "eol", then return true. Otherwise, return false. @@ -427,10 +405,11 @@ class LineReader { // dropped. It's an intentional behavior to make the code simple. bool ReadLine(const char **bol, const char **eol) { if (BufferIsEmpty()) { // First time. - const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_); + const ssize_t num_bytes = ReadFromOffset(fd_, buf_, buf_len_, offset_); if (num_bytes <= 0) { // EOF or error. return false; } + offset_ += num_bytes; eod_ = buf_ + num_bytes; bol_ = buf_; } else { @@ -443,11 +422,12 @@ class LineReader { // Read text from file and append it. char * const append_pos = buf_ + incomplete_line_length; const int capacity_left = buf_len_ - incomplete_line_length; - const ssize_t num_bytes = ReadPersistent(fd_, append_pos, - capacity_left); + const ssize_t num_bytes = + ReadFromOffset(fd_, append_pos, capacity_left, offset_); if (num_bytes <= 0) { // EOF or error. return false; } + offset_ += num_bytes; eod_ = append_pos + num_bytes; bol_ = buf_; } @@ -492,6 +472,7 @@ class LineReader { const int fd_; char * const buf_; const int buf_len_; + off_t offset_; char *bol_; char *eol_; const char *eod_; // End of data in "buf_". @@ -532,7 +513,6 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc, int out_file_name_size) { int object_fd; - // Open /proc/self/maps. int maps_fd; NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY)); FileDescriptor wrapped_maps_fd(maps_fd); @@ -540,11 +520,18 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc, return -1; } + int mem_fd; + NO_INTR(mem_fd = open("/proc/self/mem", O_RDONLY)); + FileDescriptor wrapped_mem_fd(mem_fd); + if (wrapped_mem_fd.get() < 0) { + return -1; + } + // Iterate over maps and look for the map containing the pc. Then // look into the symbol tables inside. char buf[1024]; // Big enough for line of sane /proc/self/maps int num_maps = 0; - LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf)); + LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf), 0); while (true) { num_maps++; const char *cursor; @@ -575,11 +562,6 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc, } ++cursor; // Skip ' '. - // Check start and end addresses. - if (!(start_address <= pc && pc < end_address)) { - continue; // We skip this map. PC isn't in this map. - } - // Read flags. Skip flags until we encounter a space or eol. const char * const flags_start = cursor; while (cursor < eol && *cursor != ' ') { @@ -590,6 +572,49 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc, return -1; // Malformed line. } + // Determine the base address by reading ELF headers in process memory. + ElfW(Ehdr) ehdr; + // Skip non-readable maps. + if (flags_start[0] == 'r' && + ReadFromOffsetExact(mem_fd, &ehdr, sizeof(ElfW(Ehdr)), start_address) && + memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) { + switch (ehdr.e_type) { + case ET_EXEC: + base_address = 0; + break; + case ET_DYN: + // Find the segment containing file offset 0. This will correspond + // to the ELF header that we just read. Normally this will have + // virtual address 0, but this is not guaranteed. We must subtract + // the virtual address from the address where the ELF header was + // mapped to get the base address. + // + // If we fail to find a segment for file offset 0, use the address + // of the ELF header as the base address. + base_address = start_address; + for (unsigned i = 0; i != ehdr.e_phnum; ++i) { + ElfW(Phdr) phdr; + if (ReadFromOffsetExact( + mem_fd, &phdr, sizeof(phdr), + start_address + ehdr.e_phoff + i * sizeof(phdr)) && + phdr.p_type == PT_LOAD && phdr.p_offset == 0) { + base_address = start_address - phdr.p_vaddr; + break; + } + } + break; + default: + // ET_REL or ET_CORE. These aren't directly executable, so they don't + // affect the base address. + break; + } + } + + // Check start and end addresses. + if (!(start_address <= pc && pc < end_address)) { + continue; // We skip this map. PC isn't in this map. + } + // Check flags. We are only interested in "r*x" maps. if (flags_start[0] != 'r' || flags_start[2] != 'x') { continue; // We skip this map. @@ -604,19 +629,6 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc, } ++cursor; // Skip ' '. - // Don't subtract 'start_address' from the first entry: - // * If a binary is compiled w/o -pie, then the first entry in - // process maps is likely the binary itself (all dynamic libs - // are mapped higher in address space). For such a binary, - // instruction offset in binary coincides with the actual - // instruction address in virtual memory (as code section - // is mapped to a fixed memory range). - // * If a binary is compiled with -pie, all the modules are - // mapped high at address space (in particular, higher than - // shadow memory of the tool), so the module can't be the - // first entry. - base_address = ((num_maps == 1) ? 0U : start_address) - file_offset; - // Skip to file name. "cursor" now points to dev. We need to // skip at least two spaces for dev and inode. int num_spaces = 0; @@ -655,7 +667,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc, // bytes. Output will be truncated as needed, and a NUL character is always // appended. // NOTE: code from sandbox/linux/seccomp-bpf/demo.cc. -char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) { +static char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) { // Make sure we can write at least one NUL byte. size_t n = 1; if (n > sz) @@ -672,7 +684,8 @@ char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) { // Handle negative numbers (only for base 10). if (i < 0 && base == 10) { - j = -i; + // This does "j = -i" while avoiding integer overflow. + j = static_cast(-(i + 1)) + 1; // Make sure we can write the '-' character. if (++n > sz) { @@ -717,7 +730,7 @@ char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) { // Safely appends string |source| to string |dest|. Never writes past the // buffer size |dest_size| and guarantees that |dest| is null-terminated. -void SafeAppendString(const char* source, char* dest, int dest_size) { +static void SafeAppendString(const char* source, char* dest, int dest_size) { int dest_string_length = strlen(dest); SAFE_ASSERT(dest_string_length < dest_size); dest += dest_string_length; @@ -730,7 +743,7 @@ void SafeAppendString(const char* source, char* dest, int dest_size) { // Converts a 64-bit value into a hex string, and safely appends it to |dest|. // Never writes past the buffer size |dest_size| and guarantees that |dest| is // null-terminated. -void SafeAppendHexNumber(uint64_t value, char* dest, int dest_size) { +static void SafeAppendHexNumber(uint64_t value, char* dest, int dest_size) { // 64-bit numbers in hex can have up to 16 digits. char buf[17] = {'\0'}; SafeAppendString(itoa_r(value, buf, sizeof(buf), 16, 0), dest, dest_size); @@ -768,8 +781,13 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out, out_size - 1); } +#if defined(PRINT_UNSYMBOLIZED_STACK_TRACES) + { + FileDescriptor wrapped_object_fd(object_fd); +#else // Check whether a file name was returned. if (object_fd < 0) { +#endif if (out[1]) { // The object file containing PC was determined successfully however the // object file was not opened successfully. This is still considered @@ -793,7 +811,7 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out, // Run the call back if it's installed. // Note: relocation (and much of the rest of this code) will be // wrong for prelinked shared libraries and PIE executables. - uint64 relocation = (elf_type == ET_DYN) ? start_address : 0; + uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0; int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(), pc, out, out_size, relocation); @@ -837,6 +855,71 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out, _END_GOOGLE_NAMESPACE_ +#elif defined(OS_WINDOWS) || defined(OS_CYGWIN) + +#include +#include + +#ifdef _MSC_VER +#pragma comment(lib, "dbghelp") +#endif + +_START_GOOGLE_NAMESPACE_ + +class SymInitializer { +public: + HANDLE process; + bool ready; + SymInitializer() : process(NULL), ready(false) { + // Initialize the symbol handler. + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680344(v=vs.85).aspx + process = GetCurrentProcess(); + // Defer symbol loading. + // We do not request undecorated symbols with SYMOPT_UNDNAME + // because the mangling library calls UnDecorateSymbolName. + SymSetOptions(SYMOPT_DEFERRED_LOADS); + if (SymInitialize(process, NULL, true)) { + ready = true; + } + } + ~SymInitializer() { + SymCleanup(process); + // We do not need to close `HANDLE process` because it's a "pseudo handle." + } +private: + SymInitializer(const SymInitializer&); + SymInitializer& operator=(const SymInitializer&); +}; + +static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out, + int out_size) { + const static SymInitializer symInitializer; + if (!symInitializer.ready) { + return false; + } + // Resolve symbol information from address. + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx + char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; + SYMBOL_INFO *symbol = reinterpret_cast(buf); + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + symbol->MaxNameLen = MAX_SYM_NAME; + // We use the ANSI version to ensure the string type is always `char *`. + // This could break if a symbol has Unicode in it. + BOOL ret = SymFromAddr(symInitializer.process, + reinterpret_cast(pc), 0, symbol); + if (ret == 1 && static_cast(symbol->NameLen) < out_size) { + // `NameLen` does not include the null terminating character. + strncpy(out, symbol->Name, static_cast(symbol->NameLen) + 1); + out[static_cast(symbol->NameLen)] = '\0'; + // Symbolization succeeded. Now we try to demangle the symbol. + DemangleInplace(out, out_size); + return true; + } + return false; +} + +_END_GOOGLE_NAMESPACE_ + #else # error BUG: HAVE_SYMBOLIZE was wrongly set #endif diff --git a/extern/glog/src/symbolize.h b/extern/glog/src/symbolize.h index f617184249c..c6f9ec4360e 100644 --- a/extern/glog/src/symbolize.h +++ b/extern/glog/src/symbolize.h @@ -116,8 +116,11 @@ _START_GOOGLE_NAMESPACE_ // counter "pc". The callback function should write output to "out" // and return the size of the output written. On error, the callback // function should return -1. -typedef int (*SymbolizeCallback)(int fd, void *pc, char *out, size_t out_size, - uint64 relocation); +typedef int (*SymbolizeCallback)(int fd, + void* pc, + char* out, + size_t out_size, + uint64_t relocation); void InstallSymbolizeCallback(SymbolizeCallback callback); // Installs a callback function, which will be called instead of @@ -131,9 +134,9 @@ void InstallSymbolizeCallback(SymbolizeCallback callback); // returns -1. |out_file_name_size| is the size of the file name buffer // (including the null-terminator). typedef int (*SymbolizeOpenObjectFileCallback)(uint64_t pc, - uint64_t &start_address, - uint64_t &base_address, - char *out_file_name, + uint64_t& start_address, + uint64_t& base_address, + char* out_file_name, int out_file_name_size); void InstallSymbolizeOpenObjectFileCallback( SymbolizeOpenObjectFileCallback callback); @@ -148,7 +151,7 @@ _START_GOOGLE_NAMESPACE_ // symbol name to "out". The symbol name is demangled if possible // (supports symbols generated by GCC 3.x or newer). Otherwise, // returns false. -bool Symbolize(void *pc, char *out, int out_size); +GOOGLE_GLOG_DLL_DECL bool Symbolize(void *pc, char *out, int out_size); _END_GOOGLE_NAMESPACE_ diff --git a/extern/glog/src/utilities.cc b/extern/glog/src/utilities.cc index 5c88e58d3c0..25c4b760f1c 100644 --- a/extern/glog/src/utilities.cc +++ b/extern/glog/src/utilities.cc @@ -47,6 +47,12 @@ #ifdef HAVE_SYSLOG_H # include #endif +#ifdef HAVE_UNISTD_H +# include // For geteuid. +#endif +#ifdef HAVE_PWD_H +# include +#endif #include "base/googleinit.h" @@ -84,7 +90,7 @@ static void DebugWriteToStderr(const char* data, void *) { } } -void DebugWriteToString(const char* data, void *arg) { +static void DebugWriteToString(const char* data, void *arg) { reinterpret_cast(arg)->append(data); } @@ -137,17 +143,19 @@ static void DumpStackTraceAndExit() { DumpStackTrace(1, DebugWriteToStderr, NULL); // TOOD(hamaji): Use signal instead of sigaction? -#ifdef HAVE_SIGACTION if (IsFailureSignalHandlerInstalled()) { // Set the default signal handler for SIGABRT, to avoid invoking our // own signal handler installed by InstallFailureSignalHandler(). +#ifdef HAVE_SIGACTION struct sigaction sig_action; memset(&sig_action, 0, sizeof(sig_action)); sigemptyset(&sig_action.sa_mask); sig_action.sa_handler = SIG_DFL; sigaction(SIGABRT, &sig_action, NULL); - } +#elif defined(OS_WINDOWS) + signal(SIGABRT, SIG_DFL); #endif // HAVE_SIGACTION + } abort(); } @@ -266,7 +274,7 @@ pid_t GetTID() { // If gettid() could not be used, we use one of the following. #if defined OS_LINUX return getpid(); // Linux: getpid returns thread ID when gettid is absent -#elif defined OS_WINDOWS || defined OS_CYGWIN +#elif defined OS_WINDOWS && !defined OS_CYGWIN return GetCurrentThreadId(); #else // If none of the techniques above worked, we use pthread_self(). @@ -297,8 +305,24 @@ static void MyUserNameInitializer() { if (user != NULL) { g_my_user_name = user; } else { - g_my_user_name = "invalid-user"; +#if defined(HAVE_PWD_H) && defined(HAVE_UNISTD_H) + struct passwd pwd; + struct passwd* result = NULL; + char buffer[1024] = {'\0'}; + uid_t uid = geteuid(); + int pwuid_res = getpwuid_r(uid, &pwd, buffer, sizeof(buffer), &result); + if (pwuid_res == 0) { + g_my_user_name = pwd.pw_name; + } else { + snprintf(buffer, sizeof(buffer), "uid%d", uid); + g_my_user_name = buffer; + } +#endif + if (g_my_user_name.empty()) { + g_my_user_name = "invalid-user"; + } } + } REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer()); @@ -349,4 +373,12 @@ _END_GOOGLE_NAMESPACE_ // Make an implementation of stacktrace compiled. #ifdef STACKTRACE_H # include STACKTRACE_H +# if 0 +// For include scanners which can't handle macro expansions. +# include "stacktrace_libunwind-inl.h" +# include "stacktrace_x86-inl.h" +# include "stacktrace_x86_64-inl.h" +# include "stacktrace_powerpc-inl.h" +# include "stacktrace_generic-inl.h" +# endif #endif diff --git a/extern/glog/src/utilities.h b/extern/glog/src/utilities.h index 5f79968ef55..ca21cfb3884 100644 --- a/extern/glog/src/utilities.h +++ b/extern/glog/src/utilities.h @@ -39,7 +39,9 @@ #elif defined(__CYGWIN__) || defined(__CYGWIN32__) # define OS_CYGWIN #elif defined(linux) || defined(__linux) || defined(__linux__) -# define OS_LINUX +# ifndef OS_LINUX +# define OS_LINUX +# endif #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) # define OS_MACOSX #elif defined(__FreeBSD__) @@ -97,6 +99,8 @@ // malloc() from the unwinder. This is a problem because we're // trying to use the unwinder to instrument malloc(). // +// 4) The Windows API CaptureStackTrace. +// // Note: if you add a new implementation here, make sure it works // correctly when GetStackTrace() is called with max_depth == 0. // Some code may do that. @@ -110,6 +114,8 @@ # define STACKTRACE_H "stacktrace_x86_64-inl.h" # elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2 # define STACKTRACE_H "stacktrace_powerpc-inl.h" +# elif defined(OS_WINDOWS) +# define STACKTRACE_H "stacktrace_windows-inl.h" # endif #endif @@ -121,13 +127,18 @@ # define HAVE_STACKTRACE #endif +#ifndef HAVE_SYMBOLIZE // defined by gcc #if defined(__ELF__) && defined(OS_LINUX) # define HAVE_SYMBOLIZE #elif defined(OS_MACOSX) && defined(HAVE_DLADDR) // Use dladdr to symbolize. # define HAVE_SYMBOLIZE +#elif defined(OS_WINDOWS) +// Use DbgHelp to symbolize +# define HAVE_SYMBOLIZE #endif +#endif // !defined(HAVE_SYMBOLIZE) #ifndef ARRAYSIZE // There is a better way, but this is good enough for our purpose. @@ -141,6 +152,9 @@ namespace glog_internal_namespace_ { #ifdef HAVE___ATTRIBUTE__ # define ATTRIBUTE_NOINLINE __attribute__ ((noinline)) # define HAVE_ATTRIBUTE_NOINLINE +#elif defined(OS_WINDOWS) +# define ATTRIBUTE_NOINLINE __declspec(noinline) +# define HAVE_ATTRIBUTE_NOINLINE #else # define ATTRIBUTE_NOINLINE #endif diff --git a/extern/glog/src/vlog_is_on.cc b/extern/glog/src/vlog_is_on.cc index 4c95583b683..e8fdbae7dcb 100644 --- a/extern/glog/src/vlog_is_on.cc +++ b/extern/glog/src/vlog_is_on.cc @@ -62,6 +62,12 @@ _START_GOOGLE_NAMESPACE_ namespace glog_internal_namespace_ { +// Used by logging_unittests.cc so can't make it static here. +GOOGLE_GLOG_DLL_DECL bool SafeFNMatch_(const char* pattern, + size_t patt_len, + const char* str, + size_t str_len); + // Implementation of fnmatch that does not need 0-termination // of arguments and does not allocate any memory, // but we only support "*" and "?" wildcards, not the "[...]" patterns. diff --git a/extern/glog/src/windows/glog/logging.h b/extern/glog/src/windows/glog/logging.h index f521a2b9424..3681fa3fcc4 100644 --- a/extern/glog/src/windows/glog/logging.h +++ b/extern/glog/src/windows/glog/logging.h @@ -572,8 +572,10 @@ class LogSink; // defined below LOG_TO_STRING_##severity(static_cast*>(outvec)).stream() #define LOG_IF(severity, condition) \ + static_cast(0), \ !(condition) ? (void) 0 : google::LogMessageVoidify() & LOG(severity) #define SYSLOG_IF(severity, condition) \ + static_cast(0), \ !(condition) ? (void) 0 : google::LogMessageVoidify() & SYSLOG(severity) #define LOG_ASSERT(condition) \ @@ -863,6 +865,7 @@ DECLARE_CHECK_STROP_IMPL(strcasecmp, false) &google::LogMessage::SendToLog) #define PLOG_IF(severity, condition) \ + static_cast(0), \ !(condition) ? (void) 0 : google::LogMessageVoidify() & PLOG(severity) // A CHECK() macro that postpends errno if the condition is false. E.g. @@ -935,16 +938,11 @@ struct CompileAssert { struct CrashReason; // Returns true if FailureSignalHandler is installed. -bool IsFailureSignalHandlerInstalled(); +// Needs to be exported since it's used by the signalhandler_unittest. +GOOGLE_GLOG_DLL_DECL bool IsFailureSignalHandlerInstalled(); } // namespace glog_internal_namespace_ -#define GOOGLE_GLOG_COMPILE_ASSERT(expr, msg) \ - typedef google::glog_internal_namespace_::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] - #define LOG_EVERY_N(severity, n) \ - GOOGLE_GLOG_COMPILE_ASSERT(google::GLOG_ ## severity < \ - google::NUM_SEVERITIES, \ - INVALID_REQUESTED_LOG_SEVERITY); \ SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog) #define SYSLOG_EVERY_N(severity, n) \ @@ -1012,23 +1010,29 @@ const LogSeverity GLOG_0 = GLOG_ERROR; #else // !DCHECK_IS_ON() -#define DLOG(severity) \ +#define DLOG(severity) \ + static_cast(0), \ true ? (void) 0 : google::LogMessageVoidify() & LOG(severity) -#define DVLOG(verboselevel) \ - (true || !VLOG_IS_ON(verboselevel)) ?\ +#define DVLOG(verboselevel) \ + static_cast(0), \ + (true || !VLOG_IS_ON(verboselevel)) ? \ (void) 0 : google::LogMessageVoidify() & LOG(INFO) #define DLOG_IF(severity, condition) \ + static_cast(0), \ (true || !(condition)) ? (void) 0 : google::LogMessageVoidify() & LOG(severity) #define DLOG_EVERY_N(severity, n) \ + static_cast(0), \ true ? (void) 0 : google::LogMessageVoidify() & LOG(severity) #define DLOG_IF_EVERY_N(severity, condition, n) \ + static_cast(0), \ (true || !(condition))? (void) 0 : google::LogMessageVoidify() & LOG(severity) #define DLOG_ASSERT(condition) \ + static_cast(0), \ true ? (void) 0 : LOG_ASSERT(condition) // MSVC warning C4127: conditional expression is constant @@ -1113,10 +1117,11 @@ namespace base_logging { // buffer to allow for a '\n' and '\0'. class GOOGLE_GLOG_DLL_DECL LogStreamBuf : public std::streambuf { public: - // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\n'. + // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\0'. LogStreamBuf(char *buf, int len) { setp(buf, buf + len - 2); } + // This effectively ignores overflow. virtual int_type overflow(int_type ch) { return ch; @@ -1155,13 +1160,9 @@ public: // 2005 if you are deriving from a type in the Standard C++ Library" // http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx // Let's just ignore the warning. -#ifdef _MSC_VER -# pragma warning(disable: 4275) -#endif +GLOG_MSVC_PUSH_DISABLE_WARNING(4275) class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostream { -#ifdef _MSC_VER -# pragma warning(default: 4275) -#endif +GLOG_MSVC_POP_WARNING() public: LogStream(char *buf, int len, int ctr) : std::ostream(NULL), diff --git a/extern/glog/src/windows/glog/raw_logging.h b/extern/glog/src/windows/glog/raw_logging.h index 4757a719db7..e0e6d6f1a25 100644 --- a/extern/glog/src/windows/glog/raw_logging.h +++ b/extern/glog/src/windows/glog/raw_logging.h @@ -179,11 +179,6 @@ GOOGLE_GLOG_DLL_DECL void RawLog__(LogSeverity severity, const char* format, ...) ; -// Hack to propagate time information into this module so that -// this module does not have to directly call localtime_r(), -// which could allocate memory. -GOOGLE_GLOG_DLL_DECL void RawLog__SetLastTime(const struct tm& t, int usecs); - } #endif // BASE_RAW_LOGGING_H_ diff --git a/extern/glog/src/windows/port.cc b/extern/glog/src/windows/port.cc index d9943254ee5..19bda367c62 100644 --- a/extern/glog/src/windows/port.cc +++ b/extern/glog/src/windows/port.cc @@ -38,15 +38,8 @@ #include "config.h" #include // for va_list, va_start, va_end -#include // for strstr() -#include -#include -#include #include "port.h" -using std::string; -using std::vector; - // These call the windows _vsnprintf, but always NUL-terminate. int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) { if (size == 0) // not even room for a \0? @@ -55,6 +48,12 @@ int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) { return _vsnprintf(str, size-1, format, ap); } +#ifndef HAVE_LOCALTIME_R +struct tm* localtime_r(const time_t* timep, struct tm* result) { + localtime_s(result, timep); + return result; +} +#endif // not HAVE_LOCALTIME_R #ifndef HAVE_SNPRINTF int snprintf(char *str, size_t size, const char *format, ...) { va_list ap; diff --git a/extern/glog/src/windows/port.h b/extern/glog/src/windows/port.h index 819846151b9..7b4b9c8545b 100644 --- a/extern/glog/src/windows/port.h +++ b/extern/glog/src/windows/port.h @@ -70,8 +70,11 @@ * 4715: for some reason VC++ stopped realizing you can't return after abort() * 4800: we know we're casting ints/char*'s to bools, and we're ok with that * 4996: Yes, we're ok using "unsafe" functions like fopen() and strerror() + * 4312: Converting uint32_t to a pointer when testing %p + * 4267: also subtracting two size_t to int + * 4722: Destructor never returns due to abort() */ -#pragma warning(disable:4244 4251 4355 4715 4800 4996) +#pragma warning(disable:4244 4251 4355 4715 4800 4996 4267 4312 4722) /* file I/O */ #define PATH_MAX 1024 @@ -86,6 +89,11 @@ #define pclose _pclose #define R_OK 04 /* read-only (for access()) */ #define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR) + +#define O_WRONLY _O_WRONLY +#define O_CREAT _O_CREAT +#define O_EXCL _O_EXCL + #ifndef __MINGW32__ enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 }; #endif @@ -136,19 +144,20 @@ typedef int pid_t; #endif // _MSC_VER // ----------------------------------- THREADS -#ifndef __MINGW32__ +#if defined(HAVE_PTHREAD) +# include +#else // no PTHREAD typedef DWORD pthread_t; typedef DWORD pthread_key_t; typedef LONG pthread_once_t; enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock #define pthread_self GetCurrentThreadId #define pthread_equal(pthread_t_1, pthread_t_2) ((pthread_t_1)==(pthread_t_2)) +#endif // HAVE_PTHREAD -inline struct tm* localtime_r(const time_t* timep, struct tm* result) { - localtime_s(result, timep); - return result; -} -#endif +#ifndef HAVE_LOCALTIME_R +extern GOOGLE_GLOG_DLL_DECL struct tm* localtime_r(const time_t* timep, struct tm* result); +#endif // not HAVE_LOCALTIME_R inline char* strerror_r(int errnum, char* buf, size_t buflen) { strerror_s(buf, buflen, errnum); diff --git a/extern/glog/src/windows/preprocess.sh b/extern/glog/src/windows/preprocess.sh index 5398988e7ea..c35e92913b6 100755 --- a/extern/glog/src/windows/preprocess.sh +++ b/extern/glog/src/windows/preprocess.sh @@ -95,7 +95,7 @@ DLLDEF_DEFINES="\ -e "s!@ac_cv_have_libgflags@!0!g" \ -e "s!@ac_cv_have___builtin_expect@!0!g" \ -e "s!@ac_cv_cxx_using_operator@!1!g" \ - -e "s!@ac_cv___attribute___noreturn@!!g" \ + -e "s!@ac_cv___attribute___noreturn@!__declspec(noreturn)!g" \ -e "s!@ac_cv___attribute___noinline@!!g" \ -e "s!@ac_cv___attribute___printf_4_5@!!g" \ -e "s!@ac_google_attribute@!${HAVE___ATTRIBUTE__:-0}!g" \ -- cgit v1.2.3