summaryrefslogtreecommitdiff
path: root/libgfortran/intrinsics
diff options
context:
space:
mode:
authorjb <jb@138bc75d-0d04-0410-961f-82ee72b054a4>2014-05-12 19:23:11 +0000
committerjb <jb@138bc75d-0d04-0410-961f-82ee72b054a4>2014-05-12 19:23:11 +0000
commit0a96ce03ce106e391dcc5d36d91df67e7b98021f (patch)
treeabee16e7f24de843f1d23fe13d306718e67bbd5e /libgfortran/intrinsics
parenta159faebdbe010d27690e815637291da1a120a66 (diff)
downloadgcc-0a96ce03ce106e391dcc5d36d91df67e7b98021f.tar.gz
Fix stack overflow crash in getcwd intrinsic.
2014-05-12 Janne Blomqvist <jb@gcc.gnu.org> PR libfortran/61035 * intrinsics/getcwd.c (getcwd_i4_sub): Avoid potentially large stack allocation, avoid extra copying in the common case. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@210335 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgfortran/intrinsics')
-rw-r--r--libgfortran/intrinsics/getcwd.c37
1 files changed, 26 insertions, 11 deletions
diff --git a/libgfortran/intrinsics/getcwd.c b/libgfortran/intrinsics/getcwd.c
index 161a288f172..2bc1fbc8266 100644
--- a/libgfortran/intrinsics/getcwd.c
+++ b/libgfortran/intrinsics/getcwd.c
@@ -2,7 +2,7 @@
Copyright (C) 2004-2014 Free Software Foundation, Inc.
Contributed by Steven G. Kargl <kargls@comcast.net>.
-This file is part of the GNU Fortran 95 runtime library (libgfortran).
+This file is part of the GNU Fortran runtime library (libgfortran).
Libgfortran is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
@@ -40,20 +40,35 @@ iexport_proto(getcwd_i4_sub);
void
getcwd_i4_sub (char *cwd, GFC_INTEGER_4 *status, gfc_charlen_type cwd_len)
{
- char str[cwd_len + 1];
- GFC_INTEGER_4 stat;
+ int err;
- memset(cwd, ' ', (size_t) cwd_len);
-
- if (!getcwd (str, (size_t) cwd_len + 1))
- stat = errno;
- else
+ if (getcwd (cwd, cwd_len))
{
- stat = 0;
- memcpy (cwd, str, strlen (str));
+ size_t len = strlen (cwd);
+ memset (cwd + len, ' ', cwd_len - len);
+ err = 0;
}
+ else if (errno == ERANGE)
+ {
+ /* There is a possibility that the previous attempt failed due
+ to not enough space for the terminating null byte. Try again
+ with a buffer one char longer. */
+ char *buf = xmalloc (cwd_len + 1);
+ if (getcwd (buf, cwd_len + 1))
+ {
+ memcpy (cwd, buf, cwd_len);
+ err = 0;
+ }
+ else
+ err = errno;
+ free (buf);
+ }
+ else
+ err = errno;
+ if (err)
+ memset (cwd, ' ', cwd_len);
if (status != NULL)
- *status = stat;
+ *status = err;
}
iexport(getcwd_i4_sub);