diff options
author | jb <jb@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-05-12 19:23:11 +0000 |
---|---|---|
committer | jb <jb@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-05-12 19:23:11 +0000 |
commit | 0a96ce03ce106e391dcc5d36d91df67e7b98021f (patch) | |
tree | abee16e7f24de843f1d23fe13d306718e67bbd5e | |
parent | a159faebdbe010d27690e815637291da1a120a66 (diff) | |
download | gcc-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
-rw-r--r-- | libgfortran/ChangeLog | 6 | ||||
-rw-r--r-- | libgfortran/intrinsics/getcwd.c | 37 |
2 files changed, 32 insertions, 11 deletions
diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index f0314d95195..ed26a4d7077 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,5 +1,11 @@ 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. + +2014-05-12 Janne Blomqvist <jb@gcc.gnu.org> + * configure.ac (AM_CFLAGS): Use -std=gnu11. (CFLAGS): Likewise. * configure: Regenerated. 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); |