From 4269f19c09163d6ef65043171eeccc9c521d9b5f Mon Sep 17 00:00:00 2001 From: Janne Blomqvist Date: Thu, 22 May 2014 06:51:25 +0300 Subject: PR 60324 Handle long path names, don't use PATH_MAX. From-SVN: r210738 --- libgfortran/runtime/main.c | 64 +++++++++++++++++++++++++++++++------------- libgfortran/runtime/string.c | 43 +++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 18 deletions(-) (limited to 'libgfortran/runtime') diff --git a/libgfortran/runtime/main.c b/libgfortran/runtime/main.c index 58ec6cc..8a572ec 100644 --- a/libgfortran/runtime/main.c +++ b/libgfortran/runtime/main.c @@ -26,6 +26,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include #include #include +#include #ifdef HAVE_UNISTD_H @@ -70,23 +71,18 @@ static int argc_save; static char **argv_save; static const char *exe_path; -static int please_free_exe_path_when_done; +static bool please_free_exe_path_when_done; /* Save the path under which the program was called, for use in the backtrace routines. */ void store_exe_path (const char * argv0) { -#ifndef PATH_MAX -#define PATH_MAX 1024 -#endif - #ifndef DIR_SEPARATOR #define DIR_SEPARATOR '/' #endif - char buf[PATH_MAX], *path; - const char *cwd; + char *cwd, *path; /* This can only happen if store_exe_path is called multiple times. */ if (please_free_exe_path_when_done) @@ -95,13 +91,27 @@ store_exe_path (const char * argv0) /* Reading the /proc/self/exe symlink is Linux-specific(?), but if it works it gives the correct answer. */ #ifdef HAVE_READLINK - int len; - if ((len = readlink ("/proc/self/exe", buf, sizeof (buf) - 1)) != -1) + ssize_t len, psize = 256; + while (1) { - buf[len] = '\0'; - exe_path = strdup (buf); - please_free_exe_path_when_done = 1; - return; + path = xmalloc (psize); + len = readlink ("/proc/self/exe", path, psize); + if (len < 0) + { + free (path); + break; + } + else if (len < psize) + { + path[len] = '\0'; + exe_path = strdup (path); + free (path); + please_free_exe_path_when_done = true; + return; + } + /* The remaining option is len == psize. */ + free (path); + psize *= 4; } #endif @@ -117,12 +127,29 @@ store_exe_path (const char * argv0) #endif { exe_path = argv0; - please_free_exe_path_when_done = 0; + please_free_exe_path_when_done = false; return; } #ifdef HAVE_GETCWD - cwd = getcwd (buf, sizeof (buf)); + size_t cwdsize = 256; + while (1) + { + cwd = xmalloc (cwdsize); + if (getcwd (cwd, cwdsize)) + break; + else if (errno == ERANGE) + { + free (cwd); + cwdsize *= 4; + } + else + { + free (cwd); + cwd = NULL; + break; + } + } #else cwd = NULL; #endif @@ -130,7 +157,7 @@ store_exe_path (const char * argv0) if (!cwd) { exe_path = argv0; - please_free_exe_path_when_done = 0; + please_free_exe_path_when_done = false; return; } @@ -138,10 +165,11 @@ store_exe_path (const char * argv0) if the executable is not in the cwd, but at this point we're out of better ideas. */ size_t pathlen = strlen (cwd) + 1 + strlen (argv0) + 1; - path = malloc (pathlen); + path = xmalloc (pathlen); snprintf (path, pathlen, "%s%c%s", cwd, DIR_SEPARATOR, argv0); + free (cwd); exe_path = path; - please_free_exe_path_when_done = 1; + please_free_exe_path_when_done = true; } diff --git a/libgfortran/runtime/string.c b/libgfortran/runtime/string.c index a7f68bf..5beb0fb 100644 --- a/libgfortran/runtime/string.c +++ b/libgfortran/runtime/string.c @@ -90,6 +90,49 @@ cf_strcpy (char *dest, gfc_charlen_type dest_len, const char *src) } +#ifndef HAVE_STRNLEN +static size_t +strnlen (const char *s, size_t maxlen) +{ + for (size_t ii = 0; ii < maxlen; ii++) + { + if (s[ii] == '\0') + return ii; + } + return maxlen; +} +#endif + + +#ifndef HAVE_STRNDUP +static char * +strndup (const char *s, size_t n) +{ + size_t len = strnlen (s, n); + char *p = malloc (len + 1); + if (!p) + return NULL; + memcpy (p, s, len); + p[len] = '\0'; + return p; +} +#endif + + +/* Duplicate a non-null-terminated Fortran string to a malloced + null-terminated C string. */ + +char * +fc_strdup (const char *src, gfc_charlen_type src_len) +{ + gfc_charlen_type n = fstrlen (src, src_len); + char *p = strndup (src, n); + if (!p) + os_error ("Memory allocation failed in fc_strdup"); + return p; +} + + /* Given a fortran string and an array of st_option structures, search through the array to find a match. If the option is not found, we generate an error if no default is provided. */ -- cgit v1.1