[gimp] libgimpbase: do not assume PATH_MAX to be the actual max size of paths.



commit 47fbfc2f0e9bf8c210e7dc4ecf7a02afbc827c82
Author: Jehan <jehan girinstud io>
Date:   Sat Mar 20 18:40:32 2021 +0100

    libgimpbase: do not assume PATH_MAX to be the actual max size of paths.
    
    Even though it is set by Linux's limits.h and apparently by other OSes
    too, it seems this macro is mostly bogus. On many systems, the actual
    allowed max size of paths is much higher.
    On Hurd, they don't even define the macro as there is no upper limit.
    See MR !424.
    
    This commit replaces two usages of PATH_MAX:
    - readlink() by g_file_read_link(). I checked the GLib implementation
      and could confirm it will do the proper thing, which is progressively
      incrementing their buffer allocation in a loop until the buffer is big
      enough to contain the symbolic link contents. Hence no need to rely on
      a bogus macro which is not the actual max.
    - fgets() by g_data_input_stream_read_line() which also dynamically
      allocates the returned buffer, and also properly removes the newline
      and adds a NUL byte (hence simpler code).
    
    Additionally I loop through the lines of /proc/self/maps until I find
    the first "r-xp" pathname. Indeed the current code was assuming that the
    first line was always right. Yet on my OS at least, the first line was
    GIMP executable with "r--p" permission, hence the test would fail. The
    second line had the right permission. So let's assume that we want the
    first executable path, looping through each line.

 libgimpbase/gimpreloc.c | 166 ++++++++++++++++++++++--------------------------
 1 file changed, 75 insertions(+), 91 deletions(-)
---
diff --git a/libgimpbase/gimpreloc.c b/libgimpbase/gimpreloc.c
index 7ed1783b3c..48f3b5048d 100644
--- a/libgimpbase/gimpreloc.c
+++ b/libgimpbase/gimpreloc.c
@@ -22,6 +22,7 @@
 #include <unistd.h>
 #endif /* ENABLE_RELOCATABLE_RESOURCES && ! G_OS_WIN32 */
 
+#include <gio/gio.h>
 #include <glib.h>
 #include <glib/gstdio.h>
 
@@ -41,139 +42,122 @@ _br_find_exe (GimpBinrelocInitError *error)
     *error = GIMP_RELOC_INIT_ERROR_DISABLED;
   return NULL;
 #else
-  char *path, *path2, *line, *result;
-  size_t buf_size;
-  ssize_t size;
-  struct stat stat_buf;
-  FILE *f;
-
-  /* Read from /proc/self/exe (symlink) */
-  if (sizeof (path) > SSIZE_MAX)
-    buf_size = SSIZE_MAX - 1;
-  else
-    buf_size = PATH_MAX - 1;
-  path = g_try_new (char, buf_size);
-  if (path == NULL)
-    {
-      /* Cannot allocate memory. */
-      if (error)
-        *error = GIMP_RELOC_INIT_ERROR_NOMEM;
-      return NULL;
-    }
-  path2 = g_try_new (char, buf_size);
-  if (path2 == NULL)
-    {
-      /* Cannot allocate memory. */
-      if (error)
-        *error = GIMP_RELOC_INIT_ERROR_NOMEM;
-      g_free (path);
-      return NULL;
-    }
+  GDataInputStream *data_input;
+  GInputStream     *input;
+  GFile            *file;
+  GError           *gerror = NULL;
+  gchar            *path;
+  gchar            *sym_path;
+  gchar            *maps_line;
 
-  g_strlcpy (path2, "/proc/self/exe", buf_size);
+  sym_path = g_strdup ("/proc/self/exe");
 
   while (1)
     {
-      int i;
-
-      size = readlink (path2, path, buf_size - 1);
-      if (size == -1)
+      struct stat stat_buf;
+      int         i;
+
+      /* Do not use readlink() with a buffer of size PATH_MAX because
+       * some systems actually allow paths of bigger size. Thus this
+       * macro is kind of bogus. Some systems like Hurd will not even
+       * define it (see MR !424).
+       * g_file_read_link() on the other hand will return a size of
+       * appropriate size, with newline removed and NUL terminator
+       * added.
+       */
+      path = g_file_read_link (sym_path, &gerror);
+      g_free (sym_path);
+      if (! path)
         {
-          /* Error. */
-          g_free (path2);
+          /* Read link fails but we can try reading /proc/self/maps as
+           * an alternate method.
+           */
+          g_printerr ("%s: %s\n", G_STRFUNC, gerror->message);
+          g_error_free (gerror);
+
           break;
         }
 
-      /* readlink() success. */
-      path[size] = '\0';
-
       /* Check whether the symlink's target is also a symlink.
        * We want to get the final target. */
       i = stat (path, &stat_buf);
       if (i == -1)
         {
           /* Error. */
-          g_free (path2);
           break;
         }
 
       /* stat() success. */
-      if (!S_ISLNK (stat_buf.st_mode))
+      if (! S_ISLNK (stat_buf.st_mode))
         {
           /* path is not a symlink. Done. */
-          g_free (path2);
           return path;
         }
 
       /* path is a symlink. Continue loop and resolve this. */
-      g_strlcpy (path, path2, buf_size);
+      sym_path = path;
     }
 
-
   /* readlink() or stat() failed; this can happen when the program is
    * running in Valgrind 2.2. Read from /proc/self/maps as fallback. */
 
-  buf_size = PATH_MAX + 128;
-  line = (char *) g_try_realloc (path, buf_size);
-  if (line == NULL)
+  file = g_file_new_for_path ("/proc/self/maps");
+  input = G_INPUT_STREAM (g_file_read (file, NULL, &gerror));
+  g_object_unref (file);
+  if (! input)
     {
-      /* Cannot allocate memory. */
-      g_free (path);
-      if (error)
-        *error = GIMP_RELOC_INIT_ERROR_NOMEM;
-      return NULL;
-    }
+      g_printerr ("%s: %s", G_STRFUNC, gerror->message);
+      g_error_free (gerror);
 
-  f = g_fopen ("/proc/self/maps", "r");
-  if (f == NULL)
-    {
-      g_free (line);
       if (error)
         *error = GIMP_RELOC_INIT_ERROR_OPEN_MAPS;
-      return NULL;
-    }
 
-  /* The first entry should be the executable name. */
-  result = fgets (line, (int) buf_size, f);
-  if (result == NULL)
-    {
-      fclose (f);
-      g_free (line);
-      if (error)
-        *error = GIMP_RELOC_INIT_ERROR_READ_MAPS;
       return NULL;
     }
 
-  /* Get rid of newline character. */
-  buf_size = strlen (line);
-  if (buf_size == 0)
+  data_input = g_data_input_stream_new (input);
+  g_object_unref (input);
+
+  /* The first entry with r-xp permission should be the executable name. */
+  while ((maps_line = g_data_input_stream_read_line (data_input, NULL, NULL, &gerror)))
     {
-      /* Huh? An empty string? */
-      fclose (f);
-      g_free (line);
-      if (error)
-        *error = GIMP_RELOC_INIT_ERROR_INVALID_MAPS;
-      return NULL;
-    }
-  if (line[buf_size - 1] == 10)
-    line[buf_size - 1] = 0;
+      if (maps_line == NULL)
+        {
+          if (gerror)
+            {
+              g_printerr ("%s: %s\n", G_STRFUNC, gerror->message);
+              g_error_free (gerror);
+            }
+          g_object_unref (data_input);
 
-  /* Extract the filename; it is always an absolute path. */
-  path = strchr (line, '/');
+          if (error)
+            *error = GIMP_RELOC_INIT_ERROR_READ_MAPS;
 
-  /* Sanity check. */
-  if (strstr (line, " r-xp ") == NULL || path == NULL)
-    {
-      fclose (f);
-      g_free (line);
-      if (error)
-        *error = GIMP_RELOC_INIT_ERROR_INVALID_MAPS;
-      return NULL;
+          return NULL;
+        }
+
+      /* Extract the filename; it is always an absolute path. */
+      path = strchr (maps_line, '/');
+
+      /* Sanity check. */
+      if (path && strstr (maps_line, " r-xp "))
+        {
+          /* We found the executable name. */
+          path = g_strdup (path);
+          break;
+        }
+
+      g_free (maps_line);
+      maps_line = NULL;
+      path = NULL;
     }
 
-  path = g_strdup (path);
-  g_free (line);
-  fclose (f);
+  if (path == NULL && error)
+    *error = GIMP_RELOC_INIT_ERROR_INVALID_MAPS;
+
+  g_object_unref (data_input);
+  g_free (maps_line);
+
   return path;
 #endif /* ! ENABLE_RELOCATABLE_RESOURCES || G_OS_WIN32 */
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]