https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121759
--- Comment #8 from Yohann Vautrin <[email protected]> --- I believe we were experiencing the same bug with gfortran 16.1 and it seems to be a locale-handling bug in libgfortran. It also appears to be related to this MSYS2 issue: https://github.com/msys2/MINGW-packages/issues/29825. The important thing missing to reproduce the bug reported here is that the locale, or at least LC_NUMERIC, should be set to a locale that does not use periods as decimal separators (French for example uses commas). The bug causes values written with a decimal point to be parsed only up to the decimal point. Linux is unaffected because libgfortran uses the thread-safe uselocale() path. Bug report ---------- There appear to be two separate bugs in the locale-handling code in libgfortran/io/transfer.c: 1. Reuse of an invalidated locale pointer For formatted IO, data_transfer_init saves the pointer returned by "setlocale(LC_NUMERIC, NULL)" but does not copy the string referenced by that pointer. It then calls setlocale(LC_NUMERIC, "C"). A subsequent call to setlocale may invalidate the pointer returned by the previous call, which is what happens with the Windows UCRT. The older MSVCRT behavior masked the bug because the "C" locale used at program start was stored in static storage, but there are ways to reproduce the issue with it as well. When libgfortran later tries to restore the original locale in finalize_transfer, it may therefore pass an invalid, corrupted, or empty string to setlocale. This changes LC_NUMERIC for the program from its "C" default value to the locale set in Windows regional settings 2. Locale guard value corruption data_transfer_init increments old_locale_ctr only for formatted IO, but the corresponding code in finalize_transfer is not guarded by the same FORM_FORMATTED condition. The counter is therefore also decremented after unformatted IO. An unformatted operation will therefore change old_locale_ctr from 0 to -1. Subsequent formatted operations no longer enter the locale guard correctly, and the counter remains in an invalid state. This prevents formatted operations from restoring the expected "C" numeric locale, causing the incorrect locale to persist. How to reproduce ---------------- Environment: Windows 11 23H2, amd64 - Install MSYS2 - Open Settings / Time & language / Language & region and set Regional format to, e.g., "French (Canada)" - Start a MSYS2 UCRT64 environment with gfortran installed with pacman (package name is mingw-w64-ucrt-x86_64-gcc-libgfortran, version is 16.1.0-5 currently) - Compile the attached reproducer with gfortran -Wall -Wextra -pedantic reproducer.f90 and run it If the bug is reproduced, the program will output this, followed by a backtrace: Before unformatted I/O: - Expected: 0.10000000000000001 - Parsed : 0.10000000000000001 After unformatted I/O: - Expected: 0.10000000000000001 - Parsed : 0.0000000000000000 ERROR STOP 2 Suggested fix ---------------- I've attached a patch that should fix both issues. It adds the missing guard in finalize_transfer and copies the current locale. I've not been able to test it yet. The fix should probably be backported. I believe it was added in GCC 5 by PR 47007 and 61847.
