aboutsummaryrefslogtreecommitdiff
path: root/libgfortran/runtime
diff options
context:
space:
mode:
authorjb <jb@138bc75d-0d04-0410-961f-82ee72b054a4>2014-05-22 03:51:25 +0000
committerjb <jb@138bc75d-0d04-0410-961f-82ee72b054a4>2014-05-22 03:51:25 +0000
commitfc3d374adc7e94f43e306cabf23df19c46fe4dae (patch)
treeb97492f2a8d9b9b3d41f020dde39ac89bad83229 /libgfortran/runtime
parent8f32810f4510e194a7dc78447487d79cff2293f0 (diff)
PR 60324 Handle long path names, don't use PATH_MAX.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@210738 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgfortran/runtime')
-rw-r--r--libgfortran/runtime/main.c64
-rw-r--r--libgfortran/runtime/string.c43
2 files changed, 89 insertions, 18 deletions
diff --git a/libgfortran/runtime/main.c b/libgfortran/runtime/main.c
index 58ec6cc4961..8a572ecd5ef 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 <stdlib.h>
#include <string.h>
#include <limits.h>
+#include <errno.h>
#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 a7f68bf5aa1..5beb0fbd971 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. */