]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fix stack overflow crash in getcwd intrinsic.
authorJanne Blomqvist <jb@gcc.gnu.org>
Mon, 12 May 2014 19:23:11 +0000 (22:23 +0300)
committerJanne Blomqvist <jb@gcc.gnu.org>
Mon, 12 May 2014 19:23:11 +0000 (22:23 +0300)
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.

From-SVN: r210335

libgfortran/ChangeLog
libgfortran/intrinsics/getcwd.c

index f0314d951955087a37a85cea39e350b38a0cccc3..ed26a4d70772649a0e60b76f9e1186cd1b61470b 100644 (file)
@@ -1,3 +1,9 @@
+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.
index 161a288f1721bb884dcf6046451dc5d1e6c88e15..2bc1fbc8266444a46ecb27a7d39875f78dbc3fcc 100644 (file)
@@ -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);