From 4b4a334cf67eba2abaaca1854eac5a8a03bee3e7 Mon Sep 17 00:00:00 2001 From: Billy Donahue Date: Tue, 15 Mar 2022 02:35:13 +0000 Subject: SERVER-51770 add std::error_code functions to errno_util Remove errnoWithPrefix, errnoAndDescription --- src/mongo/base/secure_allocator.cpp | 35 ++++++----- src/mongo/db/startup_warnings_common.cpp | 6 +- src/mongo/db/traffic_reader.cpp | 9 ++- src/mongo/util/errno_util.cpp | 101 ++++--------------------------- src/mongo/util/errno_util.h | 49 ++++++++++++--- src/mongo/util/processinfo.cpp | 6 +- 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 #include #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 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 - -#ifndef _WIN32 -#include // For strerror_r -#include // For errno -#endif - -#include "mongo/util/scopeguard.h" -#include "mongo/util/str.h" -#include "mongo/util/text.h" +#include +#include +#include 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(&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 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 #include #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 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; -- cgit v1.2.1