Bootstrapped and tested on x86_64-linux-gnu.

Although it bootstrapped and tested successfully on my computer,
gcc/testsuite doesn't seem to have many test units related to the spec.:-(

This patch is not very effective in GNU/Linux environments,
but it is quite useful on Windows-MinGW.

-- >8 --
In end_going_arg(), the driver uses find_file or find_a_file to obtain the
path of the library or link script, and then recursively evaluates the
obtained path in do_spec_1. If there are spaces in the path, the path will
be split into multiple paths. Functions like if_exists_spec_function()
use access() to verify file readability, so dequote_spec() is used to
dequote the string before calling access().

If processing a spec function, we need to escape the path obtained by
find_a_file and then remove the escape within the spec function to prevent
the file path from being incorrectly segmented.

Because quote_spec() requires a pointer of type char *, but find_file()
return a pointer of type const char *, find_a_file() is used instead of
find_file() in end_going_end() while retaining the behavior of
find_file().

        PR driver/90692
---
 gcc/gcc.cc | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 87 insertions(+), 7 deletions(-)

diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index f3e0004cdb8..9e9f05dbf5d 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -465,6 +465,7 @@ static const char *find_fortran_preinclude_file (int, const 
char **);
 static const char *join_spec_func (int, const char **);
 static char *convert_white_space (char *);
 static char *quote_spec (char *);
+static char *dequote_spec (const char *);
 static char *quote_spec_arg (char *);
 static bool not_actual_file_p (const char *);
 
@@ -5782,7 +5783,20 @@ end_going_arg (void)
       obstack_1grow (&obstack, 0);
       string = XOBFINISH (&obstack, const char *);
       if (this_is_library_file)
-       string = find_file (string);
+       {
+         /* File name possible contains spaces, so quote it.
+            If we are not processing spec function,
+            there is not necessary to quote it.  */
+         char * full_lib_path = find_a_file (&startfile_prefixes, string,
+                                             R_OK, true);
+         if (full_lib_path != NULL)
+           {
+             if (processing_spec_function)
+               string = quote_spec (full_lib_path);
+             else
+               string = full_lib_path;
+           }
+       }
       if (this_is_linker_script)
        {
          char * full_script_path = find_a_file (&startfile_prefixes, string, 
R_OK, true);
@@ -5794,7 +5808,11 @@ end_going_arg (void)
              return;
            }
          store_arg ("--script", false, false);
-         string = full_script_path;
+         /* Likewise.  */
+         if (processing_spec_function)
+           string = quote_spec (full_script_path);
+         else
+           string = full_script_path;
        }
       store_arg (string, delete_this_arg, this_is_output_file);
       if (this_is_output_file)
@@ -7004,6 +7022,11 @@ do_spec_1 (const char *spec, int inswitch, const char 
*soft_matched_part)
 
       case '\\':
        /* Backslash: treat next character as ordinary.  */
+
+       /* If it is not the last processing spec function,
+          retain the backslash.  */
+       if (processing_spec_function > 1)
+         obstack_1grow (&obstack, '\\');
        c = *p++;
 
        /* When adding more cases that previously matched default, make
@@ -10523,7 +10546,14 @@ static const char *
 if_exists_spec_function (int argc, const char **argv)
 {
   /* Must have only one argument.  */
-  if (argc == 1 && IS_ABSOLUTE_PATH (argv[0]) && ! access (argv[0], R_OK))
+  if (argc != 1 || !argv[0])
+    return NULL;
+
+  /* access () requires a non-quoted path.  */
+  char *dequote = dequote_spec (argv[0]);
+  bool readable = ! access (dequote, R_OK);
+  free (dequote);
+  if (IS_ABSOLUTE_PATH (argv[0]) && readable)
     return argv[0];
 
   return NULL;
@@ -10538,10 +10568,14 @@ static const char *
 if_exists_else_spec_function (int argc, const char **argv)
 {
   /* Must have exactly two arguments.  */
-  if (argc != 2)
+  if (argc != 2 || !argv[0])
     return NULL;
 
-  if (IS_ABSOLUTE_PATH (argv[0]) && ! access (argv[0], R_OK))
+  /* access () requires a non-quoted path.  */
+  char *dequote = dequote_spec (argv[0]);
+  bool readable = ! access (dequote, R_OK);
+  free (dequote);
+  if (IS_ABSOLUTE_PATH (argv[0]) && readable)
     return argv[0];
 
   return argv[1];
@@ -10558,10 +10592,14 @@ if_exists_then_else_spec_function (int argc, const 
char **argv)
 {
 
   /* Must have two or three arguments.  */
-  if (argc != 2 && argc != 3)
+  if ((argc != 2 && argc != 3) || !argv[0])
     return NULL;
 
-  if (IS_ABSOLUTE_PATH (argv[0]) && ! access (argv[0], R_OK))
+  /* access () requires a non-quoted path.  */
+  char *dequote = dequote_spec (argv[0]);
+  bool readable = ! access (dequote, R_OK);
+  free (dequote);
+  if (IS_ABSOLUTE_PATH (argv[0]) && readable)
     return argv[1];
 
   if (argc == 3)
@@ -11285,6 +11323,39 @@ quote_string (char *orig, bool (*quote_p)(char, void 
*), void *p)
     return orig;
 }
 
+/* Dequote a string which modified by quote_string.  Assume the string was
+   quoted by quote_string with the same QUOTE_P and P.
+   NB: This function would not free the input string!!  */
+
+static inline char *
+dequote_string (const char *quot, bool (*quote_p)(char, void *), void *p)
+{
+  int len, number_of_space = 0;
+
+  for (len = 0; quot[len]; len++)
+    if (quote_p (quot[len + 1], p) && quot[len] == '\\')
+      {
+       number_of_space++;
+       len++;
+      }
+
+  if (number_of_space)
+    {
+      char *new_spec = (char *) xmalloc (len - number_of_space + 1);
+      int j, k;
+      for (j = 0, k = 0; j <= len; j++, k++)
+       {
+         if (quote_p (quot[j + 1], p) && quot[j] == '\\')
+         j++;
+         new_spec[k] = quot[j];
+       }
+
+      return new_spec;
+    }
+  else
+    return xstrdup (quot);
+}
+
 /* Return true iff C is any of the characters convert_white_space
    should quote.  */
 
@@ -11351,6 +11422,15 @@ quote_spec (char *orig)
   return quote_string (orig, quote_spec_char_p, NULL);
 }
 
+/* The inverse operation of quote_spec
+   NB: This function would not free the input string!! */
+
+static inline char *
+dequote_spec (const char *quot)
+{
+  return dequote_string (quot, quote_spec_char_p, NULL);
+}
+
 /* Like quote_spec, but also turn an empty string into the spec for an
    empty argument.  */
 
-- 
2.47.3

Reply via email to