diff mbox

[libfortran] Replace sprintf() with snprintf()

Message ID BANLkTim1Z06Edetw=pUZmKhNrVsoaS0Vog@mail.gmail.com
State New
Headers show

Commit Message

Janne Blomqvist April 15, 2011, 6:53 a.m. UTC
Hi,

as is well known, sprintf() is prone to buffer overflow, hence
snprintf(). libgfortran uses snprintf() in some places, but not
everywhere. Rather than analyzing every sprintf() call for a potential
overflow, the attached patch takes the dogmatic but simple approach of
replacing all the remaining sprintf() usage with snprintf().

For targets without snprintf(), io/list_read.c contained a fallback
macro that uses sprintf(); this is moved to libgfortran.h so that it's
available everywhere.

readelf -s libgfortran.so|grep sprintf

confirms that there is no remaining usage of sprintf().

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

2011-04-15  Janne Blomqvist  <jb@gcc.gnu.org>

	* intrinsics/date_and_time.c (date_and_time): Remove sprintf CPP
	branch.
	* io/format.c (format_error): Use snprintf instead of sprintf.
	* io/list_read.c: Move snprintf fallback macro to libgfortran.h.
	(convert_integer): Use snprintf instead of sprintf.
	(parse_repeat): Likewise.
	(read_logical): Likewise.
	(read_integer): Likewise.
	(read_character): Likewise.
	(parse_real): Likewise.
	(read_complex): Likewise.
	(read_real): Likewise.
	(check_type): Likewise.
	(nml_parse_qualifier): Add string length argument, use snprintf
	instead of sprintf.
	(nml_get_obj_data): Use snprintf instead of sprintf.
	* io/open.c (new_unit): Remove sprintf CPP branch, use snprintf
	instead of sprintf.
	* io/transfer.c (require_type): Use snprintf instead of sprintf.
	* io/unix.c (tempfile): Likewise.
	* io/write.c (nml_write_obj): Likewise.
	* io/write_float.def (output_float): Remove sprintf CPP branch,
	use snprintf instead of sprintf.
	* libgfortran.h: Add fallback snprintf macro from io/list_read.c.
	* runtime/backtrace.c (show_backtrace): Remove sprintf CPP branch.
	* runtime/main.c (store_exe_path): Use snprintf instead of
	sprintf.

Comments

Jerry DeLisle April 15, 2011, 12:34 p.m. UTC | #1
On 04/14/2011 11:53 PM, Janne Blomqvist wrote:
> Hi,
>
> as is well known, sprintf() is prone to buffer overflow, hence
> snprintf(). libgfortran uses snprintf() in some places, but not
> everywhere. Rather than analyzing every sprintf() call for a potential
> overflow, the attached patch takes the dogmatic but simple approach of
> replacing all the remaining sprintf() usage with snprintf().
>
> For targets without snprintf(), io/list_read.c contained a fallback
> macro that uses sprintf(); this is moved to libgfortran.h so that it's
> available everywhere.
>
> readelf -s libgfortran.so|grep sprintf
>
> confirms that there is no remaining usage of sprintf().
>
> Regtested on x86_64-unknown-linux-gnu, Ok for trunk?
>

OK, thanks.

Jerry
diff mbox

Patch

diff --git a/libgfortran/intrinsics/date_and_time.c b/libgfortran/intrinsics/date_and_time.c
index 793df68..fa51d5f 100644
--- a/libgfortran/intrinsics/date_and_time.c
+++ b/libgfortran/intrinsics/date_and_time.c
@@ -168,7 +168,6 @@  date_and_time (char *__date, char *__time, char *__zone,
       values[5] = local_time.tm_min;
       values[6] = local_time.tm_sec;
 
-#if HAVE_SNPRINTF
       if (__date)
 	snprintf (date, DATE_LEN + 1, "%04d%02d%02d",
 		  values[0], values[1], values[2]);
@@ -179,18 +178,6 @@  date_and_time (char *__date, char *__time, char *__zone,
       if (__zone)
 	snprintf (zone, ZONE_LEN + 1, "%+03d%02d",
 		  values[3] / 60, abs (values[3] % 60));
-#else
-      if (__date)
-	sprintf (date, "%04d%02d%02d", values[0], values[1], values[2]);
-
-      if (__time)
-	sprintf (timec, "%02d%02d%02d.%03d",
-		 values[4], values[5], values[6], values[7]);
-
-      if (__zone)
-	sprintf (zone, "%+03d%02d",
-		 values[3] / 60, abs (values[3] % 60));
-#endif
     }
   else
     {
diff --git a/libgfortran/io/format.c b/libgfortran/io/format.c
index d540fc4..5760e0c 100644
--- a/libgfortran/io/format.c
+++ b/libgfortran/io/format.c
@@ -1,4 +1,4 @@ 
-/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Andy Vaught
    F2003 I/O support contributed by Jerry DeLisle
@@ -1127,16 +1127,17 @@  void
 format_error (st_parameter_dt *dtp, const fnode *f, const char *message)
 {
   int width, i, j, offset;
-  char *p, buffer[300];
+#define BUFLEN 300
+  char *p, buffer[BUFLEN];
   format_data *fmt = dtp->u.p.fmt;
 
   if (f != NULL)
     fmt->format_string = f->source;
 
   if (message == unexpected_element)
-    sprintf (buffer, message, fmt->error_element);
+    snprintf (buffer, BUFLEN, message, fmt->error_element);
   else
-    sprintf (buffer, "%s\n", message);
+    snprintf (buffer, BUFLEN, "%s\n", message);
 
   j = fmt->format_string - dtp->format;
 
diff --git a/libgfortran/io/list_read.c b/libgfortran/io/list_read.c
index 39783bf..38a92e1 100644
--- a/libgfortran/io/list_read.c
+++ b/libgfortran/io/list_read.c
@@ -1,4 +1,4 @@ 
-/* Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+/* Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Andy Vaught
    Namelist input contributed by Paul Thomas
@@ -63,10 +63,8 @@  see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 
 #define MAX_REPEAT 200000000
 
-#ifndef HAVE_SNPRINTF
-# undef snprintf
-# define snprintf(str, size, ...) sprintf (str, __VA_ARGS__)
-#endif
+
+#define MSGLEN 100
 
 /* Save a character to a string buffer, enlarging it as necessary.  */
 
@@ -471,7 +469,7 @@  nml_bad_return (st_parameter_dt *dtp, char c)
 static int
 convert_integer (st_parameter_dt *dtp, int length, int negative)
 {
-  char c, *buffer, message[100];
+  char c, *buffer, message[MSGLEN];
   int m;
   GFC_INTEGER_LARGEST v, max, max10;
 
@@ -511,7 +509,7 @@  convert_integer (st_parameter_dt *dtp, int length, int negative)
 
       if (dtp->u.p.repeat_count == 0)
 	{
-	  sprintf (message, "Zero repeat count in item %d of list input",
+	  snprintf (message, MSGLEN, "Zero repeat count in item %d of list input",
 		   dtp->u.p.item_count);
 
 	  generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
@@ -524,10 +522,10 @@  convert_integer (st_parameter_dt *dtp, int length, int negative)
 
  overflow:
   if (length == -1)
-    sprintf (message, "Repeat count overflow in item %d of list input",
+    snprintf (message, MSGLEN, "Repeat count overflow in item %d of list input",
 	     dtp->u.p.item_count);
   else
-    sprintf (message, "Integer overflow while reading item %d",
+    snprintf (message, MSGLEN, "Integer overflow while reading item %d",
 	     dtp->u.p.item_count);
 
   free_saved (dtp);
@@ -544,7 +542,7 @@  convert_integer (st_parameter_dt *dtp, int length, int negative)
 static int
 parse_repeat (st_parameter_dt *dtp)
 {
-  char message[100];
+  char message[MSGLEN];
   int c, repeat;
 
   if ((c = next_char (dtp)) == EOF)
@@ -575,7 +573,7 @@  parse_repeat (st_parameter_dt *dtp)
 
 	  if (repeat > MAX_REPEAT)
 	    {
-	      sprintf (message,
+	      snprintf (message, MSGLEN,
 		       "Repeat count overflow in item %d of list input",
 		       dtp->u.p.item_count);
 
@@ -588,7 +586,7 @@  parse_repeat (st_parameter_dt *dtp)
 	case '*':
 	  if (repeat == 0)
 	    {
-	      sprintf (message,
+	      snprintf (message, MSGLEN,
 		       "Zero repeat count in item %d of list input",
 		       dtp->u.p.item_count);
 
@@ -617,7 +615,7 @@  parse_repeat (st_parameter_dt *dtp)
     }
   else
     eat_line (dtp);
-  sprintf (message, "Bad repeat count in item %d of list input",
+  snprintf (message, MSGLEN, "Bad repeat count in item %d of list input",
 	   dtp->u.p.item_count);
   generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
   return 1;
@@ -647,7 +645,7 @@  l_push_char (st_parameter_dt *dtp, char c)
 static void
 read_logical (st_parameter_dt *dtp, int length)
 {
-  char message[100];
+  char message[MSGLEN];
   int c, i, v;
 
   if (parse_repeat (dtp))
@@ -770,7 +768,7 @@  read_logical (st_parameter_dt *dtp, int length)
     }
   else if (c != '\n')
     eat_line (dtp);
-  sprintf (message, "Bad logical value while reading item %d",
+  snprintf (message, MSGLEN, "Bad logical value while reading item %d",
 	      dtp->u.p.item_count);
   generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
   return;
@@ -793,7 +791,7 @@  read_logical (st_parameter_dt *dtp, int length)
 static void
 read_integer (st_parameter_dt *dtp, int length)
 {
-  char message[100];
+  char message[MSGLEN];
   int c, negative;
 
   negative = 0;
@@ -908,7 +906,7 @@  read_integer (st_parameter_dt *dtp, int length)
     }
   else if (c != '\n')
     eat_line (dtp);
-  sprintf (message, "Bad integer for item %d in list input",
+  snprintf (message, MSGLEN, "Bad integer for item %d in list input",
 	      dtp->u.p.item_count);
   generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
 
@@ -935,7 +933,7 @@  read_integer (st_parameter_dt *dtp, int length)
 static void
 read_character (st_parameter_dt *dtp, int length __attribute__ ((unused)))
 {
-  char quote, message[100];
+  char quote, message[MSGLEN];
   int c;
 
   quote = ' ';			/* Space means no quote character.  */
@@ -1086,7 +1084,7 @@  read_character (st_parameter_dt *dtp, int length __attribute__ ((unused)))
 	  hit_eof (dtp);
 	  return;
 	}
-      sprintf (message, "Invalid string input in item %d",
+      snprintf (message, MSGLEN, "Invalid string input in item %d",
 		  dtp->u.p.item_count);
       generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
     }
@@ -1099,7 +1097,7 @@  read_character (st_parameter_dt *dtp, int length __attribute__ ((unused)))
 static int
 parse_real (st_parameter_dt *dtp, void *buffer, int length)
 {
-  char message[100];
+  char message[MSGLEN];
   int c, m, seen_dp;
 
   if ((c = next_char (dtp)) == EOF)
@@ -1284,7 +1282,7 @@  parse_real (st_parameter_dt *dtp, void *buffer, int length)
     }
   else if (c != '\n')
     eat_line (dtp);
-  sprintf (message, "Bad floating point number for item %d",
+  snprintf (message, MSGLEN, "Bad floating point number for item %d",
 	      dtp->u.p.item_count);
   generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
 
@@ -1298,7 +1296,7 @@  parse_real (st_parameter_dt *dtp, void *buffer, int length)
 static void
 read_complex (st_parameter_dt *dtp, void * dest, int kind, size_t size)
 {
-  char message[100];
+  char message[MSGLEN];
   int c;
 
   if (parse_repeat (dtp))
@@ -1388,7 +1386,7 @@  eol_4:
     }
   else if (c != '\n')   
     eat_line (dtp);
-  sprintf (message, "Bad complex value in item %d of list input",
+  snprintf (message, MSGLEN, "Bad complex value in item %d of list input",
 	      dtp->u.p.item_count);
   generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
 }
@@ -1399,7 +1397,7 @@  eol_4:
 static void
 read_real (st_parameter_dt *dtp, void * dest, int length)
 {
-  char message[100];
+  char message[MSGLEN];
   int c;
   int seen_dp;
   int is_inf;
@@ -1760,7 +1758,7 @@  read_real (st_parameter_dt *dtp, void * dest, int length)
   else if (c != '\n')
     eat_line (dtp);
 
-  sprintf (message, "Bad real number in item %d of list input",
+  snprintf (message, MSGLEN, "Bad real number in item %d of list input",
 	      dtp->u.p.item_count);
   generate_error (&dtp->common, LIBERROR_READ_VALUE, message);
 }
@@ -1772,11 +1770,11 @@  read_real (st_parameter_dt *dtp, void * dest, int length)
 static int
 check_type (st_parameter_dt *dtp, bt type, int len)
 {
-  char message[100];
+  char message[MSGLEN];
 
   if (dtp->u.p.saved_type != BT_UNKNOWN && dtp->u.p.saved_type != type)
     {
-      sprintf (message, "Read type %s where %s was expected for item %d",
+      snprintf (message, MSGLEN, "Read type %s where %s was expected for item %d",
 		  type_name (dtp->u.p.saved_type), type_name (type),
 		  dtp->u.p.item_count);
 
@@ -1789,7 +1787,7 @@  check_type (st_parameter_dt *dtp, bt type, int len)
 
   if (dtp->u.p.saved_length != len)
     {
-      sprintf (message,
+      snprintf (message, MSGLEN,
 		  "Read kind %d %s where kind %d is required for item %d",
 		  dtp->u.p.saved_length, type_name (dtp->u.p.saved_type), len,
 		  dtp->u.p.item_count);
@@ -2040,6 +2038,7 @@  calls:
 static try
 nml_parse_qualifier (st_parameter_dt *dtp, descriptor_dimension *ad,
 		     array_loop_spec *ls, int rank, char *parse_err_msg,
+		     size_t parse_err_msg_size,
 		     int *parsed_rank)
 {
   int dim;
@@ -2109,9 +2108,11 @@  nml_parse_qualifier (st_parameter_dt *dtp, descriptor_dimension *ad,
 		      || (c==')' && dim < rank -1))
 		    {
 		      if (is_char)
-		        sprintf (parse_err_msg, "Bad substring qualifier");
+		        snprintf (parse_err_msg, parse_err_msg_size, 
+				  "Bad substring qualifier");
 		      else
-			sprintf (parse_err_msg, "Bad number of index fields");
+			snprintf (parse_err_msg, parse_err_msg_size, 
+				 "Bad number of index fields");
 		      goto err_ret;
 		    }
 		  break;
@@ -2128,10 +2129,11 @@  nml_parse_qualifier (st_parameter_dt *dtp, descriptor_dimension *ad,
 
 		default:
 		  if (is_char)
-		    sprintf (parse_err_msg,
+		    snprintf (parse_err_msg, parse_err_msg_size,
 			     "Bad character in substring qualifier");
 		  else
-		    sprintf (parse_err_msg, "Bad character in index");
+		    snprintf (parse_err_msg, parse_err_msg_size, 
+			      "Bad character in index");
 		  goto err_ret;
 		}
 
@@ -2139,9 +2141,11 @@  nml_parse_qualifier (st_parameter_dt *dtp, descriptor_dimension *ad,
 		  && dtp->u.p.saved_string == 0)
 		{
 		  if (is_char)
-		    sprintf (parse_err_msg, "Null substring qualifier");
+		    snprintf (parse_err_msg, parse_err_msg_size, 
+			      "Null substring qualifier");
 		  else
-		    sprintf (parse_err_msg, "Null index field");
+		    snprintf (parse_err_msg, parse_err_msg_size, 
+			      "Null index field");
 		  goto err_ret;
 		}
 
@@ -2149,15 +2153,17 @@  nml_parse_qualifier (st_parameter_dt *dtp, descriptor_dimension *ad,
 		  || (indx == 2 && dtp->u.p.saved_string == 0))
 		{
 		  if (is_char)
-		    sprintf (parse_err_msg, "Bad substring qualifier");
+		    snprintf (parse_err_msg, parse_err_msg_size, 
+			      "Bad substring qualifier");
 		  else
-		    sprintf (parse_err_msg, "Bad index triplet");
+		    snprintf (parse_err_msg, parse_err_msg_size,
+			      "Bad index triplet");
 		  goto err_ret;
 		}
 
 	      if (is_char && !is_array_section)
 		{
-		  sprintf (parse_err_msg,
+		  snprintf (parse_err_msg, parse_err_msg_size,
 			   "Missing colon in substring qualifier");
 		  goto err_ret;
 		}
@@ -2175,9 +2181,11 @@  nml_parse_qualifier (st_parameter_dt *dtp, descriptor_dimension *ad,
 	      if (convert_integer (dtp, sizeof(index_type), neg))
 		{
 		  if (is_char)
-		    sprintf (parse_err_msg, "Bad integer substring qualifier");
+		    snprintf (parse_err_msg, parse_err_msg_size,
+			      "Bad integer substring qualifier");
 		  else
-		    sprintf (parse_err_msg, "Bad integer in index");
+		    snprintf (parse_err_msg, parse_err_msg_size,
+			      "Bad integer in index");
 		  goto err_ret;
 		}
 	      break;
@@ -2235,16 +2243,19 @@  nml_parse_qualifier (st_parameter_dt *dtp, descriptor_dimension *ad,
 	   || (ls[dim].end < GFC_DIMENSION_LBOUND(ad[dim])))
 	{
 	  if (is_char)
-	    sprintf (parse_err_msg, "Substring out of range");
+	    snprintf (parse_err_msg, parse_err_msg_size, 
+		      "Substring out of range");
 	  else
-	    sprintf (parse_err_msg, "Index %d out of range", dim + 1);
+	    snprintf (parse_err_msg, parse_err_msg_size, 
+		      "Index %d out of range", dim + 1);
 	  goto err_ret;
 	}
 
       if (((ls[dim].end - ls[dim].start ) * ls[dim].step < 0)
 	  || (ls[dim].step == 0))
 	{
-	  sprintf (parse_err_msg, "Bad range in index %d", dim + 1);
+	  snprintf (parse_err_msg, parse_err_msg_size, 
+		   "Bad range in index %d", dim + 1);
 	  goto err_ret;
 	}
 
@@ -2732,7 +2743,8 @@  nml_get_obj_data (st_parameter_dt *dtp, namelist_info **pprev_nl,
 	return FAILURE;
       if (c != '?')
 	{
-	  sprintf (nml_err_msg, "namelist read: misplaced = sign");
+	  snprintf (nml_err_msg, nml_err_msg_size, 
+		    "namelist read: misplaced = sign");
 	  goto nml_err_ret;
 	}
       nml_query (dtp, '=');
@@ -2747,7 +2759,8 @@  nml_get_obj_data (st_parameter_dt *dtp, namelist_info **pprev_nl,
       nml_match_name (dtp, "end", 3);
       if (dtp->u.p.nml_read_error)
 	{
-	  sprintf (nml_err_msg, "namelist not terminated with / or &end");
+	  snprintf (nml_err_msg, nml_err_msg_size, 
+		    "namelist not terminated with / or &end");
 	  goto nml_err_ret;
 	}
     case '/':
@@ -2838,7 +2851,8 @@  get_name:
     {
       parsed_rank = 0;
       if (nml_parse_qualifier (dtp, nl->dim, nl->ls, nl->var_rank,
-			       nml_err_msg, &parsed_rank) == FAILURE)
+			       nml_err_msg, nml_err_msg_size, 
+			       &parsed_rank) == FAILURE)
 	{
 	  char *nml_err_msg_end = strchr (nml_err_msg, '\0');
 	  snprintf (nml_err_msg_end,
@@ -2893,7 +2907,8 @@  get_name:
       descriptor_dimension chd[1] = { {1, clow, nl->string_length} };
       array_loop_spec ind[1] = { {1, clow, nl->string_length, 1} };
 
-      if (nml_parse_qualifier (dtp, chd, ind, -1, nml_err_msg, &parsed_rank)
+      if (nml_parse_qualifier (dtp, chd, ind, -1, nml_err_msg, 
+			       nml_err_msg_size, &parsed_rank)
 	  == FAILURE)
 	{
 	  char *nml_err_msg_end = strchr (nml_err_msg, '\0');
diff --git a/libgfortran/io/open.c b/libgfortran/io/open.c
index d7448c0..bcf7941 100644
--- a/libgfortran/io/open.c
+++ b/libgfortran/io/open.c
@@ -1,4 +1,4 @@ 
-/* Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+/* Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Andy Vaught
    F2003 I/O support contributed by Jerry DeLisle
@@ -467,12 +467,8 @@  new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags * flags)
 	break;
 
       opp->file = tmpname;
-#ifdef HAVE_SNPRINTF
       opp->file_len = snprintf(opp->file, sizeof (tmpname), "fort.%d", 
 			       (int) opp->common.unit);
-#else
-      opp->file_len = sprintf(opp->file, "fort.%d", (int) opp->common.unit);
-#endif
       break;
 
     default:
@@ -504,26 +500,29 @@  new_unit (st_parameter_open *opp, gfc_unit *u, unit_flags * flags)
   if (s == NULL)
     {
       char *path, *msg;
+      size_t msglen;
       path = (char *) gfc_alloca (opp->file_len + 1);
-      msg = (char *) gfc_alloca (opp->file_len + 51);
+      msglen = opp->file_len + 51;
+      msg = (char *) gfc_alloca (msglen);
       unpack_filename (path, opp->file, opp->file_len);
 
       switch (errno)
 	{
 	case ENOENT: 
-	  sprintf (msg, "File '%s' does not exist", path);
+	  snprintf (msg, msglen, "File '%s' does not exist", path);
 	  break;
 
 	case EEXIST:
-	  sprintf (msg, "File '%s' already exists", path);
+	  snprintf (msg, msglen, "File '%s' already exists", path);
 	  break;
 
 	case EACCES:
-	  sprintf (msg, "Permission denied trying to open file '%s'", path);
+	  snprintf (msg, msglen, 
+		    "Permission denied trying to open file '%s'", path);
 	  break;
 
 	case EISDIR:
-	  sprintf (msg, "'%s' is a directory", path);
+	  snprintf (msg, msglen, "'%s' is a directory", path);
 	  break;
 
 	default:
diff --git a/libgfortran/io/transfer.c b/libgfortran/io/transfer.c
index 15f90e7..12aca97 100644
--- a/libgfortran/io/transfer.c
+++ b/libgfortran/io/transfer.c
@@ -1047,13 +1047,15 @@  write_constant_string (st_parameter_dt *dtp, const fnode *f)
 static int
 require_type (st_parameter_dt *dtp, bt expected, bt actual, const fnode *f)
 {
-  char buffer[100];
+#define BUFLEN 100
+  char buffer[BUFLEN];
 
   if (actual == expected)
     return 0;
 
   /* Adjust item_count before emitting error message.  */
-  sprintf (buffer, "Expected %s for item %d in formatted transfer, got %s",
+  snprintf (buffer, BUFLEN, 
+	    "Expected %s for item %d in formatted transfer, got %s",
 	   type_name (expected), dtp->u.p.item_count - 1, type_name (actual));
 
   format_error (dtp, f, buffer);
diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c
index d14d2b4..4295071 100644
--- a/libgfortran/io/unix.c
+++ b/libgfortran/io/unix.c
@@ -1068,7 +1068,8 @@  tempfile (st_parameter_open *opp)
   template = get_mem (tempdirlen + 23);
 
 #ifdef HAVE_MKSTEMP
-  sprintf (template, "%s%sgfortrantmpXXXXXX", tempdir, slash);
+  snprintf (template, tempdirlen + 23, "%s%sgfortrantmpXXXXXX", 
+	    tempdir, slash);
 
   fd = mkstemp (template);
 
@@ -1078,7 +1079,8 @@  tempfile (st_parameter_open *opp)
   slashlen = strlen (slash);
   do
     {
-      sprintf (template, "%s%sgfortrantmpaaaXXXXXX", tempdir, slash);
+      snprintf (template, tempdirlen + 23, "%s%sgfortrantmpaaaXXXXXX", 
+		tempdir, slash);
       if (count > 0)
 	{
 	  int c = count;
diff --git a/libgfortran/io/write.c b/libgfortran/io/write.c
index 4733d51..5338162 100644
--- a/libgfortran/io/write.c
+++ b/libgfortran/io/write.c
@@ -1,4 +1,4 @@ 
-/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+/* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Andy Vaught
    Namelist output contributed by Paul Thomas
@@ -1689,6 +1689,7 @@  nml_write_obj (st_parameter_dt *dtp, namelist_info * obj, index_type offset,
   char cup;
   char * obj_name;
   char * ext_name;
+  size_t ext_name_len;
   char rep_buff[NML_DIGITS];
   namelist_info * cmp;
   namelist_info * retval = obj->next;
@@ -1797,7 +1798,7 @@  nml_write_obj (st_parameter_dt *dtp, namelist_info * obj, index_type offset,
 	{
 	  if (rep_ctr > 1)
 	    {
-	      sprintf(rep_buff, " %d*", rep_ctr);
+	      snprintf(rep_buff, NML_DIGITS, " %d*", rep_ctr);
 	      write_character (dtp, rep_buff, 1, strlen (rep_buff));
 	      dtp->u.p.no_leading_blank = 1;
 	    }
@@ -1851,11 +1852,9 @@  nml_write_obj (st_parameter_dt *dtp, namelist_info * obj, index_type offset,
 
 	      base_name_len = base_name ? strlen (base_name) : 0;
 	      base_var_name_len = base ? strlen (base->var_name) : 0;
-	      ext_name = (char*)get_mem ( base_name_len
-					+ base_var_name_len
-					+ strlen (obj->var_name)
-					+ obj->var_rank * NML_DIGITS
-					+ 1);
+	      ext_name_len = base_name_len + base_var_name_len 
+		+ strlen (obj->var_name) + obj->var_rank * NML_DIGITS + 1;
+	      ext_name = (char*)get_mem (ext_name_len);
 
 	      memcpy (ext_name, base_name, base_name_len);
 	      clen = strlen (obj->var_name + base_var_name_len);
@@ -1872,7 +1871,8 @@  nml_write_obj (st_parameter_dt *dtp, namelist_info * obj, index_type offset,
 		      ext_name[tot_len] = '(';
 		      tot_len++;
 		    }
-		  sprintf (ext_name + tot_len, "%d", (int) obj->ls[dim_i].idx);
+		  snprintf (ext_name + tot_len, ext_name_len - tot_len, "%d", 
+			    (int) obj->ls[dim_i].idx);
 		  tot_len += strlen (ext_name + tot_len);
 		  ext_name[tot_len] = ((int) dim_i == obj->var_rank - 1) ? ')' : ',';
 		  tot_len++;
diff --git a/libgfortran/io/write_float.def b/libgfortran/io/write_float.def
index b72cf9f..9661b2b 100644
--- a/libgfortran/io/write_float.def
+++ b/libgfortran/io/write_float.def
@@ -524,11 +524,7 @@  output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
 	      *(out4++) = expchar;
 	      edigits--;
 	    }
-#if HAVE_SNPRINTF
 	  snprintf (buffer, size, "%+0*d", edigits, e);
-#else
-	  sprintf (buffer, "%+0*d", edigits, e);
-#endif
 	  memcpy4 (out4, buffer, edigits);
 	}
 
@@ -616,11 +612,7 @@  output_float (st_parameter_dt *dtp, const fnode *f, char *buffer, size_t size,
 	  *(out++) = expchar;
 	  edigits--;
 	}
-#if HAVE_SNPRINTF
       snprintf (buffer, size, "%+0*d", edigits, e);
-#else
-      sprintf (buffer, "%+0*d", edigits, e);
-#endif
       memcpy (out, buffer, edigits);
     }
 
@@ -940,7 +932,7 @@  OUTPUT_FLOAT_FMT_G(16)
 
 /* Define a macro to build code for write_float.  */
 
-  /* Note: Before output_float is called, sprintf is used to print to buffer the
+  /* Note: Before output_float is called, snprintf is used to print to buffer the
      number in the format +D.DDDDe+ddd. For an N digit exponent, this gives us
      (MIN_FIELD_WIDTH-5)-N digits after the decimal point, plus another one
      before the decimal point.
@@ -961,8 +953,6 @@  OUTPUT_FLOAT_FMT_G(16)
        equal to the precision. The exponent always contains at least two
        digits; if the value is zero, the exponent is 00.  */
 
-#ifdef HAVE_SNPRINTF
-
 #define DTOA \
 snprintf (buffer, size, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
 	  "e", ndigits - 1, tmp);
@@ -971,17 +961,6 @@  snprintf (buffer, size, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
 snprintf (buffer, size, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
 	  "Le", ndigits - 1, tmp);
 
-#else
-
-#define DTOA \
-sprintf (buffer, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
-	 "e", ndigits - 1, tmp);
-
-#define DTOAL \
-sprintf (buffer, "%+-#" STR(MIN_FIELD_WIDTH) ".*" \
-	 "Le", ndigits - 1, tmp);
-
-#endif
 
 #if defined(GFC_REAL_16_IS_FLOAT128)
 #define DTOAQ \
diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h
index 7d9aca1..6cccaca 100644
--- a/libgfortran/libgfortran.h
+++ b/libgfortran/libgfortran.h
@@ -119,6 +119,10 @@  extern int __mingw_snprintf (char *, size_t, const char *, ...)
      __attribute__ ((format (gnu_printf, 3, 4)));
 #undef snprintf
 #define snprintf __mingw_snprintf
+/* Fallback to sprintf if target does not have snprintf.  */
+#elif !defined(HAVE_SNPRINTF)
+#undef snprintf
+#define snprintf(str, size, ...) sprintf (str, __VA_ARGS__)
 #endif
 
 
diff --git a/libgfortran/runtime/backtrace.c b/libgfortran/runtime/backtrace.c
index 4a831c0..5e4f15c 100644
--- a/libgfortran/runtime/backtrace.c
+++ b/libgfortran/runtime/backtrace.c
@@ -1,7 +1,7 @@ 
-/* Copyright (C) 2006, 2007, 2009 Free Software Foundation, Inc.
+/* Copyright (C) 2006, 2007, 2009, 2011 Free Software Foundation, Inc.
    Contributed by François-Xavier Coudert
 
-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 License as published by
@@ -290,11 +290,7 @@  fallback:
 
 	st_printf ("\nBacktrace for this error:\n");
 	arg[0] = (char *) "pstack";
-#ifdef HAVE_SNPRINTF
 	snprintf (buf, sizeof(buf), "%d", (int) getppid ());
-#else
-	sprintf (buf, "%d", (int) getppid ());
-#endif
 	arg[1] = buf;
 	arg[2] = NULL;
 	execvp (arg[0], arg);
diff --git a/libgfortran/runtime/main.c b/libgfortran/runtime/main.c
index 28247ca..f5d4721 100644
--- a/libgfortran/runtime/main.c
+++ b/libgfortran/runtime/main.c
@@ -1,7 +1,8 @@ 
-/* Copyright (C) 2002-2003, 2005, 2007, 2009 Free Software Foundation, Inc.
+/* Copyright (C) 2002-2003, 2005, 2007, 2009, 2011 
+   Free Software Foundation, Inc.
    Contributed by Andy Vaught and Paul Brook <paul@nowt.org>
 
-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 License as published by
@@ -107,8 +108,9 @@  store_exe_path (const char * argv0)
 #endif
 
   /* exe_path will be cwd + "/" + argv[0] + "\0" */
-  path = malloc (strlen (cwd) + 1 + strlen (argv0) + 1);
-  sprintf (path, "%s%c%s", cwd, DIR_SEPARATOR, argv0);
+  size_t pathlen = strlen (cwd) + 1 + strlen (argv0) + 1;
+  path = malloc (pathlen);
+  snprintf (path, pathlen, "%s%c%s", cwd, DIR_SEPARATOR, argv0);
   exe_path = path;
   please_free_exe_path_when_done = 1;
 }