summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2022-03-15 02:35:13 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-03-16 01:41:26 +0000
commit4b4a334cf67eba2abaaca1854eac5a8a03bee3e7 (patch)
tree10e35337c0238e6ef410ebeaec548bb7592a234f
parent04d14e9675539103de563ffa250380538206ee93 (diff)
downloadmongo-4b4a334cf67eba2abaaca1854eac5a8a03bee3e7.tar.gz
SERVER-51770 add std::error_code functions to errno_util
Remove errnoWithPrefix, errnoAndDescription
-rw-r--r--src/mongo/base/secure_allocator.cpp35
-rw-r--r--src/mongo/db/startup_warnings_common.cpp6
-rw-r--r--src/mongo/db/traffic_reader.cpp9
-rw-r--r--src/mongo/util/errno_util.cpp101
-rw-r--r--src/mongo/util/errno_util.h49
-rw-r--r--src/mongo/util/processinfo.cpp6
6 files changed, 86 insertions, 120 deletions
diff --git a/src/mongo/base/secure_allocator.cpp b/src/mongo/base/secure_allocator.cpp
index 06a0187d695..47837cb5c7d 100644
--- a/src/mongo/base/secure_allocator.cpp
+++ b/src/mongo/base/secure_allocator.cpp
@@ -33,6 +33,7 @@
#include "mongo/base/secure_allocator.h"
+#include <fmt/format.h>
#include <memory>
#ifdef _WIN32
@@ -58,6 +59,11 @@ namespace mongo::secure_allocator_details {
namespace {
+std::string fmtError(StringData prefix) {
+ auto ec = lastSystemError();
+ return format(FMT_STRING("{}: {}"), prefix, errorMessage(ec));
+}
+
/**
* NOTE(jcarey): Why not new/delete?
*
@@ -74,7 +80,7 @@ namespace {
void EnablePrivilege(const wchar_t* name) {
LUID luid;
if (!LookupPrivilegeValueW(nullptr, name, &luid)) {
- auto str = errnoWithPrefix("Failed to LookupPrivilegeValue");
+ auto str = fmtError("Failed to LookupPrivilegeValue");
LOGV2_WARNING(23704, "{str}", "str"_attr = str);
return;
}
@@ -82,7 +88,7 @@ void EnablePrivilege(const wchar_t* name) {
// Get the access token for the current process.
HANDLE accessToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &accessToken)) {
- auto str = errnoWithPrefix("Failed to OpenProcessToken");
+ auto str = fmtError("Failed to OpenProcessToken");
LOGV2_WARNING(23705, "{str}", "str"_attr = str);
return;
}
@@ -97,7 +103,7 @@ void EnablePrivilege(const wchar_t* name) {
if (!AdjustTokenPrivileges(
accessToken, false, &privileges, sizeof(privileges), nullptr, nullptr)) {
- auto str = errnoWithPrefix("Failed to AdjustTokenPrivileges");
+ auto str = fmtError("Failed to AdjustTokenPrivileges");
LOGV2_WARNING(23706, "{str}", "str"_attr = str);
}
@@ -133,7 +139,7 @@ void growWorkingSize(std::size_t bytes) {
stdx::lock_guard<stdx::mutex> lock(workingSizeMutex);
if (!GetProcessWorkingSetSize(GetCurrentProcess(), &minWorkingSetSize, &maxWorkingSetSize)) {
- auto str = errnoWithPrefix("Failed to GetProcessWorkingSetSize");
+ auto str = fmtError("Failed to GetProcessWorkingSetSize");
LOGV2_FATAL(40285, "{str}", "str"_attr = str);
}
@@ -147,7 +153,7 @@ void growWorkingSize(std::size_t bytes) {
maxWorkingSetSize,
QUOTA_LIMITS_HARDWS_MIN_ENABLE |
QUOTA_LIMITS_HARDWS_MAX_DISABLE)) {
- auto str = errnoWithPrefix("Failed to SetProcessWorkingSetSizeEx");
+ auto str = fmtError("Failed to SetProcessWorkingSetSizeEx");
LOGV2_FATAL(40286, "{str}", "str"_attr = str);
}
}
@@ -166,7 +172,7 @@ void* systemAllocate(std::size_t bytes) {
auto ptr = VirtualAlloc(nullptr, bytes, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!ptr) {
- auto str = errnoWithPrefix("Failed to VirtualAlloc");
+ auto str = fmtError("Failed to VirtualAlloc");
LOGV2_FATAL(28835, "{str}", "str"_attr = str);
}
@@ -182,7 +188,7 @@ void* systemAllocate(std::size_t bytes) {
}
}
- auto str = errnoWithPrefix("Failed to VirtualLock");
+ auto str = fmtError("Failed to VirtualLock");
LOGV2_FATAL(28828, "{str}", "str"_attr = str);
}
@@ -191,14 +197,14 @@ void* systemAllocate(std::size_t bytes) {
void systemDeallocate(void* ptr, std::size_t bytes) {
if (VirtualUnlock(ptr, bytes) == 0) {
- auto str = errnoWithPrefix("Failed to VirtualUnlock");
+ auto str = fmtError("Failed to VirtualUnlock");
LOGV2_FATAL(28829, "{str}", "str"_attr = str);
}
// VirtualFree needs to take 0 as the size parameter for MEM_RELEASE
// (that's how the api works).
if (VirtualFree(ptr, 0, MEM_RELEASE) == 0) {
- auto str = errnoWithPrefix("Failed to VirtualFree");
+ auto str = fmtError("Failed to VirtualFree");
LOGV2_FATAL(28830, "{str}", "str"_attr = str);
}
}
@@ -237,14 +243,14 @@ void* systemAllocate(std::size_t bytes) {
mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MONGO_MAP_ANONYMOUS, -1, 0);
if (!ptr) {
- auto str = errnoWithPrefix("Failed to mmap");
+ auto str = fmtError("Failed to mmap");
LOGV2_FATAL(23714, "{str}", "str"_attr = str);
fassertFailed(28831);
}
if (mlock(ptr, bytes) != 0) {
const int err = errno;
- auto str = errnoWithPrefix(
+ auto str = fmtError(
"Failed to mlock: Cannot allocate locked memory. For more details see: "
"https://dochub.mongodb.org/core/cannot-allocate-locked-memory");
LOGV2_FATAL(23715, "{str}", "str"_attr = str, "errno"_attr = err);
@@ -267,16 +273,17 @@ void systemDeallocate(void* ptr, std::size_t bytes) {
#endif
if (munlock(ptr, bytes) != 0) {
+ auto str = fmtError("Failed to munlock");
LOGV2_FATAL(28833,
"{errnoWithPrefix_Failed_to_munlock}",
- "errnoWithPrefix_Failed_to_munlock"_attr =
- errnoWithPrefix("Failed to munlock"));
+ "errnoWithPrefix_Failed_to_munlock"_attr = str);
}
if (munmap(ptr, bytes) != 0) {
+ auto str = fmtError("Failed to munmap");
LOGV2_FATAL(28834,
"{errnoWithPrefix_Failed_to_munmap}",
- "errnoWithPrefix_Failed_to_munmap"_attr = errnoWithPrefix("Failed to munmap"));
+ "errnoWithPrefix_Failed_to_munmap"_attr = str);
}
}
diff --git a/src/mongo/db/startup_warnings_common.cpp b/src/mongo/db/startup_warnings_common.cpp
index f2c493a87c8..0c73f543064 100644
--- a/src/mongo/db/startup_warnings_common.cpp
+++ b/src/mongo/db/startup_warnings_common.cpp
@@ -50,7 +50,7 @@ namespace mongo {
bool CheckPrivilegeEnabled(const wchar_t* name) {
LUID luid;
if (!LookupPrivilegeValueW(nullptr, name, &luid)) {
- auto str = errnoWithPrefix("Failed to LookupPrivilegeValue");
+ auto str = "Failed to LookupPrivilegeValue: " + errorMessage(lastSystemError());
LOGV2_WARNING(4718701, "{str}", "str"_attr = str);
return false;
}
@@ -58,7 +58,7 @@ bool CheckPrivilegeEnabled(const wchar_t* name) {
// Get the access token for the current process.
HANDLE accessToken;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &accessToken)) {
- auto str = errnoWithPrefix("Failed to OpenProcessToken");
+ auto str = "Failed to OpenProcessToken: " + errorMessage(lastSystemError());
LOGV2_WARNING(4718702, "{str}", "str"_attr = str);
return false;
}
@@ -74,7 +74,7 @@ bool CheckPrivilegeEnabled(const wchar_t* name) {
privileges.Privilege[0].Attributes = 0;
if (!PrivilegeCheck(accessToken, &privileges, &ret)) {
- auto str = errnoWithPrefix("Failed to PrivilegeCheck");
+ auto str = "Failed to PrivilegeCheck: " + errorMessage(lastSystemError());
LOGV2_WARNING(4718703, "{str}", "str"_attr = str);
return false;
}
diff --git a/src/mongo/db/traffic_reader.cpp b/src/mongo/db/traffic_reader.cpp
index d6b5bc27a8f..c6a4ade2b48 100644
--- a/src/mongo/db/traffic_reader.cpp
+++ b/src/mongo/db/traffic_reader.cpp
@@ -90,12 +90,11 @@ bool readBytes(size_t toRead, char* buf, int fd) {
#endif
if (r == -1) {
- auto pair = errnoAndDescription();
-
+ auto ec = lastPosixError();
uassert(ErrorCodes::FileStreamFailed,
- str::stream() << "failed to read bytes: errno(" << pair.first
- << ") : " << pair.second,
- pair.first == EINTR);
+ str::stream() << "failed to read bytes: errno(" << ec.value()
+ << ") : " << errorMessage(ec),
+ ec.value() == EINTR);
continue;
} else if (r == 0) {
diff --git a/src/mongo/util/errno_util.cpp b/src/mongo/util/errno_util.cpp
index 564c0071ead..6e75b4b511a 100644
--- a/src/mongo/util/errno_util.cpp
+++ b/src/mongo/util/errno_util.cpp
@@ -27,102 +27,27 @@
* it in the license file.
*/
-#include "mongo/platform/basic.h"
-
#include "mongo/util/errno_util.h"
-#include <sstream>
-
-#ifndef _WIN32
-#include <cstring> // For strerror_r
-#include <errno.h> // For errno
-#endif
-
-#include "mongo/util/scopeguard.h"
-#include "mongo/util/str.h"
-#include "mongo/util/text.h"
+#include <cerrno>
+#include <fmt/format.h>
+#include <system_error>
namespace mongo {
-namespace {
-const char kUnknownMsg[] = "Unknown error ";
-const int kBuflen = 256; // strerror strings in non-English locales can be large.
-} // namespace
+using namespace fmt::literals;
-std::string errnoWithDescription(int errNumber) {
+std::string errorMessage(std::error_code ec) {
+ std::string r = ec.message();
+ bool vague = false;
#if defined(_WIN32)
- if (errNumber == -1)
- errNumber = GetLastError();
-#else
- if (errNumber < 0)
- errNumber = errno;
+ vague = (r == "unknown error"_sd);
+#elif defined(_LIBCPP_VERSION)
+ vague = StringData{r}.startsWith("unspecified"_sd);
#endif
-
- char buf[kBuflen];
- char* msg{nullptr};
-
-#if defined(__GNUC__) && defined(_GNU_SOURCE) && \
- (!defined(__ANDROID_API__) || !(__ANDROID_API__ <= 22)) && !defined(EMSCRIPTEN)
- msg = strerror_r(errNumber, buf, kBuflen);
-#elif defined(_WIN32)
-
- LPWSTR errorText = nullptr;
- FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- nullptr,
- errNumber,
- 0,
- reinterpret_cast<LPWSTR>(&errorText), // output
- 0, // minimum size for output buffer
- nullptr);
-
- if (errorText) {
- ON_BLOCK_EXIT([&errorText] { LocalFree(errorText); });
- std::string utf8ErrorText = toUtf8String(errorText);
- auto size = utf8ErrorText.find_first_of("\r\n");
- if (size == std::string::npos) { // not found
- size = utf8ErrorText.length();
- }
-
- if (size >= kBuflen) {
- size = kBuflen - 1;
- }
-
- memcpy(buf, utf8ErrorText.c_str(), size);
- buf[size] = '\0';
- msg = buf;
- } else if (strerror_s(buf, kBuflen, errNumber) != 0) {
- msg = buf;
- }
-#else /* XSI strerror_r */
- if (strerror_r(errNumber, buf, kBuflen) == 0) {
- msg = buf;
- }
-#endif
-
- if (!msg) {
- return str::stream() << kUnknownMsg << errNumber;
- }
-
- return {msg};
-}
-
-std::pair<int, std::string> errnoAndDescription() {
-#if defined(_WIN32)
- int errNumber = GetLastError();
-#else
- int errNumber = errno;
-#endif
- return {errNumber, errnoWithDescription(errNumber)};
-}
-
-std::string errnoWithPrefix(StringData prefix) {
- const auto suffix = errnoWithDescription();
- std::stringstream ss;
- if (!prefix.empty())
- ss << prefix << ": ";
- ss << suffix;
- return ss.str();
+ if (vague)
+ return "Unknown error {}"_format(ec.value());
+ return r;
}
} // namespace mongo
diff --git a/src/mongo/util/errno_util.h b/src/mongo/util/errno_util.h
index d948b30672f..0464c38a409 100644
--- a/src/mongo/util/errno_util.h
+++ b/src/mongo/util/errno_util.h
@@ -29,6 +29,7 @@
#pragma once
+#include <system_error>
#include <utility>
#include "mongo/base/string_data.h"
@@ -36,20 +37,54 @@
namespace mongo {
/**
- * Return a string containing the system errno (error number) and corresponding error message.
+ * Returns `{errno, std::generic_category()}`.
+ * Windows has both Windows errors and POSIX errors. That is, there's a
+ * `GetLastError` and an `errno`. They are tracked separately, and unrelated to
+ * each other.
+ *
+ * In practice, this function is useful only to handle the `errno`-setting POSIX
+ * compatibility functions on Windows.
+ *
+ * On POSIX systems, `std::system_category` is potentially a superset of
+ * `std::generic_category`, so `lastSystemError` should be preferred for
+ * handling system errors.
*/
-std::string errnoWithDescription(int errorcode = -1);
+inline std::error_code lastPosixError() {
+ return std::error_code(errno, std::generic_category());
+}
/**
- * Return the errno (error number) and the errnoWithDescription() string.
+ * On POSIX, returns `{errno, std::system_category()}`.
+ * On Windows, returns `{GetLastError(), std::system_category()}`, but see `lastPosixError`.
*/
-std::pair<int, std::string> errnoAndDescription();
+inline std::error_code lastSystemError() {
+#ifdef _WIN32
+ int e = GetLastError();
+#else
+ int e = errno;
+#endif
+ return std::error_code(e, std::system_category());
+}
/**
- * Return a string with the given prefix followed by the errnoWithDescription() string.
+ * Returns `ec.message()`, possibly augmented to disambiguate unknowns.
*
- * Useful in conjunction with uassert/massert.
+ * In libstdc++, the unknown error messages include the number. Windows and
+ * Libc++ do not include it. So if the code is an unknown, it is replaced with the
+ * message that libstdc++ would have given, which is the expanded format
+ * expression:
+ * `"Unknown error {}"_format(ec.value())`
*/
-std::string errnoWithPrefix(StringData prefix);
+std::string errorMessage(std::error_code ec);
+
+/** A system error code's error message. */
+inline std::string errnoWithDescription(int e) {
+ return errorMessage(std::error_code{e, std::system_category()});
+}
+
+/** The last system error code's error message. */
+inline std::string errnoWithDescription() {
+ return errorMessage(lastSystemError());
+}
} // namespace mongo
diff --git a/src/mongo/util/processinfo.cpp b/src/mongo/util/processinfo.cpp
index 197ebe00848..519aca8c2e1 100644
--- a/src/mongo/util/processinfo.cpp
+++ b/src/mongo/util/processinfo.cpp
@@ -65,8 +65,8 @@ public:
std::ofstream out(path.c_str(), std::ios_base::out);
out << ProcessId::getCurrent() << std::endl;
if (!out.good()) {
- auto errAndStr = errnoAndDescription();
- if (errAndStr.first == 0) {
+ auto ec = lastSystemError();
+ if (!ec) {
LOGV2(23329,
"ERROR: Cannot write pid file to {path_string}: Unable to determine OS error",
"path_string"_attr = path.string());
@@ -74,7 +74,7 @@ public:
LOGV2(23330,
"ERROR: Cannot write pid file to {path_string}: {errAndStr_second}",
"path_string"_attr = path.string(),
- "errAndStr_second"_attr = errAndStr.second);
+ "errAndStr_second"_attr = errorMessage(ec));
}
} else {
boost::system::error_code ec;