From 22d22198ecd4e1c9745baaed24db1d804a8c1530 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 11 Oct 2023 01:08:12 +0900 Subject: [PATCH 1/4] feat: use thread-safe variant of strerror --- toml/exception.hpp | 48 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/toml/exception.hpp b/toml/exception.hpp index 2b0bc63..7aa9911 100644 --- a/toml/exception.hpp +++ b/toml/exception.hpp @@ -11,11 +11,57 @@ namespace toml { +namespace detail +{ + +inline std::string str_error(int errnum) +{ + // C++ standard strerror is not thread-safe. + // C11 provides thread-safe version of this function, `strerror_s`, but it + // is not available in C++. + // To avoid using std::strerror, we need to use platform-specific functions. + // If none of the conditions are met, it calls std::strerror as a fallback. +#ifdef _MSC_VER // MSVC + constexpr std::size_t bufsize = 256; + std::array buf; + const auto result = strerror_s(buf.data(), bufsize, errnum); + if(result != 0) + { + return std::string("strerror_s failed"); + } + else + { + return std::string(buf.data()); + } +#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE // XSI + constexpr std::size_t bufsize = 256; + std::array buf; + const int result = strerror_r(errnum, buf.data(), bufsize); + if (result != 0) + { + return std::string("strerror_r failed"); + } + else + { + return std::string(buf.data()); + } +#elif defined(_GNU_SOURCE) // GNU extension + constexpr std::size_t bufsize = 256; + std::array buf; + const char* result = strerror_r(errnum, buf.data(), bufsize); + return std::string(result); +#else // fallback + return std::strerror(errnum); +#endif +} + +} // detail + struct file_io_error : public std::runtime_error { public: file_io_error(int errnum, const std::string& msg, const std::string& fname) - : std::runtime_error(msg + " \"" + fname + "\": " + std::strerror(errnum)), + : std::runtime_error(msg + " \"" + fname + "\": " + detail::str_error(errnum)), errno_(errnum) {} int get_errno() const noexcept {return errno_;} From 9b7b8908e8fd113b5642b0a66f60040f1a3436f2 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 11 Oct 2023 01:24:41 +0900 Subject: [PATCH 2/4] fix: avoid evaluating undefined macro as zero to suppress a warning --- toml/exception.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/toml/exception.hpp b/toml/exception.hpp index 7aa9911..72a4a62 100644 --- a/toml/exception.hpp +++ b/toml/exception.hpp @@ -33,7 +33,12 @@ inline std::string str_error(int errnum) { return std::string(buf.data()); } -#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE // XSI +#elif defined(_GNU_SOURCE) + constexpr std::size_t bufsize = 256; + std::array buf; + const char* result = strerror_r(errnum, buf.data(), bufsize); + return std::string(result); +#elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) constexpr std::size_t bufsize = 256; std::array buf; const int result = strerror_r(errnum, buf.data(), bufsize); @@ -45,11 +50,6 @@ inline std::string str_error(int errnum) { return std::string(buf.data()); } -#elif defined(_GNU_SOURCE) // GNU extension - constexpr std::size_t bufsize = 256; - std::array buf; - const char* result = strerror_r(errnum, buf.data(), bufsize); - return std::string(result); #else // fallback return std::strerror(errnum); #endif From 947c9951894f90392c1945ddde3639f085d8227d Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 11 Oct 2023 01:43:43 +0900 Subject: [PATCH 3/4] fix: include array to use char buffer --- toml/exception.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/toml/exception.hpp b/toml/exception.hpp index 72a4a62..3702a8d 100644 --- a/toml/exception.hpp +++ b/toml/exception.hpp @@ -2,8 +2,11 @@ // Distributed under the MIT License. #ifndef TOML11_EXCEPTION_HPP #define TOML11_EXCEPTION_HPP -#include + +#include #include +#include + #include #include "source_location.hpp" From 937a7c45feed06d2245bee5d11b9ada82254d2ce Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Wed, 11 Oct 2023 01:44:06 +0900 Subject: [PATCH 4/4] feat: fill char buffer with null char those funcs always return null-terminated string but just to make it sure --- toml/exception.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/toml/exception.hpp b/toml/exception.hpp index 3702a8d..927d791 100644 --- a/toml/exception.hpp +++ b/toml/exception.hpp @@ -27,6 +27,7 @@ inline std::string str_error(int errnum) #ifdef _MSC_VER // MSVC constexpr std::size_t bufsize = 256; std::array buf; + buf.fill('\0'); const auto result = strerror_s(buf.data(), bufsize, errnum); if(result != 0) { @@ -39,11 +40,13 @@ inline std::string str_error(int errnum) #elif defined(_GNU_SOURCE) constexpr std::size_t bufsize = 256; std::array buf; + buf.fill('\0'); const char* result = strerror_r(errnum, buf.data(), bufsize); return std::string(result); #elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) constexpr std::size_t bufsize = 256; std::array buf; + buf.fill('\0'); const int result = strerror_r(errnum, buf.data(), bufsize); if (result != 0) {