[PATCH, libgfortran] PR 61035 Stack overflow in GETCWD

Janne Blomqvist blomqvist.janne@gmail.com
Sat May 3 20:47:00 GMT 2014


Hello,

the attached patch avoids a stack overflow crash due to not trying to
create a null-terminated duplicate of the argument char array on the
stack. Also, for the common case it avoids an extra allocation and an
extra memcpy.

Regtested on x86_64-unknown-linux-gnu, Ok for trunk?

2014-05-03  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.


-- 
Janne Blomqvist
-------------- next part --------------
diff --git a/libgfortran/intrinsics/getcwd.c b/libgfortran/intrinsics/getcwd.c
index 161a288..2bc1fbc 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);
 


More information about the Gcc-patches mailing list