[PATCH v2] libstdc++: Fix std::system_category().message(int) on mingw32 target
Jonathan Wakely
jwakely.gcc@gmail.com
Sat Jan 10 12:17:43 GMT 2026
On Sat, 10 Jan 2026 at 10:45, Wang Jinghao <zheng.xianyuwang@gmail.com> wrote:
>
> On the mingw32 target, std::system_category().message(int) uses
> FormatMessage api to format error messages. When the error message contains
> insert sequences, it is unsafe not to use the FORMAT_MESSAGE_OGNORE_INSERTS
> flag, as seen at:
> https://devblogs.microsoft.com/oldnewthing/20071128-00/?p=24353
>
> The output of FormatMessage ends with "\r\n" and includes a Full stop character
> used by the current thread's UI language. Now, we will remove "\r\n" and
> any trailing '.' from the output in any language environment.
>
> In the testsuite for std::system_category().message(int), we first switch the
> thread UI language to en-US tomeet expectations in any language environment.
Thanks, the patch looks good now.
> libstdc++-v3/ChangeLog:
>
> * src/c++11/system_error.cc (system_error_category) [_WIN32]:
> Fix typo in __MINGW32__ macro name.
> Adjust behavior on the mingw32 target.
The two lines above relate to the error_category/system_category.cc
test, not the src/c++11/system_category.cc source file, right?
> Use FormatMessageA function instead of FormatMessage macro.
> * testsuite/19_diagnostics/error_category/system_category.cc:
> Adjust behavior on the mingw32 target.
I've just noticed that there's no Signed-off-by trailer in the patch.
Do you have a copyright assignment filed with the FSF?
As documented at https://gcc.gnu.org/contribute.html#legal we need
either a copyright assignment, or DCO sign-off.
If you don't have a copyrigh assignment, could you please add the
Signed-off-by trailer if you are willing and able to agree to the
terms of https://gcc.gnu.org/dco.html ?
Thanks
> ---
> libstdc++-v3/src/c++11/system_error.cc | 21 ++++++++++---------
> .../error_category/system_category.cc | 18 +++++++++++++---
> 2 files changed, 26 insertions(+), 13 deletions(-)
>
> diff --git a/libstdc++-v3/src/c++11/system_error.cc b/libstdc++-v3/src/c++11/system_error.cc
> index 548c88fcfde..7e3a3a0c904 100644
> --- a/libstdc++-v3/src/c++11/system_error.cc
> +++ b/libstdc++-v3/src/c++11/system_error.cc
> @@ -161,22 +161,23 @@ namespace
> #if defined(_WIN32) && !defined(__CYGWIN__)
> char* buf = nullptr;
> auto len
> - = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
> - | FORMAT_MESSAGE_ALLOCATE_BUFFER,
> - nullptr,
> - i,
> - LANG_USER_DEFAULT,
> - reinterpret_cast<LPTSTR>(&buf),
> - 0,
> - nullptr);
> + = FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM
> + | FORMAT_MESSAGE_ALLOCATE_BUFFER
> + | FORMAT_MESSAGE_IGNORE_INSERTS,
> + nullptr,
> + i,
> + LANG_USER_DEFAULT,
> + reinterpret_cast<LPTSTR>(&buf),
> + 0,
> + nullptr);
> if (len > 0)
> {
> struct deleter {
> void operator()(void* p) const { ::LocalFree(p); }
> };
> std::unique_ptr<char[], deleter> guard(buf);
> - if (len > 3 && !__builtin_memcmp(buf + len - 3, ".\r\n", 3)) [[likely]]
> - len -= 3;
> + if (len > 2 && !__builtin_memcmp (buf + len - 2, "\r\n", 2)) [[likely]]
> + len -= 2 + (buf[len - 3] == '.');
> return string(buf, len);
> }
> return string("Unknown error code");
> diff --git a/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc b/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc
> index 250d34f9bb5..03577234c43 100644
> --- a/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc
> +++ b/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc
> @@ -21,6 +21,11 @@
> #include <locale>
> #include <testsuite_hooks.h>
>
> +#if defined __MINGW32__ || defined __MINGW64__
> +#define WIN32_LEAN_AND_MEAN
> +#include <windows.h>
> +#endif
> +
> void
> test01()
> {
> @@ -34,7 +39,7 @@ test02()
> const std::error_category& cat = std::system_category();
> std::error_condition cond;
>
> -#if defined __MING32__ || defined __MINGW64__
> +#if defined __MINGW32__ || defined __MINGW64__
> cond = cat.default_error_condition(8); // ERROR_NOT_ENOUGH_MEMORY
> VERIFY( cond.value() == ENOMEM );
> VERIFY( cond.category() == std::generic_category() );
> @@ -112,9 +117,16 @@ test03()
> // set "C" locale to get expected message
> auto loc = std::locale::global(std::locale::classic());
>
> -#if defined __MING32__ || defined __MINGW64__
> +#if defined __MINGW32__ || defined __MINGW64__
> + // On Windows, set thread preferred UI languages to "en-US"
> + // to get expected message
> + ULONG num_langs = 1;
> + SetThreadPreferredUILanguages(MUI_LANGUAGE_NAME, L"en-US\0", &num_langs);
> +
> std::string msg = std::system_category().message(5); // ERROR_ACCESS_DENIED
> - VERIFY(msg == "Access denied");
> + VERIFY(msg == "Access is denied");
> +
> + SetThreadPreferredUILanguages(MUI_RESET_FILTERS, nullptr, nullptr);
> #else
> std::string msg = std::system_category().message(EBADF);
> VERIFY( msg.find("file") != std::string::npos );
> --
> 2.52.0
>
More information about the Libstdc++
mailing list