[2/4] ld: Refactor input_statement_is_archive_path() to not touch its argument

Message ID 91ef07eb095ae29ba9bc320ca057769231202eae.1777074100.git.calvin@wbinvd.org
State New
Headers
Series Fix build errors due to qualifier preserving strchr() |

Commit Message

Calvin Owens April 25, 2026, 2:19 a.m. UTC
  This is prep work for the next patch, no functional change intended.

Signed-off-by: Calvin Owens <calvin@wbinvd.org>
---
 ld/ldlang.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)
  

Comments

Alan Modra May 2, 2026, 8:06 a.m. UTC | #1
On Fri, Apr 24, 2026 at 07:19:45PM -0700, Calvin Owens wrote:
> +	  char *tmp = stat_strdup (file_spec);
> +
> +	  tmp[sep - file_spec] = 0;
> +	  match = name_match (tmp, aname) == 0;
> +	  stat_free (tmp);

Let's not make an unnecessary copy.  I'm going to apply the following.
----

Assign strchr return to a const char* to match its arg in a couple of
places.  archive_path now returns a const char*, and
input_statement_is_archive_path now has a const char* sep arg.  If
you follow where these args come from in ldgram.y it can be seen that
they are in fact in writable memory, so it isn't necessary to copy
file_spec to poke in a zero which is restored before the function
returns.

Signed-off-by: Calvin Owens <calvin@wbinvd.org>
Signed-off-by: Alan Modra <amodra@gmail.com>

diff --git a/ld/ldlang.c b/ld/ldlang.c
index dec3d586671..48dd33a49bb 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -337,10 +337,10 @@ stat_ldirname (const char *name)
 /* If PATTERN is of the form archive:file, return a pointer to the
    separator.  If not, return NULL.  */
 
-static char *
+static const char *
 archive_path (const char *pattern)
 {
-  char *p = NULL;
+  const char *p = NULL;
 
   if (link_info.path_separator == 0)
     return p;
@@ -362,7 +362,7 @@ archive_path (const char *pattern)
    return whether F matches FILE_SPEC.  */
 
 static bool
-input_statement_is_archive_path (const char *file_spec, char *sep,
+input_statement_is_archive_path (const char *file_spec, const char *sep,
 				 lang_input_statement_type *f)
 {
   bool match = false;
@@ -377,9 +377,10 @@ input_statement_is_archive_path (const char *file_spec, char *sep,
       if (sep != file_spec)
 	{
 	  const char *aname = bfd_get_filename (f->the_bfd->my_archive);
-	  *sep = 0;
+	  /* SEP which points into FILE_SPEC is in writable memory.  */
+	  *(char *) sep = 0;
 	  match = name_match (file_spec, aname) == 0;
-	  *sep = link_info.path_separator;
+	  *(char *) sep = link_info.path_separator;
 	}
     }
   return match;
@@ -421,7 +422,7 @@ walk_wild_file_in_exclude_list (struct name_list *exclude_list,
        list_tmp;
        list_tmp = list_tmp->next)
     {
-      char *p = archive_path (list_tmp->name);
+      const char *p = archive_path (list_tmp->name);
 
       if (p != NULL)
 	{
@@ -477,7 +478,7 @@ walk_wild_section_match (lang_wild_statement_type *ptr,
 {
   struct wildcard_list *sec;
   const char *file_spec = ptr->filename;
-  char *p;
+  const char *p;
 
   /* Check if filenames match.  */
   if (file_spec == NULL)
@@ -10946,7 +10947,7 @@ cmdline_fopen_temp (const char *path, const char *target,
 #ifdef HAVE_DOS_BASED_FILE_SYSTEM
   {
     /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
-    char *bslash = strrchr (path, '\\');
+    const char *bslash = strrchr (path, '\\');
 
     if (slash == NULL || (bslash != NULL && bslash > slash))
       slash = bslash;
  
Calvin Owens May 2, 2026, 9:58 a.m. UTC | #2
On Saturday 05/02 at 17:36 +0930, Alan Modra wrote:
> On Fri, Apr 24, 2026 at 07:19:45PM -0700, Calvin Owens wrote:
> > +	  char *tmp = stat_strdup (file_spec);
> > +
> > +	  tmp[sep - file_spec] = 0;
> > +	  match = name_match (tmp, aname) == 0;
> > +	  stat_free (tmp);
> 
> Let's not make an unnecessary copy.  I'm going to apply the following.
> ----
> 
> Assign strchr return to a const char* to match its arg in a couple of
> places.  archive_path now returns a const char*, and
> input_statement_is_archive_path now has a const char* sep arg.  If
> you follow where these args come from in ldgram.y it can be seen that
> they are in fact in writable memory, so it isn't necessary to copy
> file_spec to poke in a zero which is restored before the function
> returns.
> 
> Signed-off-by: Calvin Owens <calvin@wbinvd.org>

I've had a busy week, apologies I didn't get a chance to refresh this.

It's very generous of you to credit me, but not necessary :)

Cheers,
Calvin

> Signed-off-by: Alan Modra <amodra@gmail.com>
>
> diff --git a/ld/ldlang.c b/ld/ldlang.c
> index dec3d586671..48dd33a49bb 100644
> --- a/ld/ldlang.c
> +++ b/ld/ldlang.c
> @@ -337,10 +337,10 @@ stat_ldirname (const char *name)
>  /* If PATTERN is of the form archive:file, return a pointer to the
>     separator.  If not, return NULL.  */
>  
> -static char *
> +static const char *
>  archive_path (const char *pattern)
>  {
> -  char *p = NULL;
> +  const char *p = NULL;
>  
>    if (link_info.path_separator == 0)
>      return p;
> @@ -362,7 +362,7 @@ archive_path (const char *pattern)
>     return whether F matches FILE_SPEC.  */
>  
>  static bool
> -input_statement_is_archive_path (const char *file_spec, char *sep,
> +input_statement_is_archive_path (const char *file_spec, const char *sep,
>  				 lang_input_statement_type *f)
>  {
>    bool match = false;
> @@ -377,9 +377,10 @@ input_statement_is_archive_path (const char *file_spec, char *sep,
>        if (sep != file_spec)
>  	{
>  	  const char *aname = bfd_get_filename (f->the_bfd->my_archive);
> -	  *sep = 0;
> +	  /* SEP which points into FILE_SPEC is in writable memory.  */
> +	  *(char *) sep = 0;
>  	  match = name_match (file_spec, aname) == 0;
> -	  *sep = link_info.path_separator;
> +	  *(char *) sep = link_info.path_separator;
>  	}
>      }
>    return match;
> @@ -421,7 +422,7 @@ walk_wild_file_in_exclude_list (struct name_list *exclude_list,
>         list_tmp;
>         list_tmp = list_tmp->next)
>      {
> -      char *p = archive_path (list_tmp->name);
> +      const char *p = archive_path (list_tmp->name);
>  
>        if (p != NULL)
>  	{
> @@ -477,7 +478,7 @@ walk_wild_section_match (lang_wild_statement_type *ptr,
>  {
>    struct wildcard_list *sec;
>    const char *file_spec = ptr->filename;
> -  char *p;
> +  const char *p;
>  
>    /* Check if filenames match.  */
>    if (file_spec == NULL)
> @@ -10946,7 +10947,7 @@ cmdline_fopen_temp (const char *path, const char *target,
>  #ifdef HAVE_DOS_BASED_FILE_SYSTEM
>    {
>      /* We could have foo/bar\\baz, or foo\\bar, or d:bar.  */
> -    char *bslash = strrchr (path, '\\');
> +    const char *bslash = strrchr (path, '\\');
>  
>      if (slash == NULL || (bslash != NULL && bslash > slash))
>        slash = bslash;
> 
> -- 
> Alan Modra
  

Patch

diff --git a/ld/ldlang.c b/ld/ldlang.c
index d75f9df4d43..b52ca2c4b03 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -362,7 +362,7 @@  archive_path (const char *pattern)
    return whether F matches FILE_SPEC.  */
 
 static bool
-input_statement_is_archive_path (const char *file_spec, char *sep,
+input_statement_is_archive_path (const char *file_spec, const char *sep,
 				 lang_input_statement_type *f)
 {
   bool match = false;
@@ -377,9 +377,11 @@  input_statement_is_archive_path (const char *file_spec, char *sep,
       if (sep != file_spec)
 	{
 	  const char *aname = bfd_get_filename (f->the_bfd->my_archive);
-	  *sep = 0;
-	  match = name_match (file_spec, aname) == 0;
-	  *sep = link_info.path_separator;
+	  char *tmp = stat_strdup (file_spec);
+
+	  tmp[sep - file_spec] = 0;
+	  match = name_match (tmp, aname) == 0;
+	  stat_free (tmp);
 	}
     }
   return match;