ld: pe: Make archive member file extension comparisons case insensitive when cross...
authorMartin Storsjö <martin@martin.st>
Mon, 27 Sep 2021 08:20:24 +0000 (11:20 +0300)
committerMartin Storsjö <martin@martin.st>
Wed, 24 Aug 2022 20:18:47 +0000 (23:18 +0300)
On Windows, filename_cmp is case insensitive, but when cross compiling
with libraries that may contain members with uppercase file names, we
should keep those comparisons case insensitive when running the build
tools on other OSes too.

Also make the check for .def consistent with the other ones, fixing
out of bounds reads if file names are shorter than 4 characters.

ld/emultempl/pe.em
ld/emultempl/pep.em

index ad969ccec131f0f29cf54eaf821322880fe71f93..2706d73d14450b559d62f2777aefc48c1531917f 100644 (file)
@@ -534,6 +534,23 @@ gld${EMULATION_NAME}_list_options (FILE *file)
   fprintf (file, _("  --build-id[=STYLE]                 Generate build ID\n"));
 }
 
+/* A case insensitive comparison, regardless of the host platform, used for
+   comparing file extensions.  */
+static int
+fileext_cmp (const char *s1, const char *s2)
+{
+  for (;;)
+    {
+      int c1 = TOLOWER (*s1++);
+      int c2 = *s2++; /* Assumed to be lower case from the caller.  */
+
+      if (c1 != c2)
+        return (c1 - c2);
+
+      if (c1 == '\0')
+        return 0;
+    }
+}
 
 static void
 set_pe_name (char *name, long val)
@@ -1666,7 +1683,7 @@ gld${EMULATION_NAME}_after_open (void)
                       extension, and use that for the remainder of the
                       comparisons.  */
                    pnt = strrchr (bfd_get_filename (is3->the_bfd), '.');
-                   if (pnt != NULL && filename_cmp (pnt, ".dll") == 0)
+                   if (pnt != NULL && fileext_cmp (pnt + 1, "dll") == 0)
                      break;
                  }
 
@@ -1683,7 +1700,7 @@ gld${EMULATION_NAME}_after_open (void)
                        /* Skip static members, ie anything with a .obj
                           extension.  */
                        pnt = strrchr (bfd_get_filename (is2->the_bfd), '.');
-                       if (pnt != NULL && filename_cmp (pnt, ".obj") == 0)
+                       if (pnt != NULL && fileext_cmp (pnt + 1, "obj") == 0)
                          continue;
 
                        if (filename_cmp (bfd_get_filename (is3->the_bfd),
@@ -1701,7 +1718,7 @@ gld${EMULATION_NAME}_after_open (void)
               then leave the filename alone.  */
            pnt = strrchr (bfd_get_filename (is->the_bfd), '.');
 
-           if (is_ms_arch && (filename_cmp (pnt, ".dll") == 0))
+           if (is_ms_arch && pnt != NULL && (fileext_cmp (pnt + 1, "dll") == 0))
              {
                int idata2 = 0, reloc_count=0;
                asection *sec;
@@ -1855,9 +1872,9 @@ static bool
 gld${EMULATION_NAME}_unrecognized_file (lang_input_statement_type *entry ATTRIBUTE_UNUSED)
 {
 #ifdef DLL_SUPPORT
-  const char *ext = entry->filename + strlen (entry->filename) - 4;
+  const char *ext = strrchr (entry->filename, '.');
 
-  if (filename_cmp (ext, ".def") == 0 || filename_cmp (ext, ".DEF") == 0)
+  if (ext != NULL && fileext_cmp (ext + 1, "def") == 0)
     {
       pe_def_file = def_file_parse (entry->filename, pe_def_file);
 
index ee36a9a7e564fdcc117bd2d599927382906c1446..accefc0ed606efdfac8368561a46940b6f9b8d88 100644 (file)
@@ -181,6 +181,23 @@ static int is_underscoring (void)
   return pep_leading_underscore;
 }
 
+/* A case insensitive comparison, regardless of the host platform, used for
+   comparing file extensions.  */
+static int
+fileext_cmp (const char *s1, const char *s2)
+{
+  for (;;)
+    {
+      int c1 = TOLOWER (*s1++);
+      int c2 = *s2++; /* Assumed to be lower case from the caller.  */
+
+      if (c1 != c2)
+        return (c1 - c2);
+
+      if (c1 == '\0')
+        return 0;
+    }
+}
 
 static void
 gld${EMULATION_NAME}_before_parse (void)
@@ -1630,7 +1647,7 @@ gld${EMULATION_NAME}_after_open (void)
                       extension, and use that for the remainder of the
                       comparisons.  */
                    pnt = strrchr (bfd_get_filename (is3->the_bfd), '.');
-                   if (pnt != NULL && filename_cmp (pnt, ".dll") == 0)
+                   if (pnt != NULL && fileext_cmp (pnt + 1, "dll") == 0)
                      break;
                  }
 
@@ -1647,7 +1664,7 @@ gld${EMULATION_NAME}_after_open (void)
                        /* Skip static members, ie anything with a .obj
                           extension.  */
                        pnt = strrchr (bfd_get_filename (is2->the_bfd), '.');
-                       if (pnt != NULL && filename_cmp (pnt, ".obj") == 0)
+                       if (pnt != NULL && fileext_cmp (pnt + 1, "obj") == 0)
                          continue;
 
                        if (filename_cmp (bfd_get_filename (is3->the_bfd),
@@ -1665,7 +1682,7 @@ gld${EMULATION_NAME}_after_open (void)
               then leave the filename alone.  */
            pnt = strrchr (bfd_get_filename (is->the_bfd), '.');
 
-           if (is_ms_arch && (filename_cmp (pnt, ".dll") == 0))
+           if (is_ms_arch && pnt != NULL && (fileext_cmp (pnt + 1, "dll") == 0))
              {
                int idata2 = 0, reloc_count=0;
                asection *sec;
@@ -1725,9 +1742,9 @@ static bool
 gld${EMULATION_NAME}_unrecognized_file (lang_input_statement_type *entry ATTRIBUTE_UNUSED)
 {
 #ifdef DLL_SUPPORT
-  const char *ext = entry->filename + strlen (entry->filename) - 4;
+  const char *ext = strrchr (entry->filename, '.');
 
-  if (filename_cmp (ext, ".def") == 0 || filename_cmp (ext, ".DEF") == 0)
+  if (ext != NULL && fileext_cmp (ext + 1, "def") == 0)
     {
       pep_def_file = def_file_parse (entry->filename, pep_def_file);