Fix infinite loop when processing rpath tokens.
authorNick Clifton <nickc@redhat.com>
Mon, 7 Nov 2016 15:05:34 +0000 (15:05 +0000)
committerNick Clifton <nickc@redhat.com>
Mon, 7 Nov 2016 15:05:34 +0000 (15:05 +0000)
PR ld/20784
* emultempl/elf32.em (search_needed): Fix infinite loop when
unable to process a token.  Add support for curly braced enclosed
tokens.
* ld.texinfo (--rpath-link): Document supprot for $ORIGIN and
$LIB.

ld/ChangeLog
ld/emultempl/elf32.em
ld/ld.texinfo

index ae6d7320521b1bc5f218b585a5fa078d365e856e..9d04123a2f1d353ec2bfaf8ade1ab854700a527f 100644 (file)
@@ -1,3 +1,12 @@
+2016-11-07  Nick Clifton  <nickc@redhat.com>
+
+       PR ld/20784
+       * emultempl/elf32.em (search_needed): Fix infinite loop when
+       unable to process a token.  Add support for curly braced enclosed
+       tokens.
+       * ld.texinfo (--rpath-link): Document supprot for $ORIGIN and
+       $LIB.
+
 2016-11-07  Nick Clifton  <nickc@redhat.com>
 
        * ld.texinfo (--compress-debug-sections): Expand documentation of
index 57252da13574975fa449b69f0277f3d717ece4b2..8c6363808ee4e793742fdaf9148a67e63787bcd9 100644 (file)
@@ -495,6 +495,7 @@ gld${EMULATION_NAME}_search_needed (const char *path,
   len = strlen (name);
   while (1)
     {
+      unsigned offset = 0;
       char * var;
       char *filename, *sset;
 
@@ -527,8 +528,10 @@ gld${EMULATION_NAME}_search_needed (const char *path,
       /* PR 20535: Support the same pseudo-environment variables that
         are supported by ld.so.  Namely, $ORIGIN, $LIB and $PLATFORM.
          Since there can be more than one occurrence of these tokens in
-        the path we loop until no more are found.  */
-      while ((var = strchr (filename, '$')) != NULL)
+        the path we loop until no more are found.  Since we might not
+        be able to substitute some of the tokens we maintain an offset
+        into the filename for where we should begin our scan.  */
+      while ((var = strchr (filename + offset, '$')) != NULL)
        {
          /* The ld.so manual page does not say, but I am going to assume that
             these tokens are terminated by a directory seperator character
@@ -536,13 +539,14 @@ gld${EMULATION_NAME}_search_needed (const char *path,
             $ORIGIN should only be used at the start of a path, but that is
             not enforced here.
 
-            FIXME: The ld.so manual page also states that it allows ${ORIGIN}
-            ${LIB} and ${PLATFORM}.  We should support these variants too.
+            The ld.so manual page also states that it allows ${ORIGIN},
+            ${LIB} and ${PLATFORM}, so these are supported as well.
 
             FIXME: The code could be a lot cleverer about allocating space
             for the processed string.  */
          char *    end = strchr (var, '/');
          char *    replacement = NULL;
+         char *    v = var + 1;
          char *    freeme = NULL;
          unsigned  flen = strlen (filename);
 
@@ -550,16 +554,27 @@ gld${EMULATION_NAME}_search_needed (const char *path,
            /* Temporarily terminate the filename at the end of the token.  */
            * end = 0;
 
-         switch (var[1])
+         if (*v == '{')
+           ++ v;
+         switch (*v++)
            {
            case 'O':
-             if (strcmp (var + 2, "RIGIN") == 0)
+             if (strcmp (v, "RIGIN") == 0 || strcmp (v, "RIGIN}") == 0)
                {
                  /* ORIGIN - replace with the full path to the directory
                     containing the program or shared object.  */
                  if (needed.by == NULL)
-                   break;
-                 replacement = bfd_get_filename (needed.by);
+                   {
+                     if (link_info.output_bfd == NULL)
+                       {
+                         break;
+                       }
+                     else
+                       replacement = bfd_get_filename (link_info.output_bfd);
+                   }
+                 else
+                   replacement = bfd_get_filename (needed.by);
+
                  if (replacement)
                    {
                      char * slash;
@@ -582,7 +597,7 @@ gld${EMULATION_NAME}_search_needed (const char *path,
              break;
 
            case 'L':
-             if (strcmp (var + 2, "IB") == 0)
+             if (strcmp (v, "IB") == 0 || strcmp (v, "IB}") == 0)
                {
                  /* LIB - replace with "lib" in 32-bit environments
                     and "lib64" in 64-bit environments.  */
@@ -603,17 +618,12 @@ gld${EMULATION_NAME}_search_needed (const char *path,
              break;
 
            case 'P':
-             if (strcmp (var + 2, "LATFORM") == 0)
-               {
-                 /* Supporting $PLATFORM in a cross-hosted environment is not
-                    possible.  Supporting it in a native environment involves
-                    loading the <sys/auxv.h> header file which loads the
-                    system <elf.h> header file, which conflicts with the
-                    "include/elf/mips.h" header file.  */
-                 replacement = NULL;
-               }
-             break;
-
+             /* Supporting $PLATFORM in a cross-hosted environment is not
+                possible.  Supporting it in a native environment involves
+                loading the <sys/auxv.h> header file which loads the
+                system <elf.h> header file, which conflicts with the
+                "include/elf/mips.h" header file.  */
+             /* Fall through.  */
            default:
              break;
            }
@@ -623,14 +633,20 @@ gld${EMULATION_NAME}_search_needed (const char *path,
              char * filename2 = xmalloc (flen + strlen (replacement));
 
              if (end)
-               sprintf (filename2, "%.*s%s/%s",
-                        (int)(var - filename), filename,
-                        replacement, end + 1);
+               {
+                 sprintf (filename2, "%.*s%s/%s",
+                          (int)(var - filename), filename,
+                          replacement, end + 1);
+                 offset = (var - filename) + 1 + strlen (replacement);
+               }
              else
-               sprintf (filename2, "%.*s%s",
-                        (int)(var - filename), filename,
-                        replacement);
-               
+               {
+                 sprintf (filename2, "%.*s%s",
+                          (int)(var - filename), filename,
+                          replacement);
+                 offset = var - filename + strlen (replacement);
+               }
+
              free (filename);
              filename = filename2;
              /* There is no need to restore the path separator (when
@@ -647,12 +663,17 @@ gld${EMULATION_NAME}_search_needed (const char *path,
              if (end)
                /* Restore the path separator.  */
                * end = '/';
+
+             /* PR 20784: Make sure that we resume the scan
+                *after* the token that we could not replace.  */
+             offset = (var + 1) - filename;
            }
 
          free (freeme);
        }
 
       needed.name = filename;
+
       if (gld${EMULATION_NAME}_try_needed (&needed, force))
        return TRUE;
 
index 698d3664fef7a8f66765f5be2d860d57d219f273..d4f33b7c92880af70a741352594b96be2e15fb10 100644 (file)
@@ -1865,6 +1865,16 @@ specifies the first set of directories to search.  The
 either by specifying a list of names separated by colons, or by
 appearing multiple times.
 
+The tokens @var{$ORIGIN} and @var{$LIB} can appear in these search
+directories.  They will be replaced by the full path to the directory
+containing the program or shared object in the case of @var{$ORIGIN}
+and either @samp{lib} - for 32-bit binaries - or @samp{lib64} - for
+64-bit binaries - in the case of @var{$LIB}.
+
+The alternative form of these tokens - @var{$@{ORIGIN@}} and
+@var{$@{LIB@}} can also be used.  The token @var{$PLATFORM} is not
+supported.
+
 This option should be used with caution as it overrides the search path
 that may have been hard compiled into a shared library. In such a case it
 is possible to use unintentionally a different search path than the