[v2] libstdc++: Fix std::system_category().message(int) on mingw32 target

Message ID 20260110104314.1943-1-zheng.xianyuwang@gmail.com
State Committed
Headers
Series [v2] libstdc++: Fix std::system_category().message(int) on mingw32 target |

Commit Message

Wang Jinghao Jan. 10, 2026, 10:43 a.m. UTC
  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.

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.
	Use FormatMessageA function instead of FormatMessage macro.
	* testsuite/19_diagnostics/error_category/system_category.cc:
	Adjust behavior on the mingw32 target.
---
 libstdc++-v3/src/c++11/system_error.cc        | 21 ++++++++++---------
 .../error_category/system_category.cc         | 18 +++++++++++++---
 2 files changed, 26 insertions(+), 13 deletions(-)
  

Comments

Jonathan Wakely Jan. 10, 2026, 12:17 p.m. UTC | #1
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
>
  
Jonathan Wakely Jan. 10, 2026, 12:24 p.m. UTC | #2
On Sat, 10 Jan 2026 at 12:17, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
>
> 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 ?

Actually, don't worry, I don't think this change can be considered
"legally significant", because the changes are small except for some
whitespace changes and typo fixes.

So I'll push this to the git repo - thanks for fixing it!
  
Jonathan Wakely Jan. 10, 2026, 12:50 p.m. UTC | #3
On Sat, 10 Jan 2026 at 12:24, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
>
> On Sat, 10 Jan 2026 at 12:17, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> >
> > 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 ?
>
> Actually, don't worry, I don't think this change can be considered
> "legally significant", because the changes are small except for some
> whitespace changes and typo fixes.
>
> So I'll push this to the git repo - thanks for fixing it!

Hmm, when I test this with mingw-w64 under Wine, I get:

/home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc
01ec:fixme:nls:RtlSetThreadPreferredUILanguages 8, 00000001400A8122,
000000000021FE8C
/home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc:127:
void test03(): Assertion 'msg == "Access is denied"'
failed.
FAIL: /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc

Inspecting the 'msg' string, the content is "Access denied", which is
what we have on trunk today.

Can you confirm whether it should be "Access is denied" (as in your
patch) or "Access denied"?
  
Wang Jinghao Jan. 10, 2026, 1:28 p.m. UTC | #4
On 2026/1/10 20:50, Jonathan Wakely wrote:
> On Sat, 10 Jan 2026 at 12:24, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
>> On Sat, 10 Jan 2026 at 12:17, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
>>> 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?


Sorry, I made a mistake. The correction for the __MINGW32__ macro

is in error_category/system_category.cc.


>>>>          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 ?
>> Actually, don't worry, I don't think this change can be considered
>> "legally significant", because the changes are small except for some
>> whitespace changes and typo fixes.
>>
>> So I'll push this to the git repo - thanks for fixing it!


Thank you for your reminder!


> Hmm, when I test this with mingw-w64 under Wine, I get:
>
> /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc
> 01ec:fixme:nls:RtlSetThreadPreferredUILanguages 8, 00000001400A8122,
> 000000000021FE8C
> /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc:127:
> void test03(): Assertion 'msg == "Access is denied"'
> failed.
> FAIL: /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc
>
> Inspecting the 'msg' string, the content is "Access denied", which is
> what we have on trunk today.
>
> Can you confirm whether it should be "Access is denied" (as in your
> patch) or "Access denied"?

I apologize that I haven't tested it on Wine, but the the error message 
I encountered on my Windows 11 Version 10.0.26200 system was "Access is 
denied," which is the same as the one recorded in Microsoft Docs, see 
here: 
https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/Debug/system-error-codes--0-499-.md 
or 
https://winprotocoldoc.z19.web.core.windows.net/MS-ERREF/%5bMS-ERREF%5d.pdf 
This is probably because Wine is implemented differently than Microsoft 
Windows. :(

Perhaps we also need to add checks for the Wine environment, like those 
found at 
https://web.archive.org/web/20131028024505/https://www.winehq.org/pipermail/wine-devel/2008-September/069387.html
  
Jonathan Wakely Jan. 10, 2026, 1:37 p.m. UTC | #5
On Sat, 10 Jan 2026 at 13:28, Wang Jinghao <zheng.xianyuwang@gmail.com> wrote:
>
>
> On 2026/1/10 20:50, Jonathan Wakely wrote:
> > On Sat, 10 Jan 2026 at 12:24, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> >> On Sat, 10 Jan 2026 at 12:17, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> >>> 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?
>
>
> Sorry, I made a mistake. The correction for the __MINGW32__ macro
>
> is in error_category/system_category.cc.
>
>
> >>>>          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 ?
> >> Actually, don't worry, I don't think this change can be considered
> >> "legally significant", because the changes are small except for some
> >> whitespace changes and typo fixes.
> >>
> >> So I'll push this to the git repo - thanks for fixing it!
>
>
> Thank you for your reminder!
>
>
> > Hmm, when I test this with mingw-w64 under Wine, I get:
> >
> > /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc
> > 01ec:fixme:nls:RtlSetThreadPreferredUILanguages 8, 00000001400A8122,
> > 000000000021FE8C
> > /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc:127:
> > void test03(): Assertion 'msg == "Access is denied"'
> > failed.
> > FAIL: /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc
> >
> > Inspecting the 'msg' string, the content is "Access denied", which is
> > what we have on trunk today.
> >
> > Can you confirm whether it should be "Access is denied" (as in your
> > patch) or "Access denied"?
>
> I apologize that I haven't tested it on Wine, but the the error message
> I encountered on my Windows 11 Version 10.0.26200 system was "Access is
> denied," which is the same as the one recorded in Microsoft Docs, see
> here:
> https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/Debug/system-error-codes--0-499-.md
> or
> https://winprotocoldoc.z19.web.core.windows.net/MS-ERREF/%5bMS-ERREF%5d.pdf
> This is probably because Wine is implemented differently than Microsoft
> Windows. :(

Thanks for checking. Somebody else has also confirmed that the strings
are different for Windows and Wine.

>
> Perhaps we also need to add checks for the Wine environment, like those
> found at
> https://web.archive.org/web/20131028024505/https://www.winehq.org/pipermail/wine-devel/2008-September/069387.html

Hmm, we could do. I think it's easier to just check that the string
starts with "Access " and ends with " denied", which will match both
strings. I'll change that.
  
Jonathan Wakely Jan. 10, 2026, 1:54 p.m. UTC | #6
On Sat, 10 Jan 2026 at 13:37, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
>
> On Sat, 10 Jan 2026 at 13:28, Wang Jinghao <zheng.xianyuwang@gmail.com> wrote:
> >
> >
> > On 2026/1/10 20:50, Jonathan Wakely wrote:
> > > On Sat, 10 Jan 2026 at 12:24, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> > >> On Sat, 10 Jan 2026 at 12:17, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> > >>> 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?
> >
> >
> > Sorry, I made a mistake. The correction for the __MINGW32__ macro
> >
> > is in error_category/system_category.cc.
> >
> >
> > >>>>          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 ?
> > >> Actually, don't worry, I don't think this change can be considered
> > >> "legally significant", because the changes are small except for some
> > >> whitespace changes and typo fixes.
> > >>
> > >> So I'll push this to the git repo - thanks for fixing it!
> >
> >
> > Thank you for your reminder!
> >
> >
> > > Hmm, when I test this with mingw-w64 under Wine, I get:
> > >
> > > /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc
> > > 01ec:fixme:nls:RtlSetThreadPreferredUILanguages 8, 00000001400A8122,
> > > 000000000021FE8C
> > > /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc:127:
> > > void test03(): Assertion 'msg == "Access is denied"'
> > > failed.
> > > FAIL: /home/jwakely/src/gcc/gcc/libstdc++-v3/testsuite/19_diagnostics/error_category/system_category.cc
> > >
> > > Inspecting the 'msg' string, the content is "Access denied", which is
> > > what we have on trunk today.
> > >
> > > Can you confirm whether it should be "Access is denied" (as in your
> > > patch) or "Access denied"?
> >
> > I apologize that I haven't tested it on Wine, but the the error message
> > I encountered on my Windows 11 Version 10.0.26200 system was "Access is
> > denied," which is the same as the one recorded in Microsoft Docs, see
> > here:
> > https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/Debug/system-error-codes--0-499-.md
> > or
> > https://winprotocoldoc.z19.web.core.windows.net/MS-ERREF/%5bMS-ERREF%5d.pdf
> > This is probably because Wine is implemented differently than Microsoft
> > Windows. :(
>
> Thanks for checking. Somebody else has also confirmed that the strings
> are different for Windows and Wine.
>
> >
> > Perhaps we also need to add checks for the Wine environment, like those
> > found at
> > https://web.archive.org/web/20131028024505/https://www.winehq.org/pipermail/wine-devel/2008-September/069387.html
>
> Hmm, we could do. I think it's easier to just check that the string
> starts with "Access " and ends with " denied", which will match both
> strings. I'll change that.

I've pushed your patch to trunk now, and will backport it to the
release branches at a later date.

Thanks again for the fix.
  
Jonathan Wakely Jan. 23, 2026, 11:25 a.m. UTC | #7
On Sat, 10 Jan 2026 at 13:54, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
>
> On Sat, 10 Jan 2026 at 13:37, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:
> I've pushed your patch to trunk now, and will backport it to the
> release branches at a later date.

It has now been pushed to the gcc-14 and gcc-15 branches.

>
> Thanks again for the fix.
  

Patch

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 );