summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortschmelcher@chromium.org <tschmelcher@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-09 23:52:20 +0000
committertschmelcher@chromium.org <tschmelcher@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-09 23:52:20 +0000
commitd8617a6ad0d531e8ad63298f7cd4a091b78aa43e (patch)
treee60489d36fcbdf6f580e7c4cd715f2a085d5b56b
parenta36804546751df937333345b7a27b4ef8d60b67d (diff)
downloadchromium_src-d8617a6ad0d531e8ad63298f7cd4a091b78aa43e.zip
chromium_src-d8617a6ad0d531e8ad63298f7cd4a091b78aa43e.tar.gz
chromium_src-d8617a6ad0d531e8ad63298f7cd4a091b78aa43e.tar.bz2
Add logging macros that automatically append the last system error in string form.
Also add thread-safe, portable variants for strerror() and strerror_r() on POSIX so that existing error logging code that calls strerror() for something other than LOG, LOG_IF, or CHECK can be changed to use safe versions too. After this CL I will eliminate all unsafe uses of strerror() in our code. TEST=Linux: tested PLOG and DPLOG with both a valid error and invalid error on a dbg build with both the default strerror_r implementation (GNU) and the other one (POSIX) via some throw-away macro evilness, and also tested the default strerror_r again on an opt build to verify DPLOG is a no-op; Windows: tested PLOG and DPLOG with both a valid error and invalid error on a dbg build; also tested LOG_GETLASTERROR_MODULE with winhttp and ERROR_WINHTTP_CANNOT_CONNECT and verified that it prints the correct system message and that it doesn't with PLOG; also tested LOG_GETLASTERROR_MODULE with a bogus module name and verified that it prints an error that it can't find the module, and the original error; Mac: none (implicitly tested via the Linux POSIX tests); trybots for Win, Mac, and Linux 32-bit; built locally for Linux 32-bit and 64-bit and tested base_unittests and also running Chromium itself; wrote the upcoming CL that switches strerror() calls to use PLOG and verified that it builds and works for both Linux 32-bit and Linux 64-bit; lint BUG=none Review URL: http://codereview.chromium.org/265052 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28632 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/base.gyp2
-rw-r--r--base/logging.cc92
-rw-r--r--base/logging.h178
-rw-r--r--base/safe_strerror_posix.cc107
-rw-r--r--base/safe_strerror_posix.h36
5 files changed, 407 insertions, 8 deletions
diff --git a/base/base.gyp b/base/base.gyp
index 09dca2b..61f5e3c 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -250,6 +250,8 @@
'registry.h',
'resource_util.cc',
'resource_util.h',
+ 'safe_strerror_posix.cc',
+ 'safe_strerror_posix.h',
'scoped_bstr_win.cc',
'scoped_bstr_win.h',
'scoped_cftyperef.h',
diff --git a/base/logging.cc b/base/logging.cc
index 7981310..b59e3fb 100644
--- a/base/logging.cc
+++ b/base/logging.cc
@@ -19,6 +19,7 @@ typedef HANDLE MutexHandle;
#endif
#if defined(OS_POSIX)
+#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -37,6 +38,9 @@ typedef pthread_mutex_t* MutexHandle;
#include "base/command_line.h"
#include "base/debug_util.h"
#include "base/lock_impl.h"
+#if defined(OS_POSIX)
+#include "base/safe_strerror_posix.h"
+#endif
#include "base/string_piece.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -567,6 +571,94 @@ LogMessage::~LogMessage() {
}
}
+#if defined(OS_WIN)
+// This has already been defined in the header, but defining it again as DWORD
+// ensures that the type used in the header is equivalent to DWORD. If not,
+// the redefinition is a compile error.
+typedef DWORD SystemErrorCode;
+#endif
+
+SystemErrorCode GetLastSystemErrorCode() {
+#if defined(OS_WIN)
+ return ::GetLastError();
+#elif defined(OS_POSIX)
+ return errno;
+#else
+#error Not implemented
+#endif
+}
+
+#if defined(OS_WIN)
+Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err,
+ const char* module)
+ : err_(err),
+ module_(module),
+ log_message_(file, line, severity) {
+}
+
+Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err)
+ : err_(err),
+ module_(NULL),
+ log_message_(file, line, severity) {
+}
+
+Win32ErrorLogMessage::~Win32ErrorLogMessage() {
+ const int error_message_buffer_size = 256;
+ char msgbuf[error_message_buffer_size];
+ DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM;
+ HMODULE hmod;
+ if (module_) {
+ hmod = GetModuleHandleA(module_);
+ if (hmod) {
+ flags |= FORMAT_MESSAGE_FROM_HMODULE;
+ } else {
+ // This makes a nested Win32ErrorLogMessage. It will have module_ of NULL
+ // so it will not call GetModuleHandle, so recursive errors are
+ // impossible.
+ DPLOG(WARNING) << "Couldn't open module " << module_
+ << " for error message query";
+ }
+ } else {
+ hmod = NULL;
+ }
+ DWORD len = FormatMessageA(flags,
+ hmod,
+ err_,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ msgbuf,
+ sizeof(msgbuf) / sizeof(msgbuf[0]),
+ NULL);
+ if (len) {
+ while ((len > 0) &&
+ isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
+ msgbuf[--len] = 0;
+ }
+ stream() << ": " << msgbuf;
+ } else {
+ stream() << ": Error " << GetLastError() << " while retrieving error "
+ << err_;
+ }
+}
+#elif defined(OS_POSIX)
+ErrnoLogMessage::ErrnoLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err)
+ : err_(err),
+ log_message_(file, line, severity) {
+}
+
+ErrnoLogMessage::~ErrnoLogMessage() {
+ stream() << ": " << safe_strerror(err_);
+}
+#endif // OS_WIN
+
void CloseLogFile() {
if (!log_file)
return;
diff --git a/base/logging.h b/base/logging.h
index a1d439c..de8de71 100644
--- a/base/logging.h
+++ b/base/logging.h
@@ -75,6 +75,18 @@
//
// We also override the standard 'assert' to use 'DLOG_ASSERT'.
//
+// Lastly, there is:
+//
+// PLOG(ERROR) << "Couldn't do foo";
+// DPLOG(ERROR) << "Couldn't do foo";
+// PLOG_IF(ERROR, cond) << "Couldn't do foo";
+// DPLOG_IF(ERROR, cond) << "Couldn't do foo";
+// PCHECK(condition) << "Couldn't do foo";
+// DPCHECK(condition) << "Couldn't do foo";
+//
+// which append the last system error to the message in string form (taken from
+// GetLastError() on Windows and errno on POSIX).
+//
// The supported severity levels for macros that allow you to specify one
// are (in increasing order of severity) INFO, WARNING, ERROR, ERROR_REPORT,
// and FATAL.
@@ -192,18 +204,33 @@ const LogSeverity LOG_DFATAL_LEVEL = LOG_FATAL;
// A few definitions of macros that don't generate much code. These are used
// by LOG() and LOG_IF, etc. Since these are used all over our code, it's
// better to have compact code for these operations.
+#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \
+ logging::ClassName(__FILE__, __LINE__, logging::LOG_INFO , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \
+ logging::ClassName(__FILE__, __LINE__, logging::LOG_WARNING , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \
+ logging::ClassName(__FILE__, __LINE__, logging::LOG_ERROR , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(ClassName, ...) \
+ logging::ClassName(__FILE__, __LINE__, \
+ logging::LOG_ERROR_REPORT , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \
+ logging::ClassName(__FILE__, __LINE__, logging::LOG_FATAL , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \
+ logging::ClassName(__FILE__, __LINE__, \
+ logging::LOG_DFATAL_LEVEL , ##__VA_ARGS__)
+
#define COMPACT_GOOGLE_LOG_INFO \
- logging::LogMessage(__FILE__, __LINE__)
+ COMPACT_GOOGLE_LOG_EX_INFO(LogMessage)
#define COMPACT_GOOGLE_LOG_WARNING \
- logging::LogMessage(__FILE__, __LINE__, logging::LOG_WARNING)
+ COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage)
#define COMPACT_GOOGLE_LOG_ERROR \
- logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR)
+ COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage)
#define COMPACT_GOOGLE_LOG_ERROR_REPORT \
- logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR_REPORT)
+ COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(LogMessage)
#define COMPACT_GOOGLE_LOG_FATAL \
- logging::LogMessage(__FILE__, __LINE__, logging::LOG_FATAL)
+ COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage)
#define COMPACT_GOOGLE_LOG_DFATAL \
- logging::LogMessage(__FILE__, __LINE__, logging::LOG_DFATAL_LEVEL)
+ COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage)
// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets
// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
@@ -211,8 +238,9 @@ const LogSeverity LOG_DFATAL_LEVEL = LOG_FATAL;
// as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that
// the Windows SDK does for consistency.
#define ERROR 0
-#define COMPACT_GOOGLE_LOG_0 \
- logging::LogMessage(__FILE__, __LINE__, logging::LOG_ERROR)
+#define COMPACT_GOOGLE_LOG_EX_0(ClassName, ...) \
+ COMPACT_GOOGLE_LOG_EX_ERROR(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR
// We use the preprocessor's merging operator, "##", so that, e.g.,
// LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO. There's some funny
@@ -235,12 +263,38 @@ const LogSeverity LOG_DFATAL_LEVEL = LOG_FATAL;
#define SYSLOG_ASSERT(condition) \
SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
+#if defined(OS_WIN)
+#define LOG_GETLASTERROR(severity) \
+ COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \
+ ::logging::GetLastSystemErrorCode()).stream()
+#define LOG_GETLASTERROR_MODULE(severity, module) \
+ COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \
+ ::logging::GetLastSystemErrorCode(), module).stream()
+// PLOG is the usual error logging macro for each platform.
+#define PLOG(severity) LOG_GETLASTERROR(severity)
+#define DPLOG(severity) DLOG_GETLASTERROR(severity)
+#elif defined(OS_POSIX)
+#define LOG_ERRNO(severity) \
+ COMPACT_GOOGLE_LOG_EX_ ## severity(ErrnoLogMessage, \
+ ::logging::GetLastSystemErrorCode()).stream()
+// PLOG is the usual error logging macro for each platform.
+#define PLOG(severity) LOG_ERRNO(severity)
+#define DPLOG(severity) DLOG_ERRNO(severity)
+// TODO(tschmelcher): Should we add OSStatus logging for Mac?
+#endif
+
+#define PLOG_IF(severity, condition) \
+ !(condition) ? (void) 0 : logging::LogMessageVoidify() & PLOG(severity)
+
// CHECK dies with a fatal error if condition is not true. It is *not*
// controlled by NDEBUG, so the check will be executed regardless of
// compilation mode.
#define CHECK(condition) \
LOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". "
+#define PCHECK(condition) \
+ PLOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". "
+
// A container for a string pointer which can be evaluated to a bool -
// true iff the pointer is NULL.
struct CheckOpString {
@@ -301,6 +355,20 @@ std::string* MakeCheckOpString(const int& v1,
#define DLOG_ASSERT(condition) \
true ? (void) 0 : LOG_ASSERT(condition)
+#if defined(OS_WIN)
+#define DLOG_GETLASTERROR(severity) \
+ true ? (void) 0 : logging::LogMessageVoidify() & LOG_GETLASTERROR(severity)
+#define DLOG_GETLASTERROR_MODULE(severity, module) \
+ true ? (void) 0 : logging::LogMessageVoidify() & \
+ LOG_GETLASTERROR_MODULE(severity, module)
+#elif defined(OS_POSIX)
+#define DLOG_ERRNO(severity) \
+ true ? (void) 0 : logging::LogMessageVoidify() & LOG_ERRNO(severity)
+#endif
+
+#define DPLOG_IF(severity, condition) \
+ true ? (void) 0 : logging::LogMessageVoidify() & PLOG(severity)
+
enum { DEBUG_MODE = 0 };
// This macro can be followed by a sequence of stream parameters in
@@ -315,6 +383,9 @@ enum { DEBUG_MODE = 0 };
#define DCHECK(condition) \
while (false && (condition)) NDEBUG_EAT_STREAM_PARAMETERS
+#define DPCHECK(condition) \
+ while (false && (condition)) NDEBUG_EAT_STREAM_PARAMETERS
+
#define DCHECK_EQ(val1, val2) \
while (false && (val1) == (val2)) NDEBUG_EAT_STREAM_PARAMETERS
@@ -354,11 +425,24 @@ enum { DEBUG_MODE = 0 };
#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
+#if defined(OS_WIN)
+#define DLOG_GETLASTERROR(severity) LOG_GETLASTERROR(severity)
+#define DLOG_GETLASTERROR_MODULE(severity, module) \
+ LOG_GETLASTERROR_MODULE(severity, module)
+#elif defined(OS_POSIX)
+#define DLOG_ERRNO(severity) LOG_ERRNO(severity)
+#endif
+
+#define DPLOG_IF(severity, condition) PLOG_IF(severity, condition)
+
// debug-only checking. not executed in NDEBUG mode.
enum { DEBUG_MODE = 1 };
#define DCHECK(condition) \
LOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". "
+#define DPCHECK(condition) \
+ PLOG_IF(FATAL, !(condition)) << "Check failed: " #condition ". "
+
// Helper macro for binary operators.
// Don't use this macro directly in your code, use DCHECK_EQ et al below.
#define DCHECK_OP(name, op, val1, val2) \
@@ -413,6 +497,20 @@ DECLARE_DCHECK_STROP_IMPL(_stricmp, false)
#define DLOG_ASSERT(condition) \
true ? (void) 0 : LOG_ASSERT(condition)
+#if defined(OS_WIN)
+#define DLOG_GETLASTERROR(severity) \
+ true ? (void) 0 : logging::LogMessageVoidify() & LOG_GETLASTERROR(severity)
+#define DLOG_GETLASTERROR_MODULE(severity, module) \
+ true ? (void) 0 : logging::LogMessageVoidify() & \
+ LOG_GETLASTERROR_MODULE(severity, module)
+#elif defined(OS_POSIX)
+#define DLOG_ERRNO(severity) \
+ true ? (void) 0 : logging::LogMessageVoidify() & LOG_ERRNO(severity)
+#endif
+
+#define DPLOG_IF(severity, condition) \
+ true ? (void) 0 : logging::LogMessageVoidify() & PLOG(severity)
+
enum { DEBUG_MODE = 0 };
// This macro can be followed by a sequence of stream parameters in
@@ -428,6 +526,10 @@ extern bool g_enable_dcheck;
!logging::g_enable_dcheck ? void (0) : \
LOG_IF(ERROR_REPORT, !(condition)) << "Check failed: " #condition ". "
+#define DPCHECK(condition) \
+ !logging::g_enable_dcheck ? void (0) : \
+ PLOG_IF(ERROR_REPORT, !(condition)) << "Check failed: " #condition ". "
+
// Helper macro for binary operators.
// Don't use this macro directly in your code, use DCHECK_EQ et al below.
#define DCHECK_OP(name, op, val1, val2) \
@@ -597,6 +699,66 @@ class LogMessageVoidify {
void operator&(std::ostream&) { }
};
+#if defined(OS_WIN)
+typedef unsigned long SystemErrorCode;
+#elif defined(OS_POSIX)
+typedef int SystemErrorCode;
+#endif
+
+// Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to
+// pull in windows.h just for GetLastError() and DWORD.
+SystemErrorCode GetLastSystemErrorCode();
+
+#if defined(OS_WIN)
+// Appends a formatted system message of the GetLastError() type.
+class Win32ErrorLogMessage {
+ public:
+ Win32ErrorLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err,
+ const char* module);
+
+ Win32ErrorLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err);
+
+ std::ostream& stream() { return log_message_.stream(); }
+
+ // Appends the error message before destructing the encapsulated class.
+ ~Win32ErrorLogMessage();
+
+ private:
+ SystemErrorCode err_;
+ // Optional name of the module defining the error.
+ const char* module_;
+ LogMessage log_message_;
+
+ DISALLOW_COPY_AND_ASSIGN(Win32ErrorLogMessage);
+};
+#elif defined(OS_POSIX)
+// Appends a formatted system message of the errno type
+class ErrnoLogMessage {
+ public:
+ ErrnoLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err);
+
+ std::ostream& stream() { return log_message_.stream(); }
+
+ // Appends the error message before destructing the encapsulated class.
+ ~ErrnoLogMessage();
+
+ private:
+ SystemErrorCode err_;
+ LogMessage log_message_;
+
+ DISALLOW_COPY_AND_ASSIGN(ErrnoLogMessage);
+};
+#endif // OS_WIN
+
// Closes the log file explicitly if open.
// NOTE: Since the log file is opened as necessary by the action of logging
// statements, there's no guarantee that it will stay closed
diff --git a/base/safe_strerror_posix.cc b/base/safe_strerror_posix.cc
new file mode 100644
index 0000000..008b785
--- /dev/null
+++ b/base/safe_strerror_posix.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/safe_strerror_posix.h"
+
+#include <errno.h>
+#include <string.h>
+
+#if defined(__GLIBC__) && defined(__GNUC__)
+// GCC will complain about the unused second wrap function unless we tell it
+// that we meant for them to be potentially unused, which is exactly what this
+// attribute is for.
+#define POSSIBLY_UNUSED __attribute__((unused))
+#else
+#define POSSIBLY_UNUSED
+#endif
+
+#if defined(__GLIBC__)
+// glibc has two strerror_r functions: a historical GNU-specific one that
+// returns type char *, and a POSIX.1-2001 compliant one available since 2.3.4
+// that returns int. This wraps the GNU-specific one.
+static void POSSIBLY_UNUSED wrap_posix_strerror_r(
+ char *(*strerror_r_ptr)(int, char *, size_t),
+ int err,
+ char *buf,
+ size_t len) {
+ // GNU version.
+ char *rc = (*strerror_r_ptr)(err, buf, len);
+ if (rc != buf) {
+ // glibc did not use buf and returned a static string instead. Copy it
+ // into buf.
+ buf[0] = '\0';
+ strncat(buf, rc, len - 1);
+ }
+ // The GNU version never fails. Unknown errors get an "unknown error" message.
+ // The result is always null terminated.
+}
+#endif // __GLIBC__
+
+// Wrapper for strerror_r functions that implement the POSIX interface. POSIX
+// does not define the behaviour for some of the edge cases, so we wrap it to
+// guarantee that they are handled. This is compiled on all POSIX platforms, but
+// it will only be used on Linux if the POSIX strerror_r implementation is
+// being used (see below).
+static void POSSIBLY_UNUSED wrap_posix_strerror_r(
+ int (*strerror_r_ptr)(int, char *, size_t),
+ int err,
+ char *buf,
+ size_t len) {
+ int old_errno = errno;
+ // Have to cast since otherwise we get an error if this is the GNU version
+ // (but in such a scenario this function is never called). Sadly we can't use
+ // C++-style casts because the appropriate one is reinterpret_cast but it's
+ // considered illegal to reinterpret_cast a type to itself, so we get an
+ // error in the opposite case.
+ int result = (*strerror_r_ptr)(err, buf, len);
+ if (result == 0) {
+ // POSIX is vague about whether the string will be terminated, although
+ // it indirectly implies that typically ERANGE will be returned, instead
+ // of truncating the string. We play it safe by always terminating the
+ // string explicitly.
+ buf[len - 1] = '\0';
+ } else {
+ // Error. POSIX is vague about whether the return value is itself a system
+ // error code or something else. On Linux currently it is -1 and errno is
+ // set. On BSD-derived systems it is a system error and errno is unchanged.
+ // We try and detect which case it is so as to put as much useful info as
+ // we can into our message.
+ int strerror_error; // The error encountered in strerror
+ int new_errno = errno;
+ if (new_errno != old_errno) {
+ // errno was changed, so probably the return value is just -1 or something
+ // else that doesn't provide any info, and errno is the error.
+ strerror_error = new_errno;
+ } else {
+ // Either the error from strerror_r was the same as the previous value, or
+ // errno wasn't used. Assume the latter.
+ strerror_error = result;
+ }
+ // snprintf truncates and always null-terminates.
+ snprintf(buf,
+ len,
+ "Error %d while retrieving error %d",
+ strerror_error,
+ err);
+ }
+ errno = old_errno;
+}
+
+void safe_strerror_r(int err, char *buf, size_t len) {
+ if (buf == NULL || len <= 0) {
+ return;
+ }
+ // If using glibc (i.e., Linux), the compiler will automatically select the
+ // appropriate overloaded function based on the function type of strerror_r.
+ // The other one will be elided from the translation unit since both are
+ // static.
+ wrap_posix_strerror_r(&strerror_r, err, buf, len);
+}
+
+std::string safe_strerror(int err) {
+ const int buffer_size = 256;
+ char buf[buffer_size];
+ safe_strerror_r(err, buf, sizeof(buf));
+ return std::string(buf);
+}
diff --git a/base/safe_strerror_posix.h b/base/safe_strerror_posix.h
new file mode 100644
index 0000000..ecf3a78
--- /dev/null
+++ b/base/safe_strerror_posix.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SAFE_STRERROR_POSIX_H_
+#define BASE_SAFE_STRERROR_POSIX_H_
+
+#include <string>
+
+// BEFORE using anything from this file, first look at PLOG and friends in
+// logging.h and use them instead if applicable.
+//
+// This file declares safe, portable alternatives to the POSIX strerror()
+// function. strerror() is inherently unsafe in multi-threaded apps and should
+// never be used. Doing so can cause crashes. Additionally, the thread-safe
+// alternative strerror_r varies in semantics across platforms. Use these
+// functions instead.
+
+// Thread-safe strerror function with dependable semantics that never fails.
+// It will write the string form of error "err" to buffer buf of length len.
+// If there is an error calling the OS's strerror_r() function then a message to
+// that effect will be printed into buf, truncating if necessary. The final
+// result is always null-terminated. The value of errno is never changed.
+//
+// Use this instead of strerror_r().
+void safe_strerror_r(int err, char *buf, size_t len);
+
+// Calls safe_strerror_r with a buffer of suitable size and returns the result
+// in a C++ string.
+//
+// Use this instead of strerror(). Note though that safe_strerror_r will be
+// more robust in the case of heap corruption errors, since it doesn't need to
+// allocate a string.
+std::string safe_strerror(int err);
+
+#endif // BASE_SAFE_STRERROR_POSIX_H_