[PATCH] bfd: fix filename encoding for Win32

ZENG Hao c@cyano.cn
Mon Mar 2 06:12:37 GMT 2026


MSVCRT's ___lc_codepage_func() returns "default ACP for Windows display
language". i.e. 1252 for English, no matter how "Language for non-Unicode
programs" (system code page) is set, or whether the application manifest sets
activeCodePage to UTF-8. Thus non-ASCII path would get corrupted if user's
Windows display language does not match system code page, or downstream adds
UTF-8 manifest.

In our use case, the filename is encoded in CP_ACP.

There are some conner cases that are impossible to handle on our side (read
from file, console, pipe, socket, etc.). It is possible for downstream
distributor to ensure all tools are consistently encoded, by removing UTF-8
manifest from GCC, or adding it to all tools.
---

Note: here are some detailed comparation of MSVCRT and UCRT
___lc_codepage_func(): https://github.com/niXman/mingw-builds/issues/649

 bfd/bfdio.c      | 19 ++++++++++++++-----
 bfd/config.in    |  4 ----
 bfd/configure    | 12 ------------
 bfd/configure.ac |  1 -
 4 files changed, 14 insertions(+), 22 deletions(-)

diff --git a/bfd/bfdio.c b/bfd/bfdio.c
index ea0d1389cd1..2d8d1d90989 100644
--- a/bfd/bfdio.c
+++ b/bfd/bfdio.c
@@ -189,11 +189,20 @@ _bfd_real_fopen (const char *filename, const char *modes)
     }
 
 #ifdef __MINGW32__
-#if !HAVE_DECL____LC_CODEPAGE_FUNC
-  /* This prototype was added to locale.h in version 9.0 of MinGW-w64.  */
-  _CRTIMP unsigned int __cdecl ___lc_codepage_func (void);
-#endif
-  const unsigned int cp = ___lc_codepage_func ();
+  /* The filename is retrieved from argv, Win32 API, CRT function, or files
+     (incl. console, pipe, socket, etc.).
+     1) argv is always encoded in ACP.
+     2) Win32 file APIs uses ACP or OEMCP, depending on return value of
+        AreFileApisANSI().
+     3) UCRT filesystem functions internally converts strings from/to wchar_t
+        and call wide variants. It uses CP_UTF8 (if C locale set to ".utf8"),
+        CP_ACP or CP_OEMCP (depending on AreFileApisANSI()).
+     4) MSVCRT filesystem functions simply pass strings to Win32 file APIs.
+     5) file can be encoded in any encoding, depending on the writer.
+
+     Ignoring case 5, which is impossible to handle, CP_ACP is the only choice
+     (and don't call SetFileApisToOEM() or setlocale(".utf8")). */
+  const unsigned int cp = CP_ACP;
 #else
   const unsigned int cp = CP_UTF8;
 #endif
diff --git a/bfd/config.in b/bfd/config.in
index b3bd7cac45b..9666feb8e31 100644
--- a/bfd/config.in
+++ b/bfd/config.in
@@ -83,10 +83,6 @@
    don't. */
 #undef HAVE_DECL_VASPRINTF
 
-/* Define to 1 if you have the declaration of `___lc_codepage_func', and to 0
-   if you don't. */
-#undef HAVE_DECL____LC_CODEPAGE_FUNC
-
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #undef HAVE_DLFCN_H
 
diff --git a/bfd/configure b/bfd/configure
index 49d16fd4410..20bfd926989 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -15202,18 +15202,6 @@ cat >>confdefs.h <<_ACEOF
 #define HAVE_DECL_STRTOULL $ac_have_decl
 _ACEOF
 
-ac_fn_c_check_decl "$LINENO" "___lc_codepage_func" "ac_cv_have_decl____lc_codepage_func" "#include <locale.h>
-"
-if test "x$ac_cv_have_decl____lc_codepage_func" = xyes; then :
-  ac_have_decl=1
-else
-  ac_have_decl=0
-fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL____LC_CODEPAGE_FUNC $ac_have_decl
-_ACEOF
-
 
 
 case "${host}" in
diff --git a/bfd/configure.ac b/bfd/configure.ac
index f86c9eae754..e102bdae910 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -223,7 +223,6 @@ AC_CHECK_FUNCS(fcntl fdopen fileno fls getgid getpagesize getrlimit getuid \
 	       sysconf)
 
 AC_CHECK_DECLS([basename, ffs, stpcpy, asprintf, vasprintf, strnlen, strtoull])
-AC_CHECK_DECLS([___lc_codepage_func], [], [], [[#include <locale.h>]])
 
 BFD_BINARY_FOPEN
 
-- 
2.53.0



More information about the Binutils mailing list