fix: reduce manual resource management (#1046)

This commit is contained in:
Sergiu Deitsch 2024-01-07 21:12:40 +01:00 committed by GitHub
parent 1f9ac49c7d
commit 42a185cd88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 237 additions and 187 deletions

View File

@ -965,12 +965,13 @@ namespace google {
LOG_OCCURRENCES, &what_to_do) \
.stream()
namespace glog_internal_namespace_ {
namespace logging {
namespace internal {
template <bool>
struct CompileAssert {};
struct CrashReason;
} // namespace glog_internal_namespace_
} // namespace internal
} // namespace logging
#define LOG_EVERY_N(severity, n) \
SOME_KIND_OF_LOG_EVERY_N(severity, (n), google::LogMessage::SendToLog)
@ -1334,7 +1335,7 @@ class GLOG_EXPORT LogMessage {
void (LogMessage::*send_method)());
// Used to fill in crash information during LOG(FATAL) failures.
void RecordCrashReason(glog_internal_namespace_::CrashReason* reason);
void RecordCrashReason(logging::internal::CrashReason* reason);
// Counts of messages sent at each priority:
static int64 num_messages_[NUM_SEVERITIES]; // under log_mutex

View File

@ -1,4 +1,4 @@
// Copyright (c) 2009, Google Inc.
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -73,7 +73,7 @@ extern void (*g_logging_fail_func)();
extern void GetExistingTempDirectories(std::vector<std::string>& list);
extern int posix_strerror_r(int err, char* buf, size_t len);
extern std::string StrError(int err);
}
} // namespace google
#undef GLOG_EXPORT
#define GLOG_EXPORT
@ -300,60 +300,53 @@ static inline void RunSpecifiedBenchmarks() {
class CapturedStream {
public:
CapturedStream(int fd, string filename)
: fd_(fd),
filename_(std::move(filename)) {
: fd_(fd), filename_(std::move(filename)) {
Capture();
}
~CapturedStream() {
if (uncaptured_fd_ != -1) {
CHECK(close(uncaptured_fd_) != -1);
}
}
// Start redirecting output to a file
void Capture() {
// Keep original stream for later
CHECK(uncaptured_fd_ == -1) << ", Stream " << fd_ << " already captured!";
uncaptured_fd_ = dup(fd_);
CHECK(uncaptured_fd_ != -1);
CHECK(!uncaptured_fd_) << ", Stream " << fd_ << " already captured!";
uncaptured_fd_.reset(dup(fd_));
CHECK(uncaptured_fd_);
// Open file to save stream to
int cap_fd = open(filename_.c_str(), O_CREAT | O_TRUNC | O_WRONLY,
S_IRUSR | S_IWUSR);
CHECK(cap_fd != -1);
FileDescriptor cap_fd{open(filename_.c_str(), O_CREAT | O_TRUNC | O_WRONLY,
S_IRUSR | S_IWUSR)};
CHECK(cap_fd);
// Send stdout/stderr to this file
fflush(nullptr);
CHECK(dup2(cap_fd, fd_) != -1);
CHECK(close(cap_fd) != -1);
CHECK(dup2(cap_fd.get(), fd_) != -1);
CHECK(cap_fd.close() != -1);
}
// Remove output redirection
void StopCapture() {
// Restore original stream
if (uncaptured_fd_ != -1) {
if (uncaptured_fd_) {
fflush(nullptr);
CHECK(dup2(uncaptured_fd_, fd_) != -1);
CHECK(dup2(uncaptured_fd_.get(), fd_) != -1);
}
}
const string& filename() const { return filename_; }
private:
int fd_; // file descriptor being captured
int uncaptured_fd_{-1}; // where the stream was originally being sent to
string filename_; // file where stream is being saved
int fd_; // file descriptor being captured
FileDescriptor
uncaptured_fd_; // where the stream was originally being sent to
string filename_; // file where stream is being saved
};
static CapturedStream* s_captured_streams[STDERR_FILENO + 1];
static std::unique_ptr<CapturedStream> s_captured_streams[STDERR_FILENO + 1];
// Redirect a file descriptor to a file.
// fd - Should be STDOUT_FILENO or STDERR_FILENO
// filename - File where output should be stored
static inline void CaptureTestOutput(int fd, const string& filename) {
CHECK((fd == STDOUT_FILENO) || (fd == STDERR_FILENO));
CHECK(s_captured_streams[fd] == nullptr);
s_captured_streams[fd] = new CapturedStream(fd, filename);
s_captured_streams[fd] = std::make_unique<CapturedStream>(fd, filename);
}
static inline void CaptureTestStdout() {
CaptureTestOutput(STDOUT_FILENO, FLAGS_test_tmpdir + "/captured.out");
@ -369,7 +362,7 @@ static inline size_t GetFileSize(FILE* file) {
// Read the entire content of a file as a string
static inline string ReadEntireFile(FILE* file) {
const size_t file_size = GetFileSize(file);
char* const buffer = new char[file_size];
std::vector<char> content(file_size);
size_t bytes_last_read = 0; // # of bytes read in the last fread()
size_t bytes_read = 0; // # of bytes read so far
@ -380,32 +373,26 @@ static inline string ReadEntireFile(FILE* file) {
// pre-determined file size is reached.
do {
bytes_last_read =
fread(buffer + bytes_read, 1, file_size - bytes_read, file);
fread(content.data() + bytes_read, 1, file_size - bytes_read, file);
bytes_read += bytes_last_read;
} while (bytes_last_read > 0 && bytes_read < file_size);
const string content = string(buffer, buffer + bytes_read);
delete[] buffer;
return content;
return std::string(content.data(), bytes_read);
}
// Get the captured stdout (when fd is STDOUT_FILENO) or stderr (when
// fd is STDERR_FILENO) as a string
static inline string GetCapturedTestOutput(int fd) {
CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO);
CapturedStream* const cap = s_captured_streams[fd];
std::unique_ptr<CapturedStream> cap = std::move(s_captured_streams[fd]);
CHECK(cap) << ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
// Make sure everything is flushed.
cap->StopCapture();
// Read the captured file.
FILE* const file = fopen(cap->filename().c_str(), "r");
const string content = ReadEntireFile(file);
fclose(file);
delete cap;
s_captured_streams[fd] = nullptr;
std::unique_ptr<FILE> file{fopen(cap->filename().c_str(), "r")};
const string content = ReadEntireFile(file.get());
file.reset();
return content;
}
@ -479,11 +466,11 @@ static inline void StringReplace(string* str, const string& oldsub,
}
static inline string Munge(const string& filename) {
FILE* fp = fopen(filename.c_str(), "rb");
std::unique_ptr<FILE> fp{fopen(filename.c_str(), "rb")};
CHECK(fp != nullptr) << filename << ": couldn't open";
char buf[4096];
string result;
while (fgets(buf, 4095, fp)) {
while (fgets(buf, 4095, fp.get())) {
string line = MungeLine(buf);
const size_t str_size = 256;
char null_str[str_size];
@ -502,19 +489,17 @@ static inline string Munge(const string& filename) {
StringReplace(&line, "__ENOEXEC__", StrError(ENOEXEC));
result += line + "\n";
}
fclose(fp);
return result;
}
static inline void WriteToFile(const string& body, const string& file) {
FILE* fp = fopen(file.c_str(), "wb");
fwrite(body.data(), 1, body.size(), fp);
fclose(fp);
std::unique_ptr<FILE> fp{fopen(file.c_str(), "wb")};
fwrite(body.data(), 1, body.size(), fp.get());
}
static inline bool MungeAndDiffTest(const string& golden_filename,
CapturedStream* cap) {
if (cap == s_captured_streams[STDOUT_FILENO]) {
if (cap == s_captured_streams[STDOUT_FILENO].get()) {
CHECK(cap) << ": did you forget CaptureTestStdout()?";
} else {
CHECK(cap) << ": did you forget CaptureTestStderr()?";
@ -549,11 +534,13 @@ static inline bool MungeAndDiffTest(const string& golden_filename,
}
static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
return MungeAndDiffTest(golden_filename, s_captured_streams[STDERR_FILENO]);
return MungeAndDiffTest(golden_filename,
s_captured_streams[STDERR_FILENO].get());
}
static inline bool MungeAndDiffTestStdout(const string& golden_filename) {
return MungeAndDiffTest(golden_filename, s_captured_streams[STDOUT_FILENO]);
return MungeAndDiffTest(golden_filename,
s_captured_streams[STDOUT_FILENO].get());
}
// Save flags used from logging_unittest.cc.

View File

@ -1011,11 +1011,12 @@ bool LogFileObject::CreateLogfile(const string& time_pid_string) {
// demand that the file is unique for our timestamp (fail if it exists).
flags = flags | O_EXCL;
}
int fd = open(filename, flags, static_cast<mode_t>(FLAGS_logfile_mode));
if (fd == -1) return false;
FileDescriptor fd{
open(filename, flags, static_cast<mode_t>(FLAGS_logfile_mode))};
if (!fd) return false;
#ifdef HAVE_FCNTL
// Mark the file close-on-exec. We don't really care if this fails
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd.get(), F_SETFD, FD_CLOEXEC);
// Mark the file as exclusive write access to avoid two clients logging to the
// same file. This applies particularly when !FLAGS_timestamp_in_logfile_name
@ -1034,17 +1035,15 @@ bool LogFileObject::CreateLogfile(const string& time_pid_string) {
w_lock.l_whence = SEEK_SET;
w_lock.l_len = 0;
int wlock_ret = fcntl(fd, F_SETLK, &w_lock);
int wlock_ret = fcntl(fd.get(), F_SETLK, &w_lock);
if (wlock_ret == -1) {
close(fd); // as we are failing already, do not check errors here
return false;
}
#endif
// fdopen in append mode so if the file exists it will fseek to the end
file_.reset(fdopen(fd, "a")); // Make a FILE*.
if (file_ == nullptr) { // Man, we're screwed!
close(fd);
file_.reset(fdopen(fd.release(), "a")); // Make a FILE*.
if (file_ == nullptr) { // Man, we're screwed!
if (FLAGS_timestamp_in_logfile_name) {
unlink(filename); // Erase the half-baked evidence: an unusable log file,
// only if we just created it.
@ -1506,7 +1505,7 @@ bool LogCleaner::IsLogLastModifiedOver(
// for exclusive use by the first thread, and one for shared use by
// all other threads.
static std::mutex fatal_msg_lock;
static CrashReason crash_reason;
static logging::internal::CrashReason crash_reason;
static bool fatal_msg_exclusive = true;
static LogMessage::LogMessageData fatal_msg_data_exclusive;
static LogMessage::LogMessageData fatal_msg_data_shared;
@ -1861,8 +1860,7 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
}
}
void LogMessage::RecordCrashReason(
glog_internal_namespace_::CrashReason* reason) {
void LogMessage::RecordCrashReason(logging::internal::CrashReason* reason) {
reason->filename = fatal_msg_data_exclusive.fullname_;
reason->line_number = fatal_msg_data_exclusive.line_;
reason->message = fatal_msg_data_exclusive.message_text_ +
@ -2396,8 +2394,8 @@ void TruncateLogFile(const char* path, uint64 limit, uint64 keep) {
if (strncmp(procfd_prefix, path, strlen(procfd_prefix))) flags |= O_NOFOLLOW;
# endif
int fd = open(path, flags);
if (fd == -1) {
FileDescriptor fd{open(path, flags)};
if (!fd) {
if (errno == EFBIG) {
// The log file in question has got too big for us to open. The
// real fix for this would be to compile logging.cc (or probably
@ -2405,7 +2403,7 @@ void TruncateLogFile(const char* path, uint64 limit, uint64 keep) {
// rather scary.
// Instead just truncate the file to something we can manage
# ifdef HAVE__CHSIZE_S
if (_chsize_s(fd, 0) != 0) {
if (_chsize_s(fd.get(), 0) != 0) {
# else
if (truncate(path, 0) == -1) {
# endif
@ -2419,16 +2417,16 @@ void TruncateLogFile(const char* path, uint64 limit, uint64 keep) {
return;
}
if (fstat(fd, &statbuf) == -1) {
if (fstat(fd.get(), &statbuf) == -1) {
PLOG(ERROR) << "Unable to fstat()";
goto out_close_fd;
return;
}
// See if the path refers to a regular file bigger than the
// specified limit
if (!S_ISREG(statbuf.st_mode)) goto out_close_fd;
if (statbuf.st_size <= static_cast<off_t>(limit)) goto out_close_fd;
if (statbuf.st_size <= static_cast<off_t>(keep)) goto out_close_fd;
if (!S_ISREG(statbuf.st_mode)) return;
if (statbuf.st_size <= static_cast<off_t>(limit)) return;
if (statbuf.st_size <= static_cast<off_t>(keep)) return;
// This log file is too large - we need to truncate it
LOG(INFO) << "Truncating " << path << " to " << keep << " bytes";
@ -2437,8 +2435,10 @@ void TruncateLogFile(const char* path, uint64 limit, uint64 keep) {
read_offset = statbuf.st_size - static_cast<off_t>(keep);
write_offset = 0;
ssize_t bytesin, bytesout;
while ((bytesin = pread(fd, copybuf, sizeof(copybuf), read_offset)) > 0) {
bytesout = pwrite(fd, copybuf, static_cast<size_t>(bytesin), write_offset);
while ((bytesin = pread(fd.get(), copybuf, sizeof(copybuf), read_offset)) >
0) {
bytesout =
pwrite(fd.get(), copybuf, static_cast<size_t>(bytesin), write_offset);
if (bytesout == -1) {
PLOG(ERROR) << "Unable to write to " << path;
break;
@ -2454,15 +2454,13 @@ void TruncateLogFile(const char* path, uint64 limit, uint64 keep) {
// end of the file after our last read() above, we lose their latest
// data. Too bad ...
# ifdef HAVE__CHSIZE_S
if (_chsize_s(fd, write_offset) != 0) {
if (_chsize_s(fd.get(), write_offset) != 0) {
# else
if (ftruncate(fd, write_offset) == -1) {
if (ftruncate(fd.get(), write_offset) == -1) {
# endif
PLOG(ERROR) << "Unable to truncate " << path;
}
out_close_fd:
close(fd);
#else
LOG(ERROR) << "No log truncation support.";
#endif

View File

@ -31,19 +31,6 @@
#include <fcntl.h>
#include "config.h"
#include "utilities.h"
#ifdef HAVE_GLOB_H
# include <glob.h>
#endif
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#include <chrono>
#include <cstdio>
#include <cstdlib>
@ -58,10 +45,23 @@
#include <thread>
#include <vector>
#include "config.h"
#ifdef HAVE_GLOB_H
# include <glob.h>
#endif
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#include "base/commandlineflags.h"
#include "glog/logging.h"
#include "glog/raw_logging.h"
#include "googletest.h"
#include "utilities.h"
#ifdef GLOG_USE_GFLAGS
# include <gflags/gflags.h>
@ -785,19 +785,17 @@ static void CheckFile(const string& name, const string& expected_string,
GetFiles(name + "*", &files);
CHECK_EQ(files.size(), 1UL);
FILE* file = fopen(files[0].c_str(), "r");
std::unique_ptr<std::FILE> file{fopen(files[0].c_str(), "r")};
CHECK(file != nullptr) << ": could not open " << files[0];
char buf[1000];
while (fgets(buf, sizeof(buf), file) != nullptr) {
while (fgets(buf, sizeof(buf), file.get()) != nullptr) {
char* first = strstr(buf, expected_string.c_str());
// if first == nullptr, not found.
// Terser than if (checkInFileOrNot && first != nullptr || !check...
if (checkInFileOrNot != (first == nullptr)) {
fclose(file);
return;
}
}
fclose(file);
LOG(FATAL) << "Did " << (checkInFileOrNot ? "not " : "") << "find "
<< expected_string << " in " << files[0];
}
@ -977,8 +975,8 @@ static void TestErrno() {
static void TestOneTruncate(const char* path, uint64 limit, uint64 keep,
size_t dsize, size_t ksize, size_t expect) {
int fd;
CHECK_ERR(fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0600));
FileDescriptor fd{open(path, O_RDWR | O_CREAT | O_TRUNC, 0600)};
CHECK_ERR(fd);
const char *discardstr = "DISCARDME!", *keepstr = "KEEPME!";
const size_t discard_size = strlen(discardstr), keep_size = strlen(keepstr);
@ -987,13 +985,13 @@ static void TestOneTruncate(const char* path, uint64 limit, uint64 keep,
size_t written = 0;
while (written < dsize) {
size_t bytes = min(dsize - written, discard_size);
CHECK_ERR(write(fd, discardstr, bytes));
CHECK_ERR(write(fd.get(), discardstr, bytes));
written += bytes;
}
written = 0;
while (written < ksize) {
size_t bytes = min(ksize - written, keep_size);
CHECK_ERR(write(fd, keepstr, bytes));
CHECK_ERR(write(fd.get(), keepstr, bytes));
written += bytes;
}
@ -1001,25 +999,22 @@ static void TestOneTruncate(const char* path, uint64 limit, uint64 keep,
// File should now be shorter
struct stat statbuf;
CHECK_ERR(fstat(fd, &statbuf));
CHECK_ERR(fstat(fd.get(), &statbuf));
CHECK_EQ(static_cast<size_t>(statbuf.st_size), expect);
CHECK_ERR(lseek(fd, 0, SEEK_SET));
CHECK_ERR(lseek(fd.get(), 0, SEEK_SET));
// File should contain the suffix of the original file
const size_t buf_size = static_cast<size_t>(statbuf.st_size) + 1;
char* buf = new char[buf_size];
memset(buf, 0, buf_size);
CHECK_ERR(read(fd, buf, buf_size));
std::vector<char> buf(buf_size);
CHECK_ERR(read(fd.get(), buf.data(), buf_size));
const char* p = buf;
const char* p = buf.data();
size_t checked = 0;
while (checked < expect) {
size_t bytes = min(expect - checked, keep_size);
CHECK(!memcmp(p, keepstr, bytes));
checked += bytes;
}
close(fd);
delete[] buf;
}
static void TestTruncate() {
@ -1155,13 +1150,11 @@ static void TestLogPeriodically() {
}
namespace google {
namespace glog_internal_namespace_ {
extern // in logging.cc
bool
SafeFNMatch_(const char* pattern, size_t patt_len, const char* str,
size_t str_len);
inline namespace glog_internal_namespace_ {
// in logging.cc
extern bool SafeFNMatch_(const char* pattern, size_t patt_len, const char* str,
size_t str_len);
} // namespace glog_internal_namespace_
using glog_internal_namespace_::SafeFNMatch_;
} // namespace google
static bool WrapSafeFNMatch(string pattern, string str) {
@ -1352,28 +1345,26 @@ static void TestLogSinkWaitTillSent() {
TEST(Strerror, logging) {
int errcode = EINTR;
char* msg = strdup(strerror(errcode));
const size_t buf_size = strlen(msg) + 1;
char* buf = new char[buf_size];
std::string msg = strerror(errcode);
const size_t buf_size = msg.size() + 1;
std::vector<char> buf(buf_size);
CHECK_EQ(posix_strerror_r(errcode, nullptr, 0), -1);
buf[0] = 'A';
CHECK_EQ(posix_strerror_r(errcode, buf, 0), -1);
CHECK_EQ(posix_strerror_r(errcode, buf.data(), 0), -1);
CHECK_EQ(buf[0], 'A');
CHECK_EQ(posix_strerror_r(errcode, nullptr, buf_size), -1);
#if defined(GLOG_OS_MACOSX) || defined(GLOG_OS_FREEBSD) || \
defined(GLOG_OS_OPENBSD)
// MacOSX or FreeBSD considers this case is an error since there is
// no enough space.
CHECK_EQ(posix_strerror_r(errcode, buf, 1), -1);
CHECK_EQ(posix_strerror_r(errcode, buf.data(), 1), -1);
#else
CHECK_EQ(posix_strerror_r(errcode, buf, 1), 0);
CHECK_EQ(posix_strerror_r(errcode, buf.data(), 1), 0);
#endif
CHECK_STREQ(buf, "");
CHECK_EQ(posix_strerror_r(errcode, buf, buf_size), 0);
CHECK_STREQ(buf, msg);
delete[] buf;
CHECK_STREQ(buf.data(), "");
CHECK_EQ(posix_strerror_r(errcode, buf.data(), buf_size), 0);
CHECK_STREQ(buf.data(), msg.c_str());
CHECK_EQ(msg, StrError(errcode));
free(msg);
}
// Simple routines to look at the sizes of generated code for LOG(FATAL) and

View File

@ -125,7 +125,7 @@ inline static bool VADoRawLog(char** buf, size_t* size, const char* format,
static const int kLogBufSize = 3000;
static std::once_flag crashed;
static CrashReason crash_reason;
static logging::internal::CrashReason crash_reason;
static char crash_buf[kLogBufSize + 1] = {0}; // Will end in '\0'
namespace {

View File

@ -376,22 +376,6 @@ static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, char* out,
}
namespace {
// Thin wrapper around a file descriptor so that the file descriptor
// gets closed for sure.
struct FileDescriptor {
const int fd_;
explicit FileDescriptor(int fd) : fd_(fd) {}
~FileDescriptor() {
if (fd_ >= 0) {
close(fd_);
}
}
int get() { return fd_; }
private:
FileDescriptor(const FileDescriptor&) = delete;
void operator=(const FileDescriptor&) = delete;
};
// Helper class for reading lines from file.
//
@ -520,14 +504,14 @@ static ATTRIBUTE_NOINLINE int OpenObjectFileContainingPcAndGetStartAddress(
int maps_fd;
NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
FileDescriptor wrapped_maps_fd(maps_fd);
if (wrapped_maps_fd.get() < 0) {
if (!wrapped_maps_fd) {
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) {
if (!wrapped_mem_fd) {
return -1;
}

View File

@ -71,6 +71,12 @@ bool IsGoogleLoggingInitialized() {
return g_program_invocation_short_name != nullptr;
}
inline namespace glog_internal_namespace_ {
constexpr int FileDescriptor::InvalidHandle;
} // namespace glog_internal_namespace_
} // namespace google
// The following APIs are all internal.
@ -181,7 +187,7 @@ DumpStackTraceAndExit() {
namespace google {
namespace glog_internal_namespace_ {
inline namespace glog_internal_namespace_ {
const char* ProgramInvocationShortName() {
if (g_program_invocation_short_name != nullptr) {
@ -252,10 +258,10 @@ void DumpStackTraceToString(string* stacktrace) {
// We use an atomic operation to prevent problems with calling CrashReason
// from inside the Mutex implementation (potentially through RAW_CHECK).
static std::atomic<const CrashReason*> g_reason{nullptr};
static std::atomic<const logging::internal::CrashReason*> g_reason{nullptr};
void SetCrashReason(const CrashReason* r) {
const CrashReason* expected = nullptr;
void SetCrashReason(const logging::internal::CrashReason* r) {
const logging::internal::CrashReason* expected = nullptr;
g_reason.compare_exchange_strong(expected, r);
}

View File

@ -35,6 +35,13 @@
#ifndef UTILITIES_H__
#define UTILITIES_H__
#include <cstddef>
#include <cstdio>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
// printf macros for size_t, in the style of inttypes.h
#ifdef _LP64
# define __PRIS_PREFIX "z"
@ -53,12 +60,6 @@
#define PRIXS __PRIS_PREFIX "X"
#define PRIoS __PRIS_PREFIX "o"
#include <cstdio>
#include <memory>
#include <string>
#include <thread>
#include <type_traits>
#include "glog/logging.h"
#if defined(GLOG_USE_WINDOWS_PORT)
@ -146,7 +147,26 @@ using ssize_t = std::ptrdiff_t;
namespace google {
namespace glog_internal_namespace_ {
namespace logging {
namespace internal {
struct CrashReason {
CrashReason() = default;
const char* filename{nullptr};
int line_number{0};
const char* message{nullptr};
// We'll also store a bit of stack trace context at the time of crash as
// it may not be available later on.
void* stack[32];
int depth{0};
};
} // namespace internal
} // namespace logging
inline namespace glog_internal_namespace_ {
#if defined(__has_attribute)
# if __has_attribute(noinline)
@ -179,20 +199,7 @@ const char* const_basename(const char* filepath);
void DumpStackTraceToString(std::string* stacktrace);
struct CrashReason {
CrashReason() = default;
const char* filename{nullptr};
int line_number{0};
const char* message{nullptr};
// We'll also store a bit of stack trace context at the time of crash as
// it may not be available later on.
void* stack[32];
int depth{0};
};
void SetCrashReason(const CrashReason* r);
void SetCrashReason(const logging::internal::CrashReason* r);
void InitGoogleLoggingUtilities(const char* argv0);
void ShutdownGoogleLoggingUtilities();
@ -215,12 +222,96 @@ class ScopedExit final {
Functor functor_;
};
// Thin wrapper around a file descriptor so that the file descriptor
// gets closed for sure.
class GLOG_NO_EXPORT FileDescriptor final {
static constexpr int InvalidHandle = -1;
public:
constexpr FileDescriptor() noexcept : FileDescriptor{nullptr} {}
constexpr explicit FileDescriptor(int fd) noexcept : fd_{fd} {}
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr FileDescriptor(std::nullptr_t) noexcept : fd_{InvalidHandle} {}
FileDescriptor(const FileDescriptor& other) = delete;
FileDescriptor& operator=(const FileDescriptor& other) = delete;
FileDescriptor(FileDescriptor&& other) noexcept : fd_{other.release()} {}
FileDescriptor& operator=(FileDescriptor&& other) noexcept {
// Close the file descriptor being held and assign a new file descriptor
// previously held by 'other' without closing it.
reset(other.release());
return *this;
}
constexpr explicit operator bool() const noexcept {
return fd_ != InvalidHandle;
}
constexpr int get() const noexcept { return fd_; }
int release() noexcept { return std::exchange(fd_, InvalidHandle); }
void reset(std::nullptr_t) noexcept { safe_close(); }
void reset() noexcept { reset(nullptr); }
void reset(int fd) noexcept {
reset();
fd_ = fd;
}
int close() noexcept { return unsafe_close(); }
~FileDescriptor() { safe_close(); }
private:
int unsafe_close() noexcept { return ::close(release()); }
void safe_close() noexcept {
if (*this) {
unsafe_close();
}
}
int fd_;
};
// Provide variants of (in)equality comparison operators to avoid constructing
// temporaries.
constexpr bool operator==(const FileDescriptor& lhs, int rhs) noexcept {
return lhs.get() == rhs;
}
constexpr bool operator==(int lhs, const FileDescriptor& rhs) noexcept {
return rhs == lhs;
}
constexpr bool operator!=(const FileDescriptor& lhs, int rhs) noexcept {
return !(lhs == rhs);
}
constexpr bool operator!=(int lhs, const FileDescriptor& rhs) noexcept {
return !(lhs == rhs);
}
constexpr bool operator==(const FileDescriptor& lhs, std::nullptr_t) noexcept {
return !lhs;
}
constexpr bool operator==(std::nullptr_t, const FileDescriptor& rhs) noexcept {
return !rhs;
}
constexpr bool operator!=(const FileDescriptor& lhs, std::nullptr_t) noexcept {
return static_cast<bool>(lhs);
}
constexpr bool operator!=(std::nullptr_t, const FileDescriptor& rhs) noexcept {
return static_cast<bool>(rhs);
}
} // namespace glog_internal_namespace_
} // namespace google
using namespace google::glog_internal_namespace_;
template <>
struct std::default_delete<std::FILE> {
void operator()(FILE* p) const noexcept { fclose(p); }

View File

@ -50,18 +50,14 @@ using std::string;
namespace google {
namespace glog_internal_namespace_ {
// Used by logging_unittests.cc so can't make it static here.
GLOG_EXPORT bool SafeFNMatch_(const char* pattern, size_t patt_len,
const char* str, size_t str_len);
inline namespace glog_internal_namespace_ {
// 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.
// It's not a static function for the unittest.
GLOG_EXPORT bool SafeFNMatch_(const char* pattern, size_t patt_len,
const char* str, size_t str_len) {
GLOG_NO_EXPORT bool SafeFNMatch_(const char* pattern, size_t patt_len,
const char* str, size_t str_len) {
size_t p = 0;
size_t s = 0;
while (true) {

View File

@ -35,6 +35,7 @@
#include <cstdlib>
#include <cstring>
#include <cwchar>
#include <memory>
/* Indicates that d_type field is available in dirent structure */
#define _DIRENT_HAVE_D_TYPE
@ -622,8 +623,6 @@ static WIN32_FIND_DATAW* dirent_next(_WDIR* dirp) {
* Open directory stream using plain old C-string.
*/
static DIR* opendir(const char* dirname) {
struct DIR* dirp;
/* Must have directory name */
if (dirname == nullptr || dirname[0] == '\0') {
dirent_set_errno(ENOENT);
@ -631,7 +630,9 @@ static DIR* opendir(const char* dirname) {
}
/* Allocate memory for DIR structure */
dirp = (DIR*)malloc(sizeof(struct DIR));
std::unique_ptr<DIR, decltype(&free)> dirp{
static_cast<DIR*>(malloc(sizeof(struct DIR))), &free};
if (!dirp) {
return nullptr;
}
@ -649,23 +650,18 @@ static DIR* opendir(const char* dirname) {
* the output buffer is too small to contain the resulting
* string.
*/
goto exit_free;
return nullptr;
}
/* Open directory stream using wide-character name */
dirp->wdirp = _wopendir(wname);
if (!dirp->wdirp) {
goto exit_free;
return nullptr;
}
}
/* Success */
return dirp;
/* Failure */
exit_free:
free(dirp);
return nullptr;
return dirp.release();
}
/*