summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Pluzhnikov <ppluzhnikov@google.com>2015-10-05 20:03:48 -0700
committerPaul Pluzhnikov <ppluzhnikov@google.com>2015-10-05 20:03:48 -0700
commitbe64c2ef2ac2357ddff61841f2cc8246e5da1b20 (patch)
treeb0140cf88da2954f7940e362ae6e53728793f2e7
parentcec7d28af8ccb40dbf82d99efa13a040b31b9387 (diff)
downloadglibc-be64c2ef2ac2357ddff61841f2cc8246e5da1b20.tar.gz
glibc-be64c2ef2ac2357ddff61841f2cc8246e5da1b20.tar.xz
glibc-be64c2ef2ac2357ddff61841f2cc8246e5da1b20.zip
Fix BZ #19012 -- iconv_open leaks memory on error path.
-rw-r--r--ChangeLog6
-rw-r--r--NEWS4
-rw-r--r--iconv/gconv_db.c39
3 files changed, 39 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 77d065202e..259b05e692 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2015-10-05  Paul Pluzhnikov  <ppluzhnikov@google.com>
+
+	[BZ #19012]
+	* iconv/gconv_db.c (gen_steps): Check for additional errors.
+	Clean up on failure.
+
 2015-10-05  Joseph Myers  <joseph@codesourcery.com>
 
 	[BZ #19071]
diff --git a/NEWS b/NEWS
index d14efbd9e0..16f5cfb002 100644
--- a/NEWS
+++ b/NEWS
@@ -17,8 +17,8 @@ Version 2.23
   18757, 18778, 18781, 18787, 18789, 18790, 18795, 18796, 18803, 18820,
   18823, 18824, 18825, 18857, 18863, 18870, 18872, 18873, 18875, 18887,
   18921, 18951, 18952, 18956, 18961, 18966, 18967, 18969, 18970, 18977,
-  18980, 18981, 18985, 19003, 19016, 19032, 19046, 19049, 19050, 19059,
-  19071.
+  18980, 18981, 18985, 19003, 19012, 19016, 19032, 19046, 19049, 19050,
+  19059, 19071.
 
 * The obsolete header <regexp.h> has been removed.  Programs that require
   this header must be updated to use <regex.h> instead.
diff --git a/iconv/gconv_db.c b/iconv/gconv_db.c
index 4e6ec657e2..74b4ff5670 100644
--- a/iconv/gconv_db.c
+++ b/iconv/gconv_db.c
@@ -243,6 +243,8 @@ gen_steps (struct derivation_step *best, const char *toset,
   struct __gconv_step *result;
   struct derivation_step *current;
   int status = __GCONV_NOMEM;
+  char *from_name = NULL;
+  char *to_name = NULL;
 
   /* First determine number of steps.  */
   for (current = best; current->last != NULL; current = current->last)
@@ -259,12 +261,30 @@ gen_steps (struct derivation_step *best, const char *toset,
       current = best;
       while (step_cnt-- > 0)
 	{
-	  result[step_cnt].__from_name = (step_cnt == 0
-					  ? __strdup (fromset)
-					  : (char *)current->last->result_set);
-	  result[step_cnt].__to_name = (step_cnt + 1 == *nsteps
-					? __strdup (current->result_set)
-					: result[step_cnt + 1].__from_name);
+	  if (step_cnt == 0)
+	    {
+	      result[step_cnt].__from_name = from_name = __strdup (fromset);
+	      if (from_name == NULL)
+		{
+		  failed = 1;
+		  break;
+		}
+	    }
+	  else
+	    result[step_cnt].__from_name = (char *)current->last->result_set;
+
+	  if (step_cnt + 1 == *nsteps)
+	    {
+	      result[step_cnt].__to_name = to_name
+		= __strdup (current->result_set);
+	      if (to_name == NULL)
+		{
+		  failed = 1;
+		  break;
+		}
+	    }
+	  else
+	    result[step_cnt].__to_name = result[step_cnt + 1].__from_name;
 
 	  result[step_cnt].__counter = 1;
 	  result[step_cnt].__data = NULL;
@@ -332,6 +352,8 @@ gen_steps (struct derivation_step *best, const char *toset,
 	  while (++step_cnt < *nsteps)
 	    __gconv_release_step (&result[step_cnt]);
 	  free (result);
+	  free (from_name);
+	  free (to_name);
 	  *nsteps = 0;
 	  *handle = NULL;
 	  if (status == __GCONV_OK)
@@ -828,8 +850,9 @@ free_modules_db (struct gconv_module *node)
 /* Free all resources if necessary.  */
 libc_freeres_fn (free_mem)
 {
-  /* First free locale memory.  This needs to be done before freeing derivations,
-     as ctype cleanup functions dereference steps arrays which we free below.  */
+  /* First free locale memory.  This needs to be done before freeing
+     derivations, as ctype cleanup functions dereference steps arrays which we
+     free below.  */
   _nl_locale_subfreeres ();
 
   /* finddomain.c has similar problem.  */