PR 32507, PRIx64 in error messages on 32-bit mingw

Message ID Z3U0ywUjUDf7-0et@squeak.grove.modra.org
State New
Headers
Series PR 32507, PRIx64 in error messages on 32-bit mingw |

Commit Message

Alan Modra Jan. 1, 2025, 12:27 p.m. UTC
  People, including me, had forgotten that the bfd_error_handler just
handled standard printf format strings, not MSC %I64 and suchlike.
Using PRIx64 and similar in errors does not work if the host compiler
headers define those formats as the Microsoft %I64 variety.  (We
handled %ll OK, editing it to %I64 on such hosts.)

	PR 32507
	* bfd.c (_bfd_doprnt, _bfd_doprnt_scan): Handle %I64 and %I32
	in input strings if the host defines PRId64 as "I64d".
	Edit %ll to %I64 on detecting PRId64 as "I64d" rather than on
	a preprocessor define.
  

Patch

diff --git a/bfd/bfd.c b/bfd/bfd.c
index a0dd215e271..0e567ddeaea 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -1090,8 +1090,14 @@  _bfd_doprnt (bfd_print_callback print, void *stream, const char *format,
 	      ptr += 2;
 	    }
 
+	  /* There is a clash between Microsoft's non-standard I64
+	     and I32 integer length modifiers and glibc's
+	     non-standard I flag.  */
+	  const char *printf_flag_chars
+	    = sizeof PRId64 == sizeof "I64d" ? "-+ #0'" : "-+ #0'I";
+
 	  /* Move past flags.  */
-	  while (strchr ("-+ #0'I", *ptr))
+	  while (strchr (printf_flag_chars, *ptr))
 	    *sptr++ = *ptr++;
 
 	  if (*ptr == '*')
@@ -1141,6 +1147,22 @@  _bfd_doprnt (bfd_print_callback print, void *stream, const char *format,
 		while (ISDIGIT (*ptr))
 		  *sptr++ = *ptr++;
 	    }
+	  if (sizeof PRId64 == sizeof "I64d" && *ptr =='I')
+	    {
+	      if (ptr[1] == '6' && ptr[2] == '4')
+		{
+		  wide_width = 3;
+		  *sptr++ = *ptr++;
+		  *sptr++ = *ptr++;
+		  *sptr++ = *ptr++;
+		}
+	      else if (ptr[1] == '3' && ptr[2] == '2')
+		{
+		  *sptr++ = *ptr++;
+		  *sptr++ = *ptr++;
+		  *sptr++ = *ptr++;
+		}
+	    }
 	  while (strchr ("hlL", *ptr))
 	    {
 	      switch (*ptr)
@@ -1192,14 +1214,17 @@  _bfd_doprnt (bfd_print_callback print, void *stream, const char *format,
 			PRINT_TYPE (long, l);
 			break;
 		      case 2:
+			if (sizeof PRId64 == sizeof "I64d")
+			  {
+			    /* Convert any %ll to %I64.  */
+			    sptr[-3] = 'I';
+			    sptr[-2] = '6';
+			    sptr[-1] = '4';
+			    *sptr++ = ptr[-1];
+			    *sptr = '\0';
+			  }
+			/* Fall through.  */
 		      default:
-#if defined (__MSVCRT__)
-			sptr[-3] = 'I';
-			sptr[-2] = '6';
-			sptr[-1] = '4';
-			*sptr++ = ptr[-1];
-			*sptr = '\0';
-#endif
 			PRINT_TYPE (long long, ll);
 			break;
 		      }
@@ -1322,8 +1347,14 @@  _bfd_doprnt_scan (const char *format, va_list ap, union _bfd_doprnt_args *args)
 	      ptr += 2;
 	    }
 
+	  /* There is a clash between Microsoft's non-standard I64
+	     and I32 integer length modifiers and glibc's
+	     non-standard I flag.  */
+	  const char *printf_flag_chars
+	    = sizeof PRId64 == sizeof "I64d" ? "-+ #0'" : "-+ #0'I";
+
 	  /* Move past flags.  */
-	  while (strchr ("-+ #0'I", *ptr))
+	  while (strchr (printf_flag_chars, *ptr))
 	    ptr++;
 
 	  if (*ptr == '*')
@@ -1372,6 +1403,17 @@  _bfd_doprnt_scan (const char *format, va_list ap, union _bfd_doprnt_args *args)
 		while (ISDIGIT (*ptr))
 		  ptr++;
 	    }
+
+	  if (sizeof PRId64 == sizeof "I64d" && *ptr =='I')
+	    {
+	      if (ptr[1] == '6' && ptr[2] == '4')
+		{
+		  wide_width = 3;
+		  ptr += 3;
+		}
+	      else if (ptr[1] == '3' && ptr[2] == '2')
+		ptr += 3;
+	    }
 	  while (strchr ("hlL", *ptr))
 	    {
 	      switch (*ptr)