6c0556
commit 9429049c178b3af3d6afeb3717ff1f2214dc9572
6c0556
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
6c0556
Date:   Mon Jun 28 09:15:55 2021 +0530
6c0556
6c0556
    iconvconfig: Fix multiple issues
6c0556
    
6c0556
    It was noticed on big-endian systems that msgfmt would fail with the
6c0556
    following error:
6c0556
    
6c0556
    msgfmt: gconv_builtin.c:70: __gconv_get_builtin_trans: Assertion `cnt < sizeof (map) / sizeof (map[0])' failed.
6c0556
    Aborted (core dumped)
6c0556
    
6c0556
    This is only seen on installed systems because it was due to a
6c0556
    corrupted gconv-modules.cache.  iconvconfig had the following issues
6c0556
    (it was specifically freeing fulldir that caused this issue, but other
6c0556
    cleanups are also needed) that this patch fixes.
6c0556
    
6c0556
    - Add prefix only if dir starts with '/'
6c0556
    - Use asprintf instead of mempcpy so that the directory string is NULL
6c0556
      terminated
6c0556
    - Make a copy of the directory reference in new_module so that fulldir
6c0556
      can be freed within the same scope in handle_dir.
6c0556
    
6c0556
    Reviewed-by: Florian Weimer <fweimer@redhat.com>
6c0556
6c0556
diff --git a/iconv/Makefile b/iconv/Makefile
6c0556
index d09b8ac842731780..6df9862e748ae588 100644
6c0556
--- a/iconv/Makefile
6c0556
+++ b/iconv/Makefile
6c0556
@@ -33,7 +33,7 @@ vpath %.c ../locale/programs ../intl
6c0556
 iconv_prog-modules = iconv_charmap charmap charmap-dir linereader \
6c0556
 		     dummy-repertoire simple-hash xstrdup xmalloc \
6c0556
 		     record-status
6c0556
-iconvconfig-modules = strtab xmalloc hash-string
6c0556
+iconvconfig-modules = strtab xmalloc xasprintf xstrdup hash-string
6c0556
 extra-objs	   = $(iconv_prog-modules:=.o) $(iconvconfig-modules:=.o)
6c0556
 CFLAGS-iconv_prog.c += -I../locale/programs
6c0556
 CFLAGS-iconv_charmap.c += -I../locale/programs
6c0556
diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c
6c0556
index 01ecf6f67d55dbbf..777da870d2f8e99a 100644
6c0556
--- a/iconv/iconvconfig.c
6c0556
+++ b/iconv/iconvconfig.c
6c0556
@@ -250,6 +250,7 @@ static const char gconv_module_ext[] = MODULE_EXT;
6c0556
 
6c0556
 
6c0556
 #include <programs/xmalloc.h>
6c0556
+#include <programs/xasprintf.h>
6c0556
 
6c0556
 
6c0556
 /* C string table handling.  */
6c0556
@@ -519,11 +520,12 @@ module_compare (const void *p1, const void *p2)
6c0556
 /* Create new module record.  */
6c0556
 static void
6c0556
 new_module (const char *fromname, size_t fromlen, const char *toname,
6c0556
-	    size_t tolen, const char *directory,
6c0556
+	    size_t tolen, const char *dir_in,
6c0556
 	    const char *filename, size_t filelen, int cost, size_t need_ext)
6c0556
 {
6c0556
   struct module *new_module;
6c0556
-  size_t dirlen = strlen (directory) + 1;
6c0556
+  size_t dirlen = strlen (dir_in) + 1;
6c0556
+  const char *directory = xstrdup (dir_in);
6c0556
   char *tmp;
6c0556
   void **inserted;
6c0556
 
6c0556
@@ -654,20 +656,10 @@ handle_dir (const char *dir)
6c0556
   size_t dirlen = strlen (dir);
6c0556
   bool found = false;
6c0556
 
6c0556
-  /* Add the prefix before sending it off to the parser.  */
6c0556
-  char *fulldir = xmalloc (prefix_len + dirlen + 2);
6c0556
-  char *cp = mempcpy (mempcpy (fulldir, prefix, prefix_len), dir, dirlen);
6c0556
+  char *fulldir = xasprintf ("%s%s%s", dir[0] == '/' ? prefix : "",
6c0556
+			     dir, dir[dirlen - 1] != '/' ? "/" : "");
6c0556
 
6c0556
-  if (dir[dirlen - 1] != '/')
6c0556
-    {
6c0556
-      *cp++ = '/';
6c0556
-      *cp = '\0';
6c0556
-      dirlen++;
6c0556
-    }
6c0556
-
6c0556
-  found = gconv_parseconfdir (fulldir, dirlen + prefix_len);
6c0556
-
6c0556
-  free (fulldir);
6c0556
+  found = gconv_parseconfdir (fulldir, strlen (fulldir));
6c0556
 
6c0556
   if (!found)
6c0556
     {
6c0556
@@ -679,6 +671,8 @@ handle_dir (const char *dir)
6c0556
 	     "configuration files with names ending in .conf.");
6c0556
     }
6c0556
 
6c0556
+  free (fulldir);
6c0556
+
6c0556
   return found ? 0 : 1;
6c0556
 }
6c0556